From fcdde10512caf0a9aff2d0e127ea8912dcf1bf62 Mon Sep 17 00:00:00 2001 From: Deon George Date: Sat, 11 Sep 2021 23:32:10 +1000 Subject: [PATCH] Auto create nodes that are discovered by message packets --- app/Classes/FTN/Message.php | 35 +++++++++++- app/Classes/FTN/Packet.php | 69 +++++++++++++++++------ app/Http/Controllers/DomainController.php | 1 + app/Jobs/MessageProcess.php | 2 +- app/Models/Address.php | 2 + 5 files changed, 87 insertions(+), 22 deletions(-) diff --git a/app/Classes/FTN/Message.php b/app/Classes/FTN/Message.php index 196ea2b..f499efd 100644 --- a/app/Classes/FTN/Message.php +++ b/app/Classes/FTN/Message.php @@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Validator as ValidatorResult; use App\Classes\FTN as FTNBase; -use App\Models\{Address,Zone}; +use App\Models\{Address,Domain,Zone}; use App\Rules\TwoByteInteger; use App\Traits\EncodeUTF8; @@ -283,6 +283,35 @@ class Message extends FTNBase case 'fn': return $this->src ? Arr::get($this->src,'n') : Arr::get($this->header,'onet');; case 'ff': return $this->src ? Arr::get($this->src,'f') : Arr::get($this->header,'onode');; case 'fp': return Arr::get($this->src,'p'); + case 'fd': return Arr::get($this->src,'d'); + + case 'fdomain': + // 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->src,'d'))) + return $this->zone->domain; + + // If we get the domain from the packet, we'll find it + if ($x=Arr::get($this->src,'d')) { + return Domain::where('name',$x)->single(); + } + + return NULL; + + case 'fzone': + // Use the zone if this class was called with it. + if ($this->zone && ($this->fz == $this->zone->zone_id)) + return $this->zone; + + // If we have a domain, we'll use the zone from the domain + if ($x=$this->fdomain) { + if (($x=$this->fdomain->zones->search(function($item) { return $item->zone_id == $this->fz; })) !== FALSE) + return $this->fdomain->zones->get($x); + } + + // No domain, so we'll use the default zone + return Zone::where('zone_id',$this->fz) + ->where('default',TRUE) + ->single(); // To Addresses // Echomail doesnt have a zone, so we'll use the source zone @@ -485,7 +514,7 @@ class Message extends FTNBase /** * Return an array of flag descriptions * - * @return array + * @return Collection * * http://ftsc.org/docs/fsc-0001.000 * AttributeWord bit meaning @@ -762,7 +791,7 @@ class Message extends FTNBase // Otherwise get it from our zone object and packet header } elseif ($this->zone) { - $this->src = Address::parseFTN(sprintf('%d:%d/%d.%d',$this->zone->zone_id,$this->fn,$this->ff,$this->fp)); + $this->src = Address::parseFTN(sprintf('%d:%d/%d.%d@%s',$this->zone->zone_id,$this->fn,$this->ff,$this->fp,$this->zone->domain->name)); } // Parse SEEN-BY diff --git a/app/Classes/FTN/Packet.php b/app/Classes/FTN/Packet.php index 7d4c14d..cbc08e5 100644 --- a/app/Classes/FTN/Packet.php +++ b/app/Classes/FTN/Packet.php @@ -10,7 +10,8 @@ use Illuminate\Support\Facades\Redis; use Symfony\Component\HttpFoundation\File\File; use App\Classes\FTN as FTNBase; -use App\Models\{Address,Setup,Software,Zone}; +use App\Http\Controllers\DomainController; +use App\Models\{Address,Setup,Software,System,Zone}; class Packet extends FTNBase implements \Iterator, \Countable { @@ -415,31 +416,63 @@ class Packet extends FTNBase implements \Iterator, \Countable * Parse a message in a mail packet * * @param string $message - * @throws InvalidPacketException + * @throws InvalidPacketException|\Exception */ private function parseMessage(string $message): void { $msg = Message::parseMessage($message,$this->zone); // If the message is invalid, we'll ignore it - if ($msg->errors && ( - $msg->errors->messages()->has('from') - || $msg->errors->messages()->has('user_from') - || $msg->errors->messages()->has('user_to') - )) - { - $this->errors->push($msg); - Log::error(sprintf('%s:! Skipping message [%s] due to errors (%s)...',self::LOGKEY,$msg->msgid,join(',',$msg->errors->messages()->keys()))); + if ($msg->errors) { + // If the from address doenst exist, we'll create a new entry + if ($msg->errors->messages()->has('from')) { + Log::alert(sprintf('%s: - From FTN is not defined, creating new entry for [%s]',self::LOGKEY,$msg->fboss)); + + 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, + ]); + Address::reguard(); + + $ao->active = TRUE; + $ao->role = DomainController::NODE_UNKNOWN; + + // This shouldnt happen + if ($ao->exists) { + Log::error(sprintf('%s: - Attempting to create address [%s], but it exists?',self::LOGKEY,$msg->fboss)); + $this->errors->push($msg); + return; + } + + System::unguard(); + $so = System::firstOrCreate([ + 'name' => 'Discovered System', + 'sysop' => 'Unknown', + 'location' => '', + 'active' => TRUE, + ]); + System::reguard(); + + $so->addresses()->save($ao); + + } elseif($msg->errors->messages()->has('user_from') || $msg->errors->messages()->has('user_to')) { + Log::error(sprintf('%s:! Skipping message [%s] due to errors (%s)...',self::LOGKEY,$msg->msgid,join(',',$msg->errors->messages()->keys()))); + $this->errors->push($msg); + return; + } + } + + if ($this->use_redis) { + $key = $msg->msgid ?: sprintf('%s %s',$msg->fftn,Carbon::now()->timestamp); + Redis::set($key,serialize($msg)); + $this->messages->push($key); } else { - if ($this->use_redis) { - $key = $msg->msgid ?: sprintf('%s %s',$msg->fftn,Carbon::now()->timestamp); - Redis::set($key,serialize($msg)); - $this->messages->push($key); - - } else { - $this->messages->push($msg); - } + $this->messages->push($msg); } } } \ No newline at end of file diff --git a/app/Http/Controllers/DomainController.php b/app/Http/Controllers/DomainController.php index 3dfcb14..f43875d 100644 --- a/app/Http/Controllers/DomainController.php +++ b/app/Http/Controllers/DomainController.php @@ -18,6 +18,7 @@ class DomainController extends Controller public const NODE_PVT = 1<<5; // Pvt public const NODE_HOLD = 1<<6; // Hold public const NODE_DOWN = 1<<7; // Down + public const NODE_UNKNOWN = 1<<8; // Down // http://ftsc.org/docs/frl-1002.001 public const NUMBER_MAX = 0x7fff; diff --git a/app/Jobs/MessageProcess.php b/app/Jobs/MessageProcess.php index eebda34..eef92bc 100644 --- a/app/Jobs/MessageProcess.php +++ b/app/Jobs/MessageProcess.php @@ -112,7 +112,7 @@ class MessageProcess implements ShouldQueue $reply .= "------------------------------ END MESSAGE ------------------------------\r"; - $o = new Netmail(); + $o = new Netmail; $o->to = $this->msg->user_from; $o->from = Setup::PRODUCT_NAME; $o->subject = 'Message Undeliverable - '.$this->msg->msgid; diff --git a/app/Models/Address.php b/app/Models/Address.php index 84efa93..ac02c9c 100644 --- a/app/Models/Address.php +++ b/app/Models/Address.php @@ -69,6 +69,7 @@ class Address extends Model break; + case DomainController::NODE_UNKNOWN: case DomainController::NODE_ACTIVE: case DomainController::NODE_POINT: // Nodes dont have children, but must return a relationship instance @@ -181,6 +182,7 @@ class Address extends Model break; + case DomainController::NODE_UNKNOWN: case DomainController::NODE_POINT: // @todo Points - if the boss is defined, we should return it. return NULL;