<?php namespace App\Jobs; use Carbon\Carbon; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Log; use App\Classes\FTN\{Message,Process}; use App\Models\{Echoarea,Echomail,Netmail,Setup}; class MessageProcess implements ShouldQueue { private const LOGKEY = 'JMP'; use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; private Message $msg; private bool $skipbot; public function __construct(Message $msg,bool $skipbot=FALSE) { // Some checks $this->msg = $msg; $this->skipbot = $skipbot; } /** * When calling MessageProcess - we assume that the packet is from a valid source */ public function handle() { // Load our details $ftns = Setup::findOrFail(config('app.id'))->system->addresses; // If we are a netmail if ($this->msg->isNetmail()) { // @todo Enable checks to reject old messages // @todo Enable checks to reject duplicate // @todo Enable checks to see if this is a file request or file send // Determine if the message is to this system, or in transit if ($ftns->search(function($item) { return $this->msg->tftn == $item->ftn; }) !== FALSE) { // @todo Check if it is a duplicate message // @todo Check if the message is from a system we know about $processed = FALSE; // If the message is to a bot, we'll process it if (! $this->skipbot) foreach (config('process.robots') as $class) { if ($processed = $class::handle($this->msg)) { break; } } // We'll ignore messages from *fix users if (in_array(strtolower($this->msg->user_from),['filefix','areafix'])) { Log::info(sprintf('Ignoring Netmail to the Hub from (%s) [%s] - its from a bot.',$this->msg->user_from,$this->msg->fftn)); $o = $this->create_netmail($this->msg); $o->local = TRUE; $o->save(); $processed = TRUE; } // If not processed, no users here! if (! $processed) { $reject = [ 'ÚÄ¿ÚÄ¿ ÂÚÄ¿ÚÄ¿Ú¿', '³ ³ÄÙ ³³ÄÙ³ ³ ', 'Á ÀÄÙÀÄÙÀÄÙÀÄÙ Á ' ]; Log::info(sprintf('Netmail to the Hub from (%s) [%s] but no users here.',$this->msg->user_from,$this->msg->fftn)); $reply = "Your Netmail was not processed by the hub and cannot be delivered to anybody (as there are no users here).\r"; $reply .= "\r"; $reply .= "\r"; $reply .= "This is your original message:\r"; $reply .= "------------------------------ BEING MESSAGE ------------------------------\r"; $reply .= sprintf("TO: %s\r",$this->msg->user_to); $reply .= sprintf("SUBJECT: %s\r",$this->msg->subject); $reply .= $this->msg->message; $reply .= "------------------------------ CONTROL LINES ------------------------------\r"; $reply .= sprintf("DATE: %s\r",$this->msg->date->format('Y-m-d H:i:s')); $reply .= sprintf("MSGID: %s\r",$this->msg->msgid); foreach ($this->msg->kludge as $k=>$v) $reply .= sprintf("@%s: %s\r",strtoupper($k),$v); foreach ($this->msg->via as $via) $reply .= sprintf("VIA: %s\r",$via); $reply .= "------------------------------ END MESSAGE ------------------------------\r"; $o = new Netmail; $o->to = $this->msg->user_from; $o->from = Setup::PRODUCT_NAME; $o->subject = 'Message Undeliverable - '.$this->msg->msgid; $o->datetime = $this->msg->date; $o->tzoffset = $this->msg->date->utcOffset(); $o->cost = 0; $o->flags = Message::FLAG_LOCAL; $o->fftn_id = ($x=$this->msg->tftn_o) ? $x->id : NULL; $o->tftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL; $o->replyid = $this->msg->msgid; $o->msg = Process::format_msg($reply,$reject); $o->tagline = 'Do you think it was fate which brought us together? Nah, bad luck :('; $o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID); $o->save(); } // If in transit, store for collection } else { Log::info(sprintf('%s:Netmail [%s] in transit to (%s) [%s] from (%s) [%s].', self::LOGKEY, $this->msg->msgid, $this->msg->user_to,$this->msg->tftn, $this->msg->user_from,$this->msg->fftn, )); // @todo Check if the message is to a system we know about // @todo In transit loop checking // @todo In transit TRACE response $o = $this->create_netmail($this->msg); $o->save(); } // Else we are echomail } else { Log::debug(sprintf('%s: - Looking for echomail area [%s] for mail from [%s]',self::LOGKEY,$this->msg->echoarea,$this->msg->fboss)); if (! $this->msg->fboss_o) { Log::error(sprintf('%s:! Cannot process message for echomail area [%s] for mail from [%s] with msgid [%s] - no boss object?',self::LOGKEY,$this->msg->echoarea,$this->msg->fboss,$this->msg->msgid)); return; } $ea = Echoarea::where('name',strtoupper($this->msg->echoarea)) ->where('domain_id',$this->msg->fboss_o->zone->domain_id) ->single(); if (! $ea) { Log::alert(sprintf('%s:! Echoarea [%s] doesnt exist for zone [%d]',self::LOGKEY,$this->msg->echoarea,$this->msg->fboss_o->zone->zone_id)); return; } Log::debug(sprintf('%s: - Processing echomail [%s] in [%s].',self::LOGKEY,$this->msg->msgid,$this->msg->echoarea)); // Check for duplicate messages // FTS-0009.001 if ($this->msg->msgid) { $o = Echomail::where('msgid',$this->msg->msgid) ->where('fftn_id',($x=$this->msg->fboss_o) ? $x->id : NULL) ->where('datetime','>',Carbon::now()->subYears(3)) ->single(); Log::debug(sprintf('%s: - Checking for duplicate from host id [%d].',self::LOGKEY,($x=$this->msg->fboss_o) ? $x->id : NULL)); if ($o) { Log::alert(sprintf('%s:! Duplicate echomail [%s] in [%s] from (%s) [%s] to (%s) - updating seenby.', self::LOGKEY, $this->msg->msgid, $this->msg->echoarea, $this->msg->user_from,$this->msg->fftn, $this->msg->user_to, )); if (! $o->msg_crc) $o->msg_crc = md5($this->msg->message); $o->save(); // If the path is empty, then its probably because of the previous bug, we'll replace it. // @todo This duplicate message may have gone via a different path, be nice to record it. //$o->path()->sync($o->path->pluck('id')->merge($this->msg->pathaddress)->toArray()); // @todo if we have an export for any of the seenby addresses, remove it $o->seenby()->sync($o->seenby->pluck('id')->merge($this->msg->seenaddress)->filter()->toArray()); return; } } // Find another message with the same msg_crc if ($this->msg->message) { $o = Echomail::where('msg_crc',$xx=md5($this->msg->message)) ->where('fftn_id',($x=$this->msg->fboss_o) ? $x->id : NULL) ->where('datetime','>',Carbon::now()->subWeek()) ->get(); if ($o->count()) Log::alert(sprintf('%s:! Duplicate message CRC [%s] in [%s].', self::LOGKEY, $xx, $o->pluck('id')->join('|') )); } // @todo Can the sender create it if it doesnt exist? // @todo Can the sender send messages to this area? // - Create it, or // - Else record in bad area // We know about this area, store it $o = new Echomail; $o->init(); $o->to = $this->msg->user_to; $o->from = $this->msg->user_from; $o->subject = $this->msg->subject; $o->datetime = $this->msg->date; $o->tzoffset = $this->msg->date->utcOffset(); $o->fftn_id = ($x=$this->msg->fboss_o) ? $x->id : NULL; // @todo This should be the node that originated the message - but since that node is not in the DB it would be null $o->echoarea_id = $ea->id; $o->msgid = $this->msg->msgid; $o->replyid = $this->msg->replyid; $o->msg = $this->msg->message_src."\r"; $o->msg_src = $this->msg->message_src; $o->msg_crc = md5($this->msg->message); $o->rogue_seenby = $this->msg->rogue_seenby; $o->rogue_path = $this->msg->rogue_path; $o->set_path = $this->msg->pathaddress; $o->set_seenby = $this->msg->seenaddress; $o->save(); Log::info(sprintf('%s: - Echomail [%s] in [%s] from (%s) [%s] to (%s) - [%s].', self::LOGKEY, $this->msg->msgid, $this->msg->echoarea, $this->msg->user_from,$this->msg->fftn, $this->msg->user_to, $o->id, )); // If the message is to a bot, but not rescanned, or purposely skipbot set, we'll process it if ((! $this->skipbot) && (! $this->msg->rescanned->count())) foreach (config('process.echomail') as $class) { if ($class::handle($this->msg)) { break; } } } } private function create_netmail(Message $msg): Netmail { $o = new Netmail; $o->to = $msg->user_to; $o->from = $msg->user_from; $o->fftn_id = ($x=$msg->fftn_o) ? $x->id : NULL; $o->tftn_id = ($x=$msg->tftn_o) ? $x->id : NULL; $o->datetime = $msg->date; $o->tzoffset = $msg->date->utcOffset(); $o->flags = $msg->flags; $o->cost = $msg->cost; $o->msgid = $msg->msgid; $o->subject = $msg->subject; $o->msg = $msg->message; foreach ($msg->via as $v) $o->msg .= sprintf("\01Via %s\r",$v); $o->msg_src = $msg->message_src; $o->msg_crc = md5($msg->message); // @todo DB schema needs to handle this return $o; } }