Compare commits

...

14 Commits

Author SHA1 Message Date
a5e9a28673 Added PRODUCT_NAME_SHORT and updated PID/TID kludge to include git hash
All checks were successful
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 41s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 1m43s
Create Docker Image / Final Docker Image Manifest (push) Successful in 10s
2024-05-22 15:31:10 +10:00
49e40f4fb8 Generated mail from the hub wont have $model->errors defined 2024-05-22 09:21:59 +10:00
924d760c79 Fix FSC45 packets, point_id was still being validated the old way 2024-05-22 09:21:59 +10:00
58dc090c83 Use packets domain for packet validation, not remote sytems address 2024-05-22 09:21:59 +10:00
b20878e378 Kludges are not required in messages 2024-05-22 09:21:59 +10:00
b443762739 Fix processing echomail and when mail crc is calculated as it was decompressing the CompressedString 2024-05-22 09:21:59 +10:00
18f5354d0c Mail validation errors is now an object, and must be tested with ->count() 2024-05-22 09:21:59 +10:00
17e3c69f07 Fix for invalid-zone validation comparing a string with an int 2024-05-22 09:21:59 +10:00
51784df6a8 Fix missed Notification using old Message::class 2024-05-22 09:21:59 +10:00
8df6384736 Fixed checking for RESCAN kludge 2024-05-22 09:21:59 +10:00
752462d20f Update job:list, and change "subject" to "jobname" 2024-05-22 09:21:59 +10:00
72d68fa1ab Update SocketClient to support raw IP addresses 2024-05-22 09:21:59 +10:00
aaec5f8f4a Security update enabling update_nn to edit system details 2024-05-22 09:21:59 +10:00
ab2e288f06 More complete rework of packet parsing and packet generation with f279d85 - and testing passes 2024-05-22 09:21:59 +10:00
32 changed files with 331 additions and 305 deletions

View File

@ -240,27 +240,28 @@ class Message extends FTNBase
$o->mo->flags = $o->header['flags']; $o->mo->flags = $o->header['flags'];
$o->mo->cost = $o->header['cost']; $o->mo->cost = $o->header['cost'];
$o->mo->msg_crc = md5($o->mo->msg_src); if ($o->fftn)
$o->mo->fftn_id = $o->fftn->id;
$o->mo->fftn_id = $o->fftn?->id; else
$o->mo->set_fftn = $o->fftn_t;
switch (get_class($o->mo)) { switch (get_class($o->mo)) {
case Echomail::class: case Echomail::class:
// Echomails dont have a to address
break; break;
case Netmail::class: case Netmail::class:
$o->mo->tftn_id = $o->tftn?->id; if ($o->tftn)
$o->mo->tftn_id = $o->tftn->id;
else
$o->mo->set_tftn = $o->tftn_t;
break; break;
default: default:
throw new InvalidPacketException('Unknown message class: '.get_class($o->mo)); throw new InvalidPacketException('Unknown message class: '.get_class($o->mo));
} }
if (($x=$o->validate())->fails()) { $o->validate();
$o->mo->errors = $x;
Log::debug(sprintf('%s:! Message fails validation (%s@%s->%s@%s)',self::LOGKEY,$o->mo->from,$o->fftn_t,$o->mo->to,$o->tftn_t),['result'=>$o->mo->errors->errors()]);
}
return $o->mo; return $o->mo;
} }
@ -300,14 +301,14 @@ class Message extends FTNBase
public function __get($key) public function __get($key)
{ {
// @todo Do we need all these key values? // @todo Do we need all these key values?
Log::debug(sprintf('%s:/ Requesting key for Message::class [%s]',self::LOGKEY,$key)); //Log::debug(sprintf('%s:/ Requesting key for Message::class [%s]',self::LOGKEY,$key));
switch ($key) { switch ($key) {
// From Addresses // From Addresses
case 'fz': return Arr::get($this->src,'z'); case 'fz': return (int)Arr::get($this->src,'z');
case 'fn': return ($x=$this->src) ? Arr::get($x,'n') : Arr::get($this->header,'onet'); case 'fn': return (int)($x=$this->src) ? Arr::get($x,'n') : Arr::get($this->header,'onet');
case 'ff': return ($x=$this->src) ? Arr::get($x,'f') : Arr::get($this->header,'onode'); case 'ff': return (int)($x=$this->src) ? Arr::get($x,'f') : Arr::get($this->header,'onode');
case 'fp': return $this->mo->kludges->get('FMPT:') ?: Arr::get($this->src,'p',Arr::get($this->header,'opoint',0)); case 'fp': return (int)$this->mo->kludges->get('FMPT:') ?: Arr::get($this->src,'p',Arr::get($this->header,'opoint',0));
case 'fd': return Arr::get($this->src,'d'); case 'fd': return Arr::get($this->src,'d');
case 'fzone': case 'fzone':
@ -338,10 +339,10 @@ class Message extends FTNBase
// To Addresses // To Addresses
// Echomail doesnt have a zone, so we'll use the source zone // Echomail doesnt have a zone, so we'll use the source zone
case 'tz': return Arr::get($this->isEchomail() ? $this->src : $this->dst,'z'); case 'tz': return (int)Arr::get($this->isEchomail() ? $this->src : $this->dst,'z');
case 'tn': return Arr::get($this->header,'dnet'); case 'tn': return (int)Arr::get($this->header,'dnet');
case 'tf': return Arr::get($this->header,'dnode'); case 'tf': return (int)Arr::get($this->header,'dnode');
case 'tp': return $this->mo->kludges->get('TOPT:') ?: Arr::get($this->header,'dpoint',0); case 'tp': return (int)$this->mo->kludges->get('TOPT:') ?: Arr::get($this->header,'dpoint',0);
case 'tzone': case 'tzone':
// Use the zone if this class was called with it. // Use the zone if this class was called with it.
@ -357,6 +358,7 @@ class Message extends FTNBase
return Zone::where('zone_id',$this->tz) return Zone::where('zone_id',$this->tz)
->where('default',TRUE) ->where('default',TRUE)
->single(); ->single();
case 'tdomain': case 'tdomain':
// We'll use the zone's domain if this method class was called with a zone // We'll use the zone's domain if this method class was called with a zone
if ($this->zone && (($this->zone->domain->name === Arr::get($this->dst,'d')) || ! Arr::get($this->dst,'d'))) if ($this->zone && (($this->zone->domain->name === Arr::get($this->dst,'d')) || ! Arr::get($this->dst,'d')))
@ -537,10 +539,8 @@ class Message extends FTNBase
$this->mo->kludges->put('TOPT',$this->mo->tftn->point_id); $this->mo->kludges->put('TOPT',$this->mo->tftn->point_id);
} }
if ($this->mo->isFlagSet(self::FLAG_LOCAL)) $this->mo->kludges->put($this->mo->isFlagSet(self::FLAG_LOCAL) ? 'PID:' : 'TID:',sprintf('%s %s',Setup::PRODUCT_NAME_SHORT,$s->version));
$this->mo->kludges->put('PID',sprintf('clrghouz %s',$s->version)); $this->mo->kludges->put('DBID:',$this->mo->id);
else
$this->mo->kludges->put('TID',sprintf('clrghouz %s',$s->version));
if ($this->mo instanceof Echomail) if ($this->mo instanceof Echomail)
$return .= sprintf("AREA:%s\r",strtoupper($this->mo->echoarea->name)); $return .= sprintf("AREA:%s\r",strtoupper($this->mo->echoarea->name));
@ -556,17 +556,17 @@ class Message extends FTNBase
foreach ($this->mo->kludges as $k=>$v) foreach ($this->mo->kludges as $k=>$v)
$return .= sprintf("\01%s %s\r",$k,$v); $return .= sprintf("\01%s %s\r",$k,$v);
$return .= $this->mo->content; $return .= $this->mo->content."\r";
if ($this->mo instanceof Netmail) { if ($this->mo instanceof Netmail) {
foreach ($this->mo->path as $ao) foreach ($this->mo->path as $ao)
$return .= sprintf("\x01Via %s\r",$this->mo->via($ao)); $return .= sprintf("\x01Via %s\r",$this->mo->via($ao));
// Add our address // Add our address
$return .= sprintf("\x01Via %s @%s.UTC %s (%04X)\r", $return .= sprintf("\x01Via %s @%s.UTC %s %s\r",
$this->us->ftn3d, $this->us->ftn3d,
Carbon::now()->format('Ymd.His'), Carbon::now()->format('Ymd.His'),
Setup::PRODUCT_NAME,Setup::PRODUCT_ID); Setup::PRODUCT_NAME_SHORT,$s->version);
} else { } else {
// FTS-0004.001/FSC-0068.001 The message SEEN-BY lines // FTS-0004.001/FSC-0068.001 The message SEEN-BY lines
@ -695,6 +695,7 @@ class Message extends FTNBase
// Process the message content // Process the message content
if ($content=substr($message,$ptr_start,$ptr_end-$ptr_start)) { if ($content=substr($message,$ptr_start,$ptr_end-$ptr_start)) {
$o->msg_src = $content; $o->msg_src = $content;
$o->msg_crc = md5($content);
$ptr_content_start = 0; $ptr_content_start = 0;
// See if we have a tagline // See if we have a tagline
@ -806,7 +807,7 @@ class Message extends FTNBase
'tftn_id' => $this->isNetmail() ? 'required|exists:App\Models\Address,id' : 'prohibited', 'tftn_id' => $this->isNetmail() ? 'required|exists:App\Models\Address,id' : 'prohibited',
'rogue_path' => $this->isEchomail() ? 'sometimes|array' : 'prohibited', 'rogue_path' => $this->isEchomail() ? 'sometimes|array' : 'prohibited',
'rogue_seenby' => $this->isEchomail() ? 'sometimes|array' : 'prohibited', 'rogue_seenby' => $this->isEchomail() ? 'sometimes|array' : 'prohibited',
'kludges' => 'present|array|min:1', // @todo add in required KEYS like INTL for netmails 'kludges' => 'present|array', // @todo add in required KEYS like INTL for netmails
'onode' => ['required',new TwoByteIntegerWithZero], 'onode' => ['required',new TwoByteIntegerWithZero],
'dnode' => ['required',new TwoByteIntegerWithZero], 'dnode' => ['required',new TwoByteIntegerWithZero],
@ -830,14 +831,16 @@ class Message extends FTNBase
$validator->errors()->add('invalid-zone',sprintf('Message zone [%d] doesnt match packet zone [%d].',$this->fz,$this->zone->zone_id)); $validator->errors()->add('invalid-zone',sprintf('Message zone [%d] doesnt match packet zone [%d].',$this->fz,$this->zone->zone_id));
} }
if (! $this->fboss_o) if (! $this->fftn)
$validator->errors()->add('from',sprintf('Undefined Node [%s] sent message.',$this->fboss)); $validator->errors()->add('from',sprintf('Undefined Node [%s] sent message.',$this->fftn_t));
if (! $this->tboss_o) if ($this->isNetmail() && (! $this->tftn))
$validator->errors()->add('to',sprintf('Undefined Node [%s] for destination.',$this->tboss)); $validator->errors()->add('to',sprintf('Undefined Node [%s] for destination.',$this->tftn_t));
}); });
$this->mo->errors = $validator->errors();
if ($validator->fails()) if ($validator->fails())
$this->mo->errors = $validator; Log::debug(sprintf('%s:! Message fails validation (%s@%s->%s@%s)',self::LOGKEY,$this->mo->from,$this->fftn_t,$this->mo->to,$this->tftn_t),['result'=>$validator->errors()]);
return $validator; return $validator;
} }

View File

@ -11,7 +11,7 @@ use Symfony\Component\HttpFoundation\File\File;
use App\Classes\FTN as FTNBase; use App\Classes\FTN as FTNBase;
use App\Exceptions\InvalidPacketException; use App\Exceptions\InvalidPacketException;
use App\Models\{Address,Domain,Echomail,Netmail,Software,Zone}; use App\Models\{Address,Domain,Echomail,Netmail,Software,System,Zone};
use App\Notifications\Netmails\EchomailBadAddress; use App\Notifications\Netmails\EchomailBadAddress;
/** /**
@ -206,7 +206,7 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
*/ */
public function __get($key) public function __get($key)
{ {
Log::debug(sprintf('%s:/ Requesting key for Packet::class [%s]',self::LOGKEY,$key)); //Log::debug(sprintf('%s:/ Requesting key for Packet::class [%s]',self::LOGKEY,$key));
switch ($key) { switch ($key) {
// From Addresses // From Addresses
@ -418,98 +418,75 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
$msg = Message::parseMessage($message,$this->zone); $msg = Message::parseMessage($message,$this->zone);
// @todo If the message from domain (eg: $msg->fftn->zone->domain) is different to the packet address domain ($pkt->fftn->zone->domain), we'll skip this message
Log::debug(sprintf('%s:^ Message [%s] - Packet from domain [%d], Message domain [%d]',self::LOGKEY,$msg->msgid,$this->fftn->zone->domain_id,$msg->fftn->zone->domain_id));
// If the message is invalid, we'll ignore it // If the message is invalid, we'll ignore it
if ($msg->errors) { if ($msg->errors->count()) {
Log::info(sprintf('%s:- Message [%s] has errors',self::LOGKEY,$msg->msgid)); Log::info(sprintf('%s:- Message [%s] has [%d] errors',self::LOGKEY,$msg->msgid ?: 'No ID',$msg->errors->count()));
// If the messages is not for the right zone, we'll ignore it // If the messages is not for the right zone, we'll ignore it
if ($msg->errors->messages()->has('invalid-zone')) { if ($msg->errors->has('invalid-zone')) {
Log::alert(sprintf('%s:! Message [%s] is from an invalid zone [%s], packet is from [%s] - ignoring it',self::LOGKEY,$msg->msgid,$msg->fftn->zone->zone_id,$this->fftn->zone->zone_id)); Log::alert(sprintf('%s:! Message [%s] is from an invalid zone [%s], packet is from [%s] - ignoring it',self::LOGKEY,$msg->msgid,$msg->fftn->zone->zone_id,$this->fftn->zone->zone_id));
if (! $msg->rescanned->count()) if (! $msg->kludges->get('RESCANNED'))
Notification::route('netmail',$this->fftn)->notify(new EchomailBadAddress($msg)); Notification::route('netmail',$this->fftn)->notify(new EchomailBadAddress($msg));
return; return;
} }
// @todo If the $msg->fftn doesnt exist, we'll need to create it // If the $msg->fftn doesnt exist, we'll need to create it
// @todo If the $msg->tftn doesnt exist (netmail), we'll need to create it (ergo intransit) if ($msg->errors->has('from') && $this->fftn && $this->fftn->zone_id) {
/* Log::debug(sprintf('%s:^ From address [%s] doesnt exist, it needs to be created',self::LOGKEY,$msg->set->get('set_fftn')));
// If the to address doenst exist, we'll create a new entry
if ($msg->errors->messages()->has('to') && $msg->tzone) {
try {
// @todo Need to work out the correct region for the host_id
Address::unguard();
$ao = Address::firstOrNew([
'zone_id' => $msg->tzone->id,
//'region_id' => 0,
'host_id' => $msg->tn,
'node_id' => $msg->tf,
'point_id' => $msg->tp,
'active' => TRUE, // @todo This should be false, as it hasnt been assigned to the node
]);
Address::reguard();
if (is_null($ao->region_id)) $ao = Address::findFTN($msg->set->get('set_fftn'),TRUE);
$ao->region_id = $ao->host_id;
if ($ao?->exists && ($ao->zone?->domain_id !== $this->fftn->zone->domain_id)) {
Log::alert(sprintf('%s:! From address [%s] domain [%d] doesnt match packet domain [%d]?',self::LOGKEY,$msg->set->get('set_fftn'),$ao->zone?->domain_id,$this->fftn->zone->domain_id));
} catch (\Exception $e) {
Log::error(sprintf('%s:! Error finding/creating TO address [%s] for message',self::LOGKEY,$msg->tboss),['error'=>$e->getMessage()]);
$this->errors->push($msg);
return; return;
} }
if (! $ao) {
$so = System::createUnknownSystem(); $so = System::createUnknownSystem();
$ao = Address::createFTN($msg->set->get('set_fftn'),$so);
$so->addresses()->save($ao);
Log::alert(sprintf('%s:- To FTN is not defined, creating new entry for [%s] (%d)',self::LOGKEY,$msg->tboss,$ao->id));
} }
// If the from address doenst exist, we'll create a new entry $msg->fftn_id = $ao->id;
if ($msg->errors->messages()->has('from') && $msg->tzone) { Log::alert(sprintf('%s:- From FTN [%s] is not defined, created new entry for (%d)',self::LOGKEY,$msg->set->get('set_fftn'),$ao->id));
try { }
// @todo Need to work out the correct region for the host_id
Address::unguard();
$ao = Address::firstOrNew([
'zone_id' => $msg->fzone->id,
//'region_id' => 0,
'host_id' => $msg->fn,
'node_id' => $msg->ff,
'point_id' => $msg->fp,
'active'=> TRUE, // @todo This should be FALSE as it hasnt been assigned to the node
]);
Address::reguard();
if (is_null($ao->region_id)) // If the $msg->tftn doesnt exist, we'll need to create it
$ao->region_id = $ao->host_id; if ($msg->errors->has('to') && $this->tftn && $this->tftn->zone_id) {
Log::debug(sprintf('%s:^ To address [%s] doesnt exist, it needs to be created',self::LOGKEY,$msg->set->get('set_tftn')));
$ao = Address::findFTN($msg->set->get('set_tftn'),TRUE);
if ($ao?->exists && ($ao->zone?->domain_id !== $this->tftn->zone->domain_id)) {
Log::alert(sprintf('%s:! To address [%s] domain [%d] doesnt match packet domain [%d]?',self::LOGKEY,$msg->set->get('set_tftn'),$ao->zone?->domain_id,$this->fftn->zone->domain_id));
} catch (\Exception $e) {
Log::error(sprintf('%s:! Error finding/creating FROM address [%s] for message',self::LOGKEY,$msg->fboss),['error'=>$e->getMessage()]);
$this->errors->push($msg);
return; return;
} }
if (! $ao) {
$so = System::createUnknownSystem(); $so = System::createUnknownSystem();
$ao = Address::createFTN($msg->set->get('set_fftn'),$so);
$so->addresses()->save($ao);
Log::alert(sprintf('%s:- From FTN is not defined, creating new entry for [%s] (%d)',self::LOGKEY,$msg->fboss,$ao->id));
} }
*/
// If the from/to user is missing $msg->tftn_id = $ao->id;
if ($msg->errors->messages()->has('from') || $msg->errors->messages()->has('to')) { Log::alert(sprintf('%s:- To FTN [%s] is not defined, created new entry for (%d)',self::LOGKEY,$msg->set->get('set_tftn'),$ao->id));
Log::error(sprintf('%s:! Skipping message [%s] due to errors (%s)...',self::LOGKEY,$msg->msgid,join(',',$msg->errors->messages()->keys()))); }
$this->errors->push($msg);
// If there is no fftn, then its from a system that we dont know about
if (! $this->fftn) {
Log::alert(sprintf('%s:! No further message processing, packet is from a system we dont know about [%s]',self::LOGKEY,$this->fftn_t));
$this->messages->push($msg);
return; return;
} }
} }
// @todo If the message from domain (eg: $msg->fftn->zone->domain) is different to the packet address domain ($pkt->fftn->zone->domain), we'll skip this message
Log::debug(sprintf('%s:^ Message [%s] - Packet from domain [%d], Message domain [%d]',self::LOGKEY,$msg->msgid,$this->fftn->zone->domain_id,$msg->fftn->zone->domain_id));
$this->messages->push($msg); $this->messages->push($msg);
} }

View File

@ -63,34 +63,36 @@ final class FSC39 extends Packet
*/ */
protected function header(): string protected function header(): string
{ {
$oldest = $this->messages->sortBy('datetime')->last();
try { try {
return pack(collect(self::HEADER)->pluck(1)->join(''), return pack(collect(self::HEADER)->pluck(1)->join(''),
$this->ff, // Orig Node $this->fftn_p->node_id, // Orig Node
$this->tf, // Dest Node $this->tftn_p->node_id, // Dest Node
Arr::get($this->header,'y'), // Year $oldest->datetime->format('Y'), // Year
Arr::get($this->header,'m'), // Month $oldest->datetime->format('m')-1, // Month
Arr::get($this->header,'d'), // Day $oldest->datetime->format('d'), // Day
Arr::get($this->header,'H'), // Hour $oldest->datetime->format('H'), // Hour
Arr::get($this->header,'M'), // Minute $oldest->datetime->format('i'), // Minute
Arr::get($this->header,'S'), // Second $oldest->datetime->format('s'), // Second
0, // Baud 0, // Baud
2, // Packet Version (should be 2) 2, // Packet Version (should be 2)
$this->fn, // Orig Net $this->fftn_p->host_id, // Orig Net
$this->tn, // Dest Net $this->tftn_p->host_id, // Dest Net
(Setup::PRODUCT_ID & 0xff), // Product Code Lo (Setup::PRODUCT_ID & 0xff), // Product Code Lo
Setup::PRODUCT_VERSION_MAJ, // Product Version Major Setup::PRODUCT_VERSION_MAJ, // Product Version Major
$this->password, // Packet Password $this->pass_p ?: $this->tftn_p->session('pktpass'), // Packet Password
$this->fz, // Orig Zone $this->fftn_p->zone->zone_id, // Orig Zone
$this->tz, // Dest Zone $this->tftn_p->zone->zone_id, // Dest Zone
'', // Reserved '', // Reserved
Arr::get($this->header,'capvalid',1<<0), // fsc-0039.004 (copy of 0x2c) Arr::get($this->header,'capvalid',1<<0), // fsc-0039.004 (copy of 0x2c)
((Setup::PRODUCT_ID >> 8) & 0xff), // Product Code Hi ((Setup::PRODUCT_ID >> 8) & 0xff), // Product Code Hi
Setup::PRODUCT_VERSION_MIN, // Product Version Minor Setup::PRODUCT_VERSION_MIN, // Product Version Minor
Arr::get($this->header,'capword',1<<0), // Capability Word 1<<0, // Capability Word
$this->fz, // Orig Zone $this->fftn_p->zone->zone_id, // Orig Zone
$this->tz, // Dest Zone $this->tftn_p->zone->zone_id, // Dest Zone
$this->fp, // Orig Point $this->fftn_p->point_id, // Orig Point
$this->tp, // Dest Point $this->tftn_p->point_id, // Dest Point
strtoupper(hexstr(Setup::PRODUCT_ID)), // ProdData strtoupper(hexstr(Setup::PRODUCT_ID)), // ProdData
); );

View File

@ -44,22 +44,22 @@ final class FSC45 extends Packet
{ {
try { try {
return pack(collect(self::HEADER)->pluck(1)->join(''), return pack(collect(self::HEADER)->pluck(1)->join(''),
$this->ff, // Orig Node $this->fftn_p->node_id, // Orig Node
$this->tf, // Dest Node $this->tftn_p->node_id, // Dest Node
$this->fp, // Orig Point $this->fftn_p->point_id, // Orig Point
$this->tp, // Dest Point $this->tftn_p->point_id, // Dest Point
'', // Reserved '', // Reserved
2, // Sub Version (should be 2) 2, // Sub Version (should be 2)
2, // Packet Version (should be 2) 2, // Packet Version (should be 2)
$this->fn, // Orig Net $this->fftn_p->host_id, // Orig Net
$this->tn, // Dest Net $this->tftn_p->host_id, // Dest Net
(Setup::PRODUCT_ID & 0xff), // Product Code (Setup::PRODUCT_ID & 0xff), // Product Code
Setup::PRODUCT_VERSION_MAJ, // Product Version Setup::PRODUCT_VERSION_MAJ, // Product Version
$this->password, // Packet Password $this->pass_p ?: $this->tftn_p->session('pktpass'), // Packet Password
$this->fz, // Orig Zone $this->fftn_p->zone->zone_id, // Orig Zone
$this->tz, // Dest Zone $this->tftn_p->zone->zone_id, // Dest Zone
$this->fd, // Orig Domain $this->fftn_p->zone->domain->name, // Orig Domain
$this->td, // Dest Domain $this->tftn_p->zone->domain->name, // Dest Domain
strtoupper(hexstr(Setup::PRODUCT_ID)), // ProdData strtoupper(hexstr(Setup::PRODUCT_ID)), // ProdData
); );

View File

@ -43,25 +43,27 @@ final class FTS1 extends Packet
*/ */
protected function header(): string protected function header(): string
{ {
$oldest = $this->messages->sortBy('datetime')->last();
try { try {
return pack(collect(self::HEADER)->pluck(1)->join(''), return pack(collect(self::HEADER)->pluck(1)->join(''),
$this->ff, // Orig Node $this->fftn_p->node_id, // Orig Node
$this->tf, // Dest Node $this->tftn_p->node_id, // Dest Node
Arr::get($this->header,'y'), // Year $oldest->datetime->format('Y'), // Year
Arr::get($this->header,'m'), // Month $oldest->datetime->format('m')-1, // Month
Arr::get($this->header,'d'), // Day $oldest->datetime->format('d'), // Day
Arr::get($this->header,'H'), // Hour $oldest->datetime->format('H'), // Hour
Arr::get($this->header,'M'), // Minute $oldest->datetime->format('i'), // Minute
Arr::get($this->header,'S'), // Second $oldest->datetime->format('s'), // Second
0, // Baud 0, // Baud
2, // Packet Version (should be 2) 2, // Packet Version (should be 2)
$this->fn, // Orig Net $this->fftn_p->host_id, // Orig Net
$this->tn, // Dest Net $this->tftn_p->host_id, // Dest Net
(Setup::PRODUCT_ID & 0xff), // Product Code Lo (Setup::PRODUCT_ID & 0xff), // Product Code Lo
Setup::PRODUCT_VERSION_MAJ, // Product Version Major Setup::PRODUCT_VERSION_MAJ, // Product Version Major
$this->password, // Packet Password $this->pass_p ?: $this->tftn_p->session('pktpass'), // Packet Password
$this->fz, // Orig Zone $this->fftn_p->zone->zone_id, // Orig Zone
$this->tz, // Dest Zone $this->tftn_p->zone->zone_id, // Dest Zone
'', // Reserved '', // Reserved
); );

View File

@ -11,7 +11,7 @@ abstract class Process
{ {
public static function canProcess(Echoarea $eao): bool public static function canProcess(Echoarea $eao): bool
{ {
return $eao->automsgs; return $eao->automsgs ? TRUE : FALSE;
} }
/** /**

View File

@ -201,6 +201,12 @@ final class SocketClient {
$sort = collect(['AAAA','A']); $sort = collect(['AAAA','A']);
if (filter_var($address,FILTER_VALIDATE_IP))
$resolved = collect([[
(($x=filter_var($address,FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) ? 'ipv6' : 'ip')=>$address,
'type'=>$x ? 'AAAA' : 'A'
]]);
else
// We only look at AAAA/A records // We only look at AAAA/A records
$resolved = collect(dns_get_record($address,DNS_AAAA|DNS_A)) $resolved = collect(dns_get_record($address,DNS_AAAA|DNS_A))
->filter(function($item) use ($sort) { return $sort->search(Arr::get($item,'type')) !== FALSE; }) ->filter(function($item) use ($sort) { return $sort->search(Arr::get($item,'type')) !== FALSE; })

View File

@ -39,7 +39,7 @@ class JobList extends Command
$o->uuid, $o->uuid,
$o->id, $o->id,
$o->display_name, $o->display_name,
$o->command->subject, $o->command->jobname,
$o->attempts,$o->maxTries, $o->attempts,$o->maxTries,
$o->available_at ?: '-', $o->available_at ?: '-',
$o->attempts ? sprintf(' (Created:%s)',$o->created_at) : '' $o->attempts ? sprintf(' (Created:%s)',$o->created_at) : ''

View File

@ -69,7 +69,7 @@ class PacketInfo extends Command
try { try {
$this->warn(sprintf('- Date : %s (%s)',$msg->datetime,$msg->datetime->tz->toOffsetName())); $this->warn(sprintf('- Date : %s (%s)',$msg->datetime,$msg->datetime->tz->toOffsetName()));
$this->warn(sprintf(' - Errors : %s',$msg->errors?->errors()->count() ? 'YES' : 'No')); $this->warn(sprintf(' - Errors : %s',$msg->errors->count() ? 'YES' : 'No'));
$this->warn(sprintf(' - Flags : %s',$msg->flags()->keys()->join(', '))); $this->warn(sprintf(' - Flags : %s',$msg->flags()->keys()->join(', ')));
$this->warn(sprintf(' - Cost : %d',$msg->cost)); $this->warn(sprintf(' - Cost : %d',$msg->cost));
$this->warn(sprintf(' - From : %s (%s)',$msg->from,$msg->fftn->ftn)); $this->warn(sprintf(' - From : %s (%s)',$msg->from,$msg->fftn->ftn));
@ -81,10 +81,10 @@ class PacketInfo extends Command
if ($msg instanceof Echomail) if ($msg instanceof Echomail)
$this->warn(sprintf(' - Area : %s',$msg->echoarea->name)); $this->warn(sprintf(' - Area : %s',$msg->echoarea->name));
if ($msg->errors) { if ($msg->errors->count()) {
echo "\n"; echo "\n";
$this->error("Errors:"); $this->error("Errors:");
foreach ($msg->errors->errors()->all() as $error) foreach ($msg->errors->all() as $error)
$this->error(' - '.$error); $this->error(' - '.$error);
} }
@ -103,7 +103,7 @@ class PacketInfo extends Command
$this->error(sprintf(' - To: %s (%s)',$msg->to,$msg->tftn)); $this->error(sprintf(' - To: %s (%s)',$msg->to,$msg->tftn));
$this->error(sprintf(' - Subject: %s',$msg->subject)); $this->error(sprintf(' - Subject: %s',$msg->subject));
foreach ($msg->errors->errors()->all() as $error) foreach ($msg->errors->all() as $error)
$this->line(' - '.$error); $this->line(' - '.$error);
} }

View File

@ -3,9 +3,7 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use App\Classes\File;
use App\Classes\FTN\Packet; use App\Classes\FTN\Packet;
use App\Jobs\PacketProcess as Job; use App\Jobs\PacketProcess as Job;
use App\Models\Address; use App\Models\Address;
@ -60,16 +58,13 @@ class PacketProcess extends Command
/** /**
* Execute the console command. * Execute the console command.
* *
* @return void * @return int|void
* @throws \App\Exceptions\InvalidPacketException * @throws \Exception
*/ */
public function handle() public function handle()
{ {
//$fs = Storage::disk(config('fido.local_disk'));
$rel_name = sprintf('%s/%s',config('fido.dir'),$this->argument('file')); $rel_name = sprintf('%s/%s',config('fido.dir'),$this->argument('file'));
//$f = new File($fs->path($rel_name));
$m = []; $m = [];
if ($this->argument('ftn')) { if ($this->argument('ftn')) {
$ao = Address::findFTN($this->argument('ftn')); $ao = Address::findFTN($this->argument('ftn'));
@ -84,6 +79,6 @@ class PacketProcess extends Command
Job::dispatchSync($rel_name,$ao->zone->domain,$this->option('dontqueue')); Job::dispatchSync($rel_name,$ao->zone->domain,$this->option('dontqueue'));
return Command::SUCCESS; return self::SUCCESS;
} }
} }

View File

@ -16,7 +16,7 @@ use Illuminate\Support\Facades\Notification;
use Illuminate\Support\ViewErrorBag; use Illuminate\Support\ViewErrorBag;
use App\Classes\FTN\Message; use App\Classes\FTN\Message;
use App\Http\Requests\{AddressMerge,AreafixRequest,SystemEchoareaRequest,SystemRegister,SystemSessionRequest}; use App\Http\Requests\{AddressMerge,AreafixRequest,SystemEchoareaRequest,SystemRegisterRequest,SystemSessionRequest};
use App\Jobs\AddressPoll; use App\Jobs\AddressPoll;
use App\Models\{Address,Echoarea,Echomail,Filearea,Netmail,Setup,System,Zone}; use App\Models\{Address,Echoarea,Echomail,Filearea,Netmail,Setup,System,Zone};
use App\Notifications\Netmails\AddressLink; use App\Notifications\Netmails\AddressLink;
@ -29,13 +29,18 @@ class SystemController extends Controller
/** /**
* Add or edit a node * Add or edit a node
*/ */
public function add_edit(SystemRegister $request,System $o) public function add_edit(SystemRegisterRequest $request, System $o)
{ {
if ($request->post()) { if ($request->validated()) {
foreach (['name','location','sysop','hold','phone','address','port','active','method','notes','zt_id','pkt_type','heartbeat'] as $key) foreach (['name','location','phone','address','port','active','method','pkt_type'] as $key)
$o->{$key} = $request->post($key); $o->{$key} = $request->validated($key);
switch ($request->post('pollmode')) { // Sometimes items
foreach (['sysop','hold','notes','zt_id','heartbeat'] as $key)
if ($request->validated($key))
$o->{$key} = $request->validated($key);
switch ($request->validated('pollmode')) {
case 1: $o->pollmode = FALSE; break; case 1: $o->pollmode = FALSE; break;
case 2: $o->pollmode = TRUE; break; case 2: $o->pollmode = TRUE; break;
default: $o->pollmode = NULL; default: $o->pollmode = NULL;
@ -49,9 +54,9 @@ class SystemController extends Controller
->transform(function($item) { $item['active'] = Arr::get($item,'active',FALSE); return $item; }); ->transform(function($item) { $item['active'] = Arr::get($item,'active',FALSE); return $item; });
$o->mailers()->sync($mailers); $o->mailers()->sync($mailers);
if ($request->post('users')) { if ($request->validated('users')) {
if (array_filter($request->post('users'),function($item) { return $item; })) if (array_filter($request->validated('users'),function($item) { return $item; }))
$o->users()->sync($request->post('users')); $o->users()->sync($request->validated('users'));
else else
$o->users()->detach(); $o->users()->detach();
} }
@ -62,7 +67,7 @@ class SystemController extends Controller
$o->load(['addresses.zone.domain','addresses.nodes_hub','addresses.system','sessions.domain','sessions.systems']); $o->load(['addresses.zone.domain','addresses.nodes_hub','addresses.system','sessions.domain','sessions.systems']);
return view('system.addedit') return view('system.addedit')
->with('action',$o->exists ? 'update' : 'create') ->with('action',$o->exists ? 'update_nn' : 'create')
->with('o',$o); ->with('o',$o);
} }
@ -767,7 +772,7 @@ class SystemController extends Controller
/** /**
* Register a system, or link to an existing system * Register a system, or link to an existing system
*/ */
public function register(SystemRegister $request) public function register(SystemRegisterRequest $request)
{ {
// Step 1, show the user a form to select an existing defined system // Step 1, show the user a form to select an existing defined system
if ($request->isMethod('GET')) if ($request->isMethod('GET'))

View File

@ -10,8 +10,7 @@ use Illuminate\Validation\Rule;
use App\Classes\FTN\Packet; use App\Classes\FTN\Packet;
use App\Models\{Setup,System}; use App\Models\{Setup,System};
// @todo rename to SystemRegisterRequest class SystemRegisterRequest extends FormRequest
class SystemRegister extends FormRequest
{ {
private System $so; private System $so;
@ -73,7 +72,7 @@ class SystemRegister extends FormRequest
],($so && $so->exists) ? [ ],($so && $so->exists) ? [
'users' => 'nullable|array|min:1|max:2', 'users' => 'nullable|array|min:1|max:2',
'active' => 'required|boolean', 'active' => 'required|boolean',
'hold' => 'required|boolean', 'hold' => 'sometimes|boolean',
'pollmode' => 'required|integer|min:0|max:2', 'pollmode' => 'required|integer|min:0|max:2',
'heartbeat' => 'nullable|integer|min:0|max:48', 'heartbeat' => 'nullable|integer|min:0|max:48',
] : [])); ] : []));

View File

@ -50,7 +50,7 @@ class AddressPoll implements ShouldQueue, ShouldBeUnique
case 'address': case 'address':
return $this->ao; return $this->ao;
case 'subject': case 'jobname':
return $this->ao->ftn; return $this->ao->ftn;
default: default:
@ -125,7 +125,7 @@ class AddressPoll implements ShouldQueue, ShouldBeUnique
} }
} catch (SocketException $e) { } catch (SocketException $e) {
Log::error(sprintf('%s:! Unable to connect to [%s]: %s',self::LOGKEY,$this->ao->ftn,$e->getMessage())); Log::error(sprintf('%s:! SocketException Unable to connect to [%s]: %s',self::LOGKEY,$this->ao->ftn,$e->getMessage()));
break; break;
} catch (\ErrorException $e) { } catch (\ErrorException $e) {

View File

@ -47,7 +47,7 @@ class EchoareaImport implements ShouldQueue
public function __get($key): mixed public function __get($key): mixed
{ {
switch ($key) { switch ($key) {
case 'subject': case 'jobname':
return sprintf('%s-%s',$this->do->name,$this->file); return sprintf('%s-%s',$this->do->name,$this->file);
default: default:

View File

@ -47,7 +47,7 @@ class FileareaImport implements ShouldQueue
public function __get($key): mixed public function __get($key): mixed
{ {
switch ($key) { switch ($key) {
case 'subject': case 'jobname':
return sprintf('%s-%s',$this->do->name,$this->file); return sprintf('%s-%s',$this->do->name,$this->file);
default: default:

View File

@ -41,8 +41,9 @@ class MessageProcess implements ShouldQueue
public function __get($key): mixed public function __get($key): mixed
{ {
switch ($key) { switch ($key) {
case 'subject': case 'jobname':
return sprintf('%s-%s-%s',$this->pktname,$this->mo->set->get('set_sender')->ftn,$this->mo->msgid); $mo = unserialize($this->mo);
return sprintf('%s-%s-%s',$mo->set->get('set_pkt'),$mo->set->get('set_sender')->ftn,$mo->msgid);
default: default:
return NULL; return NULL;

View File

@ -58,7 +58,7 @@ class NodelistImport implements ShouldQueue
public function __get($key): mixed public function __get($key): mixed
{ {
switch ($key) { switch ($key) {
case 'subject': case 'jobname':
return sprintf('%s-%s',$this->domain?->name,is_object($this->file) ? $this->file->name : $this->file); return sprintf('%s-%s',$this->domain?->name,is_object($this->file) ? $this->file->name : $this->file);
default: default:

View File

@ -44,7 +44,7 @@ class PacketProcess implements ShouldQueue
public function __get($key): mixed public function __get($key): mixed
{ {
switch ($key) { switch ($key) {
case 'subject': case 'jobname':
return $this->filename; return $this->filename;
default: default:
@ -78,7 +78,7 @@ class PacketProcess implements ShouldQueue
break; break;
} }
if (! our_nodes($this->do)->contains($pkt->fftn)) { if (! our_nodes($pkt->fftn->zone->domain)->contains($pkt->fftn)) {
Log::error(sprintf('%s:! Packet [%s] is from a system that is not configured with us? [%s] for [%s]',self::LOGKEY,$this->filename,$pkt->fftn_t,$this->do->name)); Log::error(sprintf('%s:! Packet [%s] is from a system that is not configured with us? [%s] for [%s]',self::LOGKEY,$this->filename,$pkt->fftn_t,$this->do->name));
// @todo Notification::route('netmail',$pkt->fftn)->notify(new UnexpectedPacketFromYou($this->filename)); // @todo Notification::route('netmail',$pkt->fftn)->notify(new UnexpectedPacketFromYou($this->filename));
@ -87,8 +87,8 @@ class PacketProcess implements ShouldQueue
} }
// Check the packet is to our address, if not we'll reject it. // Check the packet is to our address, if not we'll reject it.
if (! our_address($this->do)->contains($pkt->tftn)) { if (! our_address($pkt->tftn->zone->domain)->contains($pkt->tftn)) {
Log::error(sprintf('%s:! Packet [%s] is not to our address? [%s]',self::LOGKEY,$this->filename,$pkt->tftn)); Log::error(sprintf('%s:! Packet [%s] is not to our address? [%s]',self::LOGKEY,$this->filename,$pkt->tftn->ftn));
// @todo Notification::route('netmail',$pkt->fftn)->notify(new UnexpectedPacketToUs($this->filename)); // @todo Notification::route('netmail',$pkt->fftn)->notify(new UnexpectedPacketToUs($this->filename));
break; break;
@ -115,8 +115,8 @@ class PacketProcess implements ShouldQueue
elseif ($msg instanceof Echomail) elseif ($msg instanceof Echomail)
Log::info(sprintf('%s:- Echomail from [%s]',self::LOGKEY,$msg->fftn->ftn)); Log::info(sprintf('%s:- Echomail from [%s]',self::LOGKEY,$msg->fftn->ftn));
if ($msg->errors) { if ($msg->errors->count()) {
Log::error(sprintf('%s:! Message [%s] has [%d] errors, unable to process',self::LOGKEY,$msg->msgid,$msg->errors->errors()->count())); Log::error(sprintf('%s:! Message [%s] has [%d] errors, unable to process',self::LOGKEY,$msg->msgid,$msg->errors->count()));
continue; continue;
} }

View File

@ -42,7 +42,7 @@ class TicProcess implements ShouldQueue
public function __get($key): mixed public function __get($key): mixed
{ {
switch ($key) { switch ($key) {
case 'subject': case 'jobname':
return sprintf('%s %s',$this->do?->name,$this->file); return sprintf('%s %s',$this->do?->name,$this->file);
default: default:

View File

@ -154,7 +154,7 @@ class Address extends Model
$o = new self; $o = new self;
$o->active = TRUE; $o->active = TRUE;
$o->zone_id = $zo->id; $o->zone_id = $zo->id;
$o->region_id = 0; // @todo Automatically determine region $o->region_id = $ftn['r'];
$o->host_id = $ftn['n']; $o->host_id = $ftn['n'];
$o->node_id = $ftn['f']; $o->node_id = $ftn['f'];
$o->point_id = $ftn['p']; $o->point_id = $ftn['p'];
@ -307,8 +307,39 @@ class Address extends Model
if ((! empty($matches[4])) AND ((! is_numeric($matches[$i])) || ($matches[4] > self::ADDRESS_FIELD_MAX))) if ((! empty($matches[4])) AND ((! is_numeric($matches[$i])) || ($matches[4] > self::ADDRESS_FIELD_MAX)))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - point address invalid [%d]',$ftn,$matches[4])); throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - point address invalid [%d]',$ftn,$matches[4]));
// Work out region
$region_id = 0;
$zone_id = NULL;
// We can only work out region if we have a domain
if ($matches[5] ?? NULL) {
$o = new self;
$o->host_id = $matches[2];
$o->node_id = $matches[3];
$o->point_id = empty($matches[4]) ? 0 : (int)$matches[4];
$zo = Zone::select('zones.*')->where('zone_id',$matches[1])->join('domains',['domains.id'=>'zones.domain_id'])->where('domains.name',$matches[5])->single();
$o->zone_id = $zo?->id;
$parent = $o->parent();
$zone_id = $parent?->zone->zone_id;
// For flattened domains
if ($zo->domain->flatten && is_null($zone_id))
foreach ($zo->domain->zones as $zoo) {
$o->zone_id = $zoo->id;
$parent = $o->parent();
if ($parent)
break;
}
$region_id = $parent?->region_id;
$zone_id = $parent?->zone->zone_id;
}
return [ return [
'z'=>(int)$matches[1], 'z'=>(int)$zone_id ?: $matches[1],
'r'=>(int)$region_id,
'n'=>(int)$matches[2], 'n'=>(int)$matches[2],
'f'=>(int)$matches[3], 'f'=>(int)$matches[3],
'p'=>empty($matches[4]) ? 0 : (int)$matches[4], 'p'=>empty($matches[4]) ? 0 : (int)$matches[4],

View File

@ -59,6 +59,7 @@ final class Echomail extends Model implements Packet
$this->{$key} = $value; $this->{$key} = $value;
break; break;
case 'set_fftn':
// Values that we pass to boot() to record how we got this echomail // Values that we pass to boot() to record how we got this echomail
case 'set_pkt': case 'set_pkt':
case 'set_recvtime': case 'set_recvtime':
@ -91,7 +92,7 @@ final class Echomail extends Model implements Packet
parent::boot(); parent::boot();
static::creating(function($model) { static::creating(function($model) {
if (! is_null($model->errors)) if (isset($model->errors) && $model->errors->count())
throw new \Exception('Cannot save, validation errors exist'); throw new \Exception('Cannot save, validation errors exist');
}); });

View File

@ -55,6 +55,8 @@ final class Netmail extends Model implements Packet
break; break;
case 'set_fftn':
case 'set_tftn':
// Values that we pass to boot() to record how we got this netmail // Values that we pass to boot() to record how we got this netmail
case 'set_pkt': case 'set_pkt':
case 'set_recvtime': case 'set_recvtime':
@ -84,7 +86,7 @@ final class Netmail extends Model implements Packet
parent::boot(); parent::boot();
static::creating(function($model) { static::creating(function($model) {
if (! is_null($model->errors)) if (isset($model->errors) && $model->errors->count())
throw new \Exception('Cannot save, validation errors exist'); throw new \Exception('Cannot save, validation errors exist');
}); });

View File

@ -20,6 +20,7 @@ use App\Classes\Protocol\{Binkp,DNS,EMSI};
class Setup extends Model class Setup extends Model
{ {
public const PRODUCT_NAME = 'Clearing Houz'; public const PRODUCT_NAME = 'Clearing Houz';
public const PRODUCT_NAME_SHORT = 'clrghouz';
public const PRODUCT_ID = 0xAB8D; public const PRODUCT_ID = 0xAB8D;
public const PRODUCT_VERSION_MAJ = 0; public const PRODUCT_VERSION_MAJ = 0;
public const PRODUCT_VERSION_MIN = 0; public const PRODUCT_VERSION_MIN = 0;

View File

@ -5,9 +5,8 @@ namespace App\Notifications\Netmails;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Classes\FTN\Message;
use App\Notifications\Netmails; use App\Notifications\Netmails;
use App\Models\Netmail; use App\Models\{Echomail,Netmail};
use App\Traits\{MessagePath,PageTemplate}; use App\Traits\{MessagePath,PageTemplate};
class EchomailBadAddress extends Netmails class EchomailBadAddress extends Netmails
@ -16,14 +15,14 @@ class EchomailBadAddress extends Netmails
private const LOGKEY = 'NBA'; private const LOGKEY = 'NBA';
private Message $mo; private Echomail $mo;
/** /**
* Send a sysop a message if they give us a message with a bad address in it. * Send a sysop a message if they give us a message with a bad address in it.
* *
* @param Message $mo * @param Echomail $mo
*/ */
public function __construct(Message $mo) public function __construct(Echomail $mo)
{ {
parent::__construct(); parent::__construct();

View File

@ -8,7 +8,7 @@ namespace App\Traits;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator as ValidatorResult; use Illuminate\Support\MessageBag;
use App\Classes\FTN\Message; use App\Classes\FTN\Message;
use App\Models\Address; use App\Models\Address;
@ -20,7 +20,7 @@ trait MessageAttributes
// Items we need to set when creating() // Items we need to set when creating()
public Collection $set; public Collection $set;
// Validation Errors // Validation Errors
public ?ValidatorResult $errors = NULL; public ?MessageBag $errors = NULL;
private const cast_utf8 = [ private const cast_utf8 = [
'to', 'to',
@ -46,7 +46,7 @@ trait MessageAttributes
public function getContentAttribute(): string public function getContentAttribute(): string
{ {
if ($this->msg_src) if ($this->msg_src)
return $this->msg_src."\r"; return $this->msg_src;
// If we have a msg_src attribute, we'll use that // If we have a msg_src attribute, we'll use that
$result = $this->msg."\r\r"; $result = $this->msg."\r\r";
@ -60,7 +60,7 @@ trait MessageAttributes
if ($this->origin) if ($this->origin)
$result .= sprintf("%s",$this->origin); $result .= sprintf("%s",$this->origin);
return rtrim($result,"\r")."\r"; return rtrim($result,"\r");
} }
public function getDateAttribute(): Carbon public function getDateAttribute(): Carbon

View File

@ -1,6 +1,6 @@
<span> <span>
<small> <small>
<a href="/" class="goback float-start p-0">{{ request()->getHost() }}</a> &copy {{ \Carbon\Carbon::now()->year }} Deon George <a href="/" class="goback float-start p-0">{{ request()->getHost() }}</a> &copy {{ \Carbon\Carbon::now()->year }} Deon George
<span class="float-end"><strong class="highlight">clrghouz</strong> <small>[<strong class="gray">{{ gethostname() }}</strong>@if (File::exists('../VERSION')) @ <strong class="success">{{ chop(File::get('../VERSION')) }}</strong>@endif]</small></span> <span class="float-end"><strong class="highlight">{{ \App\Models\Setup::PRODUCT_NAME_SHORT }}</strong> <small>[<strong class="gray">{{ gethostname() }}</strong>@if (File::exists('../VERSION')) @ <strong class="success">{{ chop(File::get('../VERSION')) }}</strong>@endif]</small></span>
</small> </small>
</span> </span>

View File

@ -94,7 +94,7 @@
<div id="collapse_msg_{{ $loop->parent->parent->index }}_{{ $loop->index }}" class="accordion-collapse collapse @if($result->messages->count() === 1 && $loop->parent->first)show @endif" aria-labelledby="pktmsg" data-bs-parent="#accordion_file_{{ $loop->parent->parent->index }}"> <div id="collapse_msg_{{ $loop->parent->parent->index }}_{{ $loop->index }}" class="accordion-collapse collapse @if($result->messages->count() === 1 && $loop->parent->first)show @endif" aria-labelledby="pktmsg" data-bs-parent="#accordion_file_{{ $loop->parent->parent->index }}">
<div class="accordion-body"> <div class="accordion-body">
@if ($msg->errors) @if ($msg->errors)
@foreach ($msg->errors->messages()->all() as $error) @foreach ($msg->errors->all() as $error)
<div class="alert alert-danger"> <div class="alert alert-danger">
{{ $error }} {{ $error }}
</div> </div>

View File

@ -1,12 +1,12 @@
@php @php
use App\Models\Address; use App\Models\Address;
@endphp @endphp
<!-- $o=System::class --> <!-- $o=System::class -->
@extends('layouts.app') @extends('layouts.app')
@section('htmlheader_title') @section('htmlheader_title')
@can('admin',$o) @if($o->exists) Update @else Add @endif @endcan System @can('update_nn',$o) @if($o->exists) Update @else Add @endif @endcan System
@endsection @endsection
@section('content') @section('content')
@ -21,6 +21,7 @@
<p>This system is the ZC for the following zones: <strong class="highlight">{!! $o->zcs->sortBy('zone_id')->map(function($item) { return sprintf('%d@%s',$item->zone_id,$item->domain->name); })->join('</strong>, <strong class="highlight">') !!} </strong></p> <p>This system is the ZC for the following zones: <strong class="highlight">{!! $o->zcs->sortBy('zone_id')->map(function($item) { return sprintf('%d@%s',$item->zone_id,$item->domain->name); })->join('</strong>, <strong class="highlight">') !!} </strong></p>
@endif @endif
@include('widgets.error')
<div class="accordion" id="accordion_homepage"> <div class="accordion" id="accordion_homepage">
@if ($o->exists) @if ($o->exists)
<!-- System --> <!-- System -->

View File

@ -1,3 +1,4 @@
<!-- $o=System::class -->
<form class="needs-validation" method="post" novalidate> <form class="needs-validation" method="post" novalidate>
@csrf @csrf
<input type="hidden" name="system_id" value="{{ $o->id }}"> <input type="hidden" name="system_id" value="{{ $o->id }}">
@ -5,7 +6,7 @@
<div class="row pt-0"> <div class="row pt-0">
<div class="col-12"> <div class="col-12">
<div class="greyframe titledbox shadow0xb0"> <div class="greyframe titledbox shadow0xb0">
<h2 class="cap">@can('update',$o) @if($o->exists) Update @else Add @endif @endif System</h2> <h2 class="cap">@can($action,$o) @if($o->exists) Update @else Add @endif @endif System</h2>
@include('system.widget.system') @include('system.widget.system')
</div> </div>

View File

@ -1,9 +1,9 @@
@php @php
use App\Classes\FTN\Packet; use App\Classes\FTN\Packet;
use App\Models\{Mailer,User}; use App\Models\{Mailer,User};
@endphp @endphp
<!-- $o = System::class --> <!-- $o=System::class -->
<div class="row"> <div class="row">
<div class="col-xl-9 col-12"> <div class="col-xl-9 col-12">
@can('admin',$o) @can('admin',$o)
@ -46,7 +46,7 @@
<label for="name" class="form-label">BBS Name</label> <label for="name" class="form-label">BBS Name</label>
<div class="input-group has-validation"> <div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-pc"></i></span> <span class="input-group-text"><i class="bi bi-pc"></i></span>
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" placeholder="Name" name="name" value="{{ old('name',$o->name) }}" required @cannot('update',$o)readonly @endcannot autofocus> <input type="text" class="form-control @error('name') is-invalid @enderror" id="name" placeholder="Name" name="name" value="{{ old('name',$o->name) }}" required @cannot($action,$o)readonly @endcannot autofocus>
<span id="search-icon" style="width: 0;"><i style="border-radius: 50%;" class="spinner-border spinner-border-sm text-dark d-none"></i></span> <span id="search-icon" style="width: 0;"><i style="border-radius: 50%;" class="spinner-border spinner-border-sm text-dark d-none"></i></span>
<div id="system_search_results"></div> <div id="system_search_results"></div>
<span class="invalid-feedback" role="alert"> <span class="invalid-feedback" role="alert">
@ -227,7 +227,7 @@
<div class="row"> <div class="row">
<!-- Active --> <!-- Active -->
<div class="col-6"> <div class="col-6">
@can('update',$o) @can($action,$o)
<label for="active" class="form-label">Active</label> <label for="active" class="form-label">Active</label>
<div class="input-group"> <div class="input-group">
<div class="btn-group" role="group"> <div class="btn-group" role="group">
@ -245,7 +245,7 @@
<div class="row"> <div class="row">
<!-- Hold --> <!-- Hold -->
<div class="col-6"> <div class="col-6">
@can('update',$o) @can('admin',$o)
<label for="hold" class="form-label">Hold Mail <i class="bi bi-info-circle" title="Dont give the node any mail regardless of poll mode"></i></label> <label for="hold" class="form-label">Hold Mail <i class="bi bi-info-circle" title="Dont give the node any mail regardless of poll mode"></i></label>
<div class="input-group"> <div class="input-group">
<div class="btn-group" role="group"> <div class="btn-group" role="group">
@ -263,7 +263,7 @@
<div class="row"> <div class="row">
<!-- Poll Mode --> <!-- Poll Mode -->
<div class="col-12"> <div class="col-12">
@can('update',$o) @can($action,$o)
<label for="pollmode" class="form-label">Poll Mode <i class="bi bi-info-circle" title="Poll node when mail available, poll on a schedule or hold mail for collection"></i></label> <label for="pollmode" class="form-label">Poll Mode <i class="bi bi-info-circle" title="Poll node when mail available, poll on a schedule or hold mail for collection"></i></label>
<div class="input-group has-validation"> <div class="input-group has-validation">
<div class="btn-group @error('pollmode') is-invalid @enderror" role="group"> <div class="btn-group @error('pollmode') is-invalid @enderror" role="group">
@ -287,11 +287,18 @@
</div> </div>
<div class="row"> <div class="row">
<!-- @todo This is only relevant for uplinks, so hide it if this system isnt an uplink --> <div class="col-12">
<div class="col-12 @if((old('pollmode') === "0") || is_null($o->pollmode))d-none @endif" id="heartbeat_option">
@can('admin',$o)
<div class="row p-0"> <div class="row p-0">
<div class="col-6"> <div class="col-6">
<label for="autohold" class="form-label">Auto Hold</label>
<div class="input-group">
<button id="autohold" @class(['btn','btn-danger'=>$o->autohold,'btn-success'=>(! $o->autohold)])><i @class(['bi-toggle-on'=>$o->autohold,'bi-toggle-off'=>(! $o->autohold)])></i></button>
</div>
</div>
<!-- @todo This is only relevant for uplinks, so hide it if this system isnt an uplink -->
@can('admin',$o)
<div class="col-6 @if((old('pollmode') === "0") || is_null($o->pollmode))d-none @endif" id="heartbeat_option">
<label for="heartbeat" class="form-label">Heartbeat <i class="bi bi-info-circle" title="Attempt contact after last seen"></i></label> <label for="heartbeat" class="form-label">Heartbeat <i class="bi bi-info-circle" title="Attempt contact after last seen"></i></label>
<div class="input-group has-validation"> <div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-hourglass-bottom"></i></span> <span class="input-group-text"><i class="bi bi-hourglass-bottom"></i></span>
@ -303,18 +310,15 @@
</span> </span>
</div> </div>
</div> </div>
<div class="col-6">
<label for="passkey" class="form-label">Auto Hold</label>
<button id="autohold" @class(['btn','btn-danger'=>$o->autohold,'btn-success'=>(! $o->autohold)])><i @class(['bi-toggle-on'=>$o->autohold,'bi-toggle-off'=>(! $o->autohold)])></i></button>
</div>
</div>
@endcan @endcan
@if (! is_null($o->pollmode))
</div>
@if(! is_null($o->pollmode))
<div class="row"> <div class="row">
<div class="col-12 bg-secondary rounded p-2 small"> <div class="col-12 bg-secondary rounded p-2 small">
@if($job = $o->poll()) @if($job=$o->poll())
<div class="row p-0"> <div class="row p-0">
<div class="col-4 text-dark"> <div class="col-4 text-dark">
@if($job->attempts)Last: @else Scheduled: @endif @if($job->attempts)Last: @else Scheduled: @endif
@ -333,7 +337,7 @@
</div> </div>
</div> </div>
@if ($job->attempts) @if($job->attempts)
<div class="row"> <div class="row">
<div class="col-4 text-dark"> <div class="col-4 text-dark">
Next: Next:
@ -363,7 +367,7 @@
</div> </div>
</div> </div>
@if ($o->heartbeat) @if($o->heartbeat)
<div class="row"> <div class="row">
<div class="col-4 text-dark"> <div class="col-4 text-dark">
Next Heartbeat: Next Heartbeat:
@ -381,7 +385,7 @@
</div> </div>
<div class="col-8"> <div class="col-8">
<strong class="highlight"> <strong class="highlight">
@if ($job) Queued @if($job) Queued
@elseif ($o->autohold)Auto Hold @elseif ($o->autohold)Auto Hold
@else @else
@switch($o->pollmode) @switch($o->pollmode)
@ -416,7 +420,7 @@
@if($o->exists) @if($o->exists)
@can($action,$o) @can($action,$o)
<a href="{{ url('system') }}" class="btn btn-danger">Cancel</a> <a href="{{ url('system') }}" class="btn btn-danger">Cancel</a>
<button type="submit" name="submit" class="btn btn-success float-end">@if ($o->exists)Save @else Add @endif</button> <button type="submit" name="submit" class="btn btn-success float-end">@if($o->exists)Save @else Add @endif</button>
@else @else
<input type="hidden" name="system_id" value="{{ $o->id }}"> <input type="hidden" name="system_id" value="{{ $o->id }}">
<span><small><strong>NOTE:</strong> You'll be able to update these details after registration is completed.</small></span> <span><small><strong>NOTE:</strong> You'll be able to update these details after registration is completed.</small></span>
@ -449,7 +453,6 @@
}) })
$('#poll_hold').on('click',function() { $('#poll_hold').on('click',function() {
$('#heartbeat_option').addClass('d-none'); $('#heartbeat_option').addClass('d-none');
console.log('hold');
}) })
$("#autohold").on('click',function(item) { $("#autohold").on('click',function(item) {
var that = $(this) var that = $(this)

View File

@ -7,8 +7,8 @@ use Illuminate\Support\Facades\Storage;
use Tests\TestCase; use Tests\TestCase;
use App\Classes\File; use App\Classes\File;
use App\Classes\FTN\{Message,Packet}; use App\Classes\FTN\Packet;
use App\Models\{Address,Domain,System,Zone}; use App\Models\{Address,Domain,Echomail,System,Zone};
class PacketTest extends TestCase class PacketTest extends TestCase
{ {
@ -116,15 +116,16 @@ class PacketTest extends TestCase
$this->assertEquals(1,count($pkt)); $this->assertEquals(1,count($pkt));
$this->assertEquals('3634/27 12 154/10 221/6 218/840 770/1 633/280',$pkt->messages[0]->path[0]); $this->assertEquals('3634/27 12 154/10 221/6 218/840 770/1 633/280',$pkt->messages[0]->path[0]);
$this->assertEquals('1/120 18/0 116/116 120/616 123/0 10 25 126 160 180 200 525 755 3001',$pkt->messages[0]->seenby[0]); $this->assertEquals('1/120 18/0 116/116 120/616 123/0 10 25 126 160 180 200 525 755 3001',$pkt->messages[0]->seenby[0]);
$this->assertEquals('*The Gate BBS*Shelby, NC USA*thegateb.synchro.net* (1:3634/27)',$pkt->messages[0]->origin); $this->assertEquals(' * Origin: *The Gate BBS*Shelby, NC USA*thegateb.synchro.net* (1:3634/27)',$pkt->messages[0]->origin);
$this->assertEquals('1:3634/27.0@fidonet',$pkt->messages[0]->fftn); $this->assertEquals('1:3634/27.0@fidonet',$pkt->messages[0]->fftn->ftn);
$this->assertEquals('1:633/2744.0@fidonet',$pkt->messages[0]->tftn); $this->assertEquals('3:633/2744.0@fidonet',$pkt->tftn->ftn);
$this->assertEquals('Gate Keeper',$pkt->messages[0]->user_from); $this->assertEquals('Gate Keeper',$pkt->messages[0]->from);
$this->assertEquals('Meitsi',$pkt->messages[0]->user_to); $this->assertEquals('Meitsi',$pkt->messages[0]->to);
$this->assertEquals('Status of HAM radio in FidoNet',$pkt->messages[0]->subject); $this->assertEquals('Status of HAM radio in FidoNet',$pkt->messages[0]->subject);
$this->assertEquals('275.fidonet_ham@1:3634/27 29ddab74',$pkt->messages[0]->msgid); $this->assertEquals('275.fidonet_ham@1:3634/27 29ddab74',$pkt->messages[0]->msgid);
$this->assertEquals('1:229/428 012c0322',$pkt->messages[0]->replyid); $this->assertEquals('1:229/428 012c0322',$pkt->messages[0]->replyid);
$this->assertEquals('bc291b3ea15750c2d0c39c9221093901',md5($pkt->messages[0]->message)); $this->assertEquals('93a956cbde8b1215f4cf67e514116487',md5($pkt->messages[0]->content));
$this->assertEquals('93a956cbde8b1215f4cf67e514116487',$pkt->messages[0]->msg_crc);
} }
} }
@ -142,15 +143,16 @@ class PacketTest extends TestCase
$this->assertEquals(43,count($pkt)); $this->assertEquals(43,count($pkt));
$this->assertEquals('229/664 426 633/280',$pkt->messages[0]->path[0]); $this->assertEquals('229/664 426 633/280',$pkt->messages[0]->path[0]);
$this->assertEquals('15/0 106/201 128/260 129/305 153/7715 218/700 221/6 226/30 227/114',$pkt->messages[0]->seenby[0]); $this->assertEquals('15/0 106/201 128/260 129/305 153/7715 218/700 221/6 226/30 227/114',$pkt->messages[0]->seenby[0]);
$this->assertEquals('Northern Realms (1:229/664)',$pkt->messages[0]->origin); $this->assertEquals(' * Origin: Northern Realms (1:229/664)',$pkt->messages[0]->origin);
$this->assertEquals('1:229/664.0@fidonet',$pkt->messages[0]->fftn); $this->assertEquals('1:229/664.0@fidonet',$pkt->messages[0]->fftn->ftn);
$this->assertEquals('1:633/2744.0@fidonet',$pkt->messages[0]->tftn); $this->assertEquals('3:633/2744.0@fidonet',$pkt->tftn->ftn);
$this->assertEquals('Northern Realms',$pkt->messages[0]->user_from); $this->assertEquals('Northern Realms',$pkt->messages[0]->from);
$this->assertEquals('All',$pkt->messages[0]->user_to); $this->assertEquals('All',$pkt->messages[0]->to);
$this->assertEquals('NYPost Daily Horoscope',$pkt->messages[0]->subject); $this->assertEquals('NYPost Daily Horoscope',$pkt->messages[0]->subject);
$this->assertEquals('1:229/664 56db6f89',$pkt->messages[0]->msgid); $this->assertEquals('1:229/664 56db6f89',$pkt->messages[0]->msgid);
$this->assertEquals('',$pkt->messages[0]->replyid); $this->assertEquals('',$pkt->messages[0]->replyid);
$this->assertEquals('b8c33987647e88f86456f0e571e98398',md5($pkt->messages[0]->message)); $this->assertEquals('ad761cfc02d87383056cc29e026b3d57',md5($pkt->messages[0]->content));
$this->assertEquals('ad761cfc02d87383056cc29e026b3d57',$pkt->messages[0]->msg_crc);
} }
} }
@ -166,18 +168,19 @@ class PacketTest extends TestCase
$this->assertInstanceOf(Packet\FSC48::class,$pkt); $this->assertInstanceOf(Packet\FSC48::class,$pkt);
$this->assertEquals('ABCDEFG#',$pkt->password); $this->assertEquals('ABCDEFG#',$pkt->password);
$this->assertEquals(4,count($pkt)); $this->assertEquals(4,count($pkt));
$this->assertInstanceOf(Message::class,$pkt->messages[0]); $this->assertInstanceOf(Echomail::class,$pkt->messages[0]);
$this->assertEquals('3/165 100 184',$pkt->messages[0]->path[0]); $this->assertEquals('3/165 100 184',$pkt->messages[0]->path[0]);
$this->assertEquals('1/100 179 2/100 116 3/100 105 107 108 109 110 111 113 119 120 126 127',$pkt->messages[0]->seenby[0]); $this->assertEquals('1/100 179 2/100 116 3/100 105 107 108 109 110 111 113 119 120 126 127',$pkt->messages[0]->seenby[0]);
$this->assertEquals('www.theunderground.us Telnet 10023 SSH 7771 (21:3/165)',$pkt->messages[0]->origin); $this->assertEquals(' * Origin: www.theunderground.us Telnet 10023 SSH 7771 (21:3/165)',$pkt->messages[0]->origin);
$this->assertEquals('21:3/165.0@fsxnet',$pkt->messages[0]->fftn); $this->assertEquals('21:3/165.0@fsxnet',$pkt->messages[0]->fftn->ftn);
$this->assertEquals('21:3/2744.0@fsxnet',$pkt->messages[0]->tftn); $this->assertEquals('21:3/2744.0@fsxnet',$pkt->tftn->ftn);
$this->assertEquals('ibbslastcall',$pkt->messages[0]->user_from); $this->assertEquals('ibbslastcall',$pkt->messages[0]->from);
$this->assertEquals('All',$pkt->messages[0]->user_to); $this->assertEquals('All',$pkt->messages[0]->to);
$this->assertEquals('ibbslastcall-data',$pkt->messages[0]->subject); $this->assertEquals('ibbslastcall-data',$pkt->messages[0]->subject);
$this->assertEquals('21:3/165 6b42fe09',$pkt->messages[0]->msgid); $this->assertEquals('21:3/165 6b42fe09',$pkt->messages[0]->msgid);
$this->assertEquals('',$pkt->messages[0]->replyid); $this->assertEquals('',$pkt->messages[0]->replyid);
$this->assertEquals('aa6bc82b63355ab68889f61822305072',md5($pkt->messages[0]->message)); $this->assertEquals('413eb972809e1ce8ac5f5cf7b545fc10',md5($pkt->messages[0]->content));
$this->assertEquals('413eb972809e1ce8ac5f5cf7b545fc10',$pkt->messages[0]->msg_crc);
} }
} }
@ -185,6 +188,7 @@ class PacketTest extends TestCase
{ {
$this->init_private(); $this->init_private();
// @note this pkt is from/to a sender not defined
$f = $this->mail_file('mail/test_nomsgid_origin.pkt'); $f = $this->mail_file('mail/test_nomsgid_origin.pkt');
foreach ($f as $packet) { foreach ($f as $packet) {
$pkt = Packet::process($packet,$f->itemName(),$f->itemSize()); $pkt = Packet::process($packet,$f->itemName(),$f->itemSize());
@ -193,21 +197,21 @@ class PacketTest extends TestCase
$this->assertEquals(1,$pkt->count()); $this->assertEquals(1,$pkt->count());
foreach ($pkt as $msg) { foreach ($pkt as $msg) {
$this->assertNotTrue($msg->isNetmail()); $this->assertInstanceOf(Echomail::class,$msg);
$this->assertEquals('PVT_TEST',$msg->echoarea); $this->assertEquals('PVT_TEST',$msg->set->get('set_echoarea'));
} }
$this->assertInstanceOf(Message::class,$pkt->messages[0]);
$this->assertEquals('1/1 999/1',$pkt->messages[0]->path[0]); $this->assertEquals('1/1 999/1',$pkt->messages[0]->path[0]);
$this->assertEquals('Daytona BBS (Netherlands) (10:3/151)',$pkt->messages[0]->origin); $this->assertEquals(' * Origin: Daytona BBS (Netherlands) (10:3/151)',$pkt->messages[0]->origin);
$this->assertEquals('10:3/151.0@private',$pkt->messages[0]->fftn); $this->assertEquals('10:3/151.0@private',$pkt->messages[0]->set->get('set_fftn'));
$this->assertEquals('10:999/999.0@private',$pkt->messages[0]->tftn); $this->assertEquals('10:999/999.0@private',$pkt->tftn_t);
$this->assertEquals('Hub Robot',$pkt->messages[0]->user_from); $this->assertEquals('Hub Robot',$pkt->messages[0]->from);
$this->assertEquals('Henk Hilgersum',$pkt->messages[0]->user_to); $this->assertEquals('Henk Hilgersum',$pkt->messages[0]->to);
$this->assertEquals('LEMEIN',$pkt->messages[0]->subject); $this->assertEquals('LEMEIN',$pkt->messages[0]->subject);
$this->assertEquals('',$pkt->messages[0]->msgid); $this->assertEquals('',$pkt->messages[0]->msgid);
$this->assertEquals('',$pkt->messages[0]->replyid); $this->assertEquals('',$pkt->messages[0]->replyid);
$this->assertEquals('6bbe3d0475cf60804ca4e942212d3456',md5($pkt->messages[0]->message)); $this->assertEquals('a5933ea2bbcddf955d6940e1dad5cc1b',md5($pkt->messages[0]->content));
$this->assertEquals('a5933ea2bbcddf955d6940e1dad5cc1b',$pkt->messages[0]->msg_crc);
} }
} }
@ -227,7 +231,7 @@ class PacketTest extends TestCase
foreach ($pkt as $msg) { foreach ($pkt as $msg) {
dump($msg); dump($msg);
$this->assertNotTrue($msg->isNetmail()); $this->assertInstanceOf(Echomail::class,$msg);
$this->assertNotFalse($msg->path->search('1/1 999/1')); $this->assertNotFalse($msg->path->search('1/1 999/1'));
$this->assertNotFalse($msg->seenby->search('1/1 4 3/0 999/1 999')); $this->assertNotFalse($msg->seenby->search('1/1 4 3/0 999/1 999'));
} }
@ -248,22 +252,22 @@ class PacketTest extends TestCase
$this->assertEquals(1,$pkt->count()); $this->assertEquals(1,$pkt->count());
foreach ($pkt as $msg) { foreach ($pkt as $msg) {
$this->assertNotTrue($msg->isNetmail()); $this->assertInstanceOf(Echomail::class,$msg);
$this->assertEquals('PVT_TEST',$msg->echoarea); $this->assertEquals('PVT_TEST',$msg->set->get('set_echoarea'));
$this->assertNotFalse($msg->seenby->search('1/1 999/1 999')); $this->assertNotFalse($msg->seenby->search('1/1 999/1 999'));
} }
$this->assertInstanceOf(Message::class,$pkt->messages[0]);
$this->assertEquals('999/1',$pkt->messages[0]->path[0]); $this->assertEquals('999/1',$pkt->messages[0]->path[0]);
$this->assertEquals('Alterant MailHUB at your service (10:999/1)',$pkt->messages[0]->origin); $this->assertEquals(' * Origin: Alterant MailHUB at your service (10:999/1)',$pkt->messages[0]->origin);
$this->assertEquals('10:999/1.0@private',$pkt->messages[0]->fftn); $this->assertEquals('10:999/1.0@private',$pkt->messages[0]->set->get('set_fftn'));
$this->assertEquals('10:999/999.0@private',$pkt->messages[0]->tftn); $this->assertEquals('10:999/999.0@private',$pkt->tftn_t);
$this->assertEquals('Hub Robot',$pkt->messages[0]->user_from); $this->assertEquals('Hub Robot',$pkt->messages[0]->from);
$this->assertEquals('deon',$pkt->messages[0]->user_to); $this->assertEquals('deon',$pkt->messages[0]->to);
$this->assertEquals('Hub Robot Report',$pkt->messages[0]->subject); $this->assertEquals('Hub Robot Report',$pkt->messages[0]->subject);
$this->assertEquals('10:999/1 612aecda',$pkt->messages[0]->msgid); $this->assertEquals('10:999/1 612aecda',$pkt->messages[0]->msgid);
$this->assertEquals('',$pkt->messages[0]->replyid); $this->assertEquals('',$pkt->messages[0]->replyid);
$this->assertEquals('61078e680cda04c8b5eba0f712582e70',md5($pkt->messages[0]->message)); $this->assertEquals('354e42649bc4e6aea5f0833ce5ad43c5',md5($pkt->messages[0]->content));
$this->assertEquals('354e42649bc4e6aea5f0833ce5ad43c5',$pkt->messages[0]->msg_crc);
} }
} }
@ -282,14 +286,13 @@ class PacketTest extends TestCase
foreach ($pkt as $msg) { foreach ($pkt as $msg) {
$messages = TRUE; $messages = TRUE;
$this->assertNotTrue($msg->isNetmail()); $this->assertInstanceOf(Echomail::class,$pkt->messages[0]);
$this->assertSame('21:1/151 6189F64C',$msg->msgid); $this->assertSame('21:1/151 6189F64C',$msg->msgid);
$this->assertSame('db727bd3778ddd457784ada4bf016010',md5($msg->message)); $this->assertSame('1fe499b444ba7e391fbb4f1bc8a18ac1',md5($msg->content));
$this->assertSame('5b627ab5936b0550a97b738f4deff419',md5($msg->message_src)); $this->assertSame('1fe499b444ba7e391fbb4f1bc8a18ac1',$msg->msg_crc);
$this->assertContains('3/2744 4/100 106 5/100',$msg->seenby); $this->assertContains('3/2744 4/100 106 5/100',$msg->seenby);
$this->assertContains('1/151 100 3/100',$msg->path); $this->assertContains('1/151 100 3/100',$msg->path);
$this->assertCount(11,$msg->seenby); $this->assertCount(11,$msg->seenby);
$this->assertCount(0,$msg->unknown);
} }
$this->assertTrue($messages); $this->assertTrue($messages);
@ -311,14 +314,13 @@ class PacketTest extends TestCase
foreach ($pkt as $msg) { foreach ($pkt as $msg) {
$messages = TRUE; $messages = TRUE;
$this->assertNotTrue($msg->isNetmail()); $this->assertInstanceOf(Echomail::class,$msg);
$this->assertSame('21:1/126 eec6e958',$msg->msgid); $this->assertSame('21:1/126 eec6e958',$msg->msgid);
$this->assertSame('5a525cc1c393292dc65160a852d4d615',md5($msg->message)); $this->assertSame('a354ed6afcb436081e123e12dc0c8764',md5($msg->content));
$this->assertSame('a3193edcc68521d4ed07da6db2aeb0b6',md5($msg->message_src)); $this->assertSame('a354ed6afcb436081e123e12dc0c8764',$msg->msg_crc);
$this->assertContains('1/995 2/100 116 1202 3/100 105 107 108 109 110 111 112 113 117 119',$msg->seenby); $this->assertContains('1/995 2/100 116 1202 3/100 105 107 108 109 110 111 112 113 117 119',$msg->seenby);
$this->assertContains('1/126 100 3/100',$msg->path); $this->assertContains('1/126 100 3/100',$msg->path);
$this->assertCount(10,$msg->seenby); $this->assertCount(10,$msg->seenby);
$this->assertCount(0,$msg->unknown);
} }
$this->assertTrue($messages); $this->assertTrue($messages);
@ -340,14 +342,13 @@ class PacketTest extends TestCase
foreach ($pkt as $msg) { foreach ($pkt as $msg) {
$messages = TRUE; $messages = TRUE;
$this->assertNotTrue($msg->isNetmail()); $this->assertInstanceOf(Echomail::class,$msg);
$this->assertSame('10:999/1 612aecda',$msg->msgid); $this->assertSame('10:999/1 612aecda',$msg->msgid);
$this->assertSame('61078e680cda04c8b5eba0f712582e70',md5($msg->message)); $this->assertSame('354e42649bc4e6aea5f0833ce5ad43c5',md5($msg->content));
$this->assertSame('b9d65d4f7319ded282f3f1986276ae79',md5($msg->message_src)); $this->assertSame('354e42649bc4e6aea5f0833ce5ad43c5',$msg->msg_crc);
$this->assertContains('1/1 999/1 999',$msg->seenby); $this->assertContains('1/1 999/1 999',$msg->seenby);
$this->assertContains('999/1',$msg->path); $this->assertContains('999/1',$msg->path);
$this->assertCount(1,$msg->seenby); $this->assertCount(1,$msg->seenby);
$this->assertCount(0,$msg->unknown);
} }
$this->assertTrue($messages); $this->assertTrue($messages);
@ -371,27 +372,25 @@ class PacketTest extends TestCase
$c++; $c++;
$messages = TRUE; $messages = TRUE;
$this->assertNotTrue($msg->isNetmail()); $this->assertInstanceOf(Echomail::class,$msg);
switch ($c) { switch ($c) {
case 1: case 1:
$this->assertSame('3:712/886 220da89f',$msg->msgid); $this->assertSame('3:712/886 220da89f',$msg->msgid);
$this->assertSame('9f5544bea46ef57a45f561b9e07dd71e',md5($msg->message)); $this->assertSame('49caf318b7bebedc652f31622d014430',md5($msg->content));
$this->assertSame('9bf4b8c348ac235cc218577abf7140af',md5($msg->message_src)); $this->assertSame('49caf318b7bebedc652f31622d014430',$msg->msg_crc);
$this->assertContains('633/0 267 280 281 408 410 412 509 509 640/1384 712/114 550 620 848',$msg->seenby); $this->assertContains('633/0 267 280 281 408 410 412 509 509 640/1384 712/114 550 620 848',$msg->seenby);
$this->assertContains('712/886 848 633/280',$msg->path); $this->assertContains('712/886 848 633/280',$msg->path);
$this->assertCount(2,$msg->seenby); $this->assertCount(2,$msg->seenby);
$this->assertCount(0,$msg->unknown);
break; break;
case 4: case 4:
$this->assertSame('',$msg->msgid); $this->assertNull($msg->msgid);
$this->assertSame('b975057002def556c5a9497aacd000fb',md5($msg->message)); $this->assertSame('514205c1670312887a68272b21df593c',md5($msg->content));
$this->assertSame('c90dd234d2aa029af22c453a25b79a4e',md5($msg->message_src)); $this->assertSame('514205c1670312887a68272b21df593c',$msg->msg_crc);
$this->assertContains('633/267 280 281 384 408 410 412 418 420 509 509 712/848 770/1 100 330',$msg->seenby); $this->assertContains('633/267 280 281 384 408 410 412 418 420 509 509 712/848 770/1 100 330',$msg->seenby);
$this->assertContains('772/210 770/1 633/280',$msg->path); $this->assertContains('772/210 770/1 633/280',$msg->path);
$this->assertCount(2,$msg->seenby); $this->assertCount(2,$msg->seenby);
$this->assertCount(0,$msg->unknown);
default: default:
continue 2; continue 2;

View File

@ -323,8 +323,6 @@ class RoutingTest extends TestCase
// Create a child // Create a child
$ao = Address::createFTN('100:10/21.2@a',$so); $ao = Address::createFTN('100:10/21.2@a',$so);
$ao->region_id = 1; // @todo This should be worked out from the parent node (if exists), or another node on the same host
$ao->save();
$ao = Address::findFTN('100:10/21.0@a'); $ao = Address::findFTN('100:10/21.0@a');
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]); $ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);