319 lines
10 KiB
PHP
319 lines
10 KiB
PHP
<?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 Illuminate\Support\Facades\Notification;
|
|
|
|
use App\Classes\FTN\Message;
|
|
use App\Models\{Echomail,Netmail,User};
|
|
use App\Notifications\Netmails\{EchoareaNotExist,EchoareaNotSubscribed,EchoareaNoWrite,NetmailForward,NetmailHubNoUser};
|
|
use App\Traits\ParseAddresses;
|
|
|
|
class MessageProcess implements ShouldQueue
|
|
{
|
|
private const LOGKEY = 'JMP';
|
|
|
|
use Dispatchable,InteractsWithQueue,Queueable,SerializesModels,ParseAddresses;
|
|
|
|
private Echomail|Netmail|string $mo;
|
|
private bool $skipbot;
|
|
|
|
/**
|
|
* Process a message from a packet
|
|
*
|
|
* @param Echomail|Netmail $mo The message object
|
|
* @param bool $skipbot Dont trigger bot actions
|
|
*/
|
|
public function __construct(Echomail|Netmail $mo,bool $skipbot=FALSE)
|
|
{
|
|
// @todo We need to serialize this model here, because laravel has an error unserializing it (Model Not Found)
|
|
$this->mo = utf8_encode(serialize($mo->withoutRelations()));
|
|
$this->skipbot = $skipbot;
|
|
}
|
|
|
|
public function __get($key): mixed
|
|
{
|
|
switch ($key) {
|
|
case 'jobname':
|
|
$mo = unserialize($this->mo);
|
|
return sprintf('%s-%s-%s',$mo->set->get('set_pkt'),$mo->set->get('set_sender')->ftn,$mo->msgid);
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* At this point, we know that the packet is from a system we know about, and the packet is to us:
|
|
* + From a system that is configured with us, and the password has been validated
|
|
* + From a system that is not configured with us, and it may have netmails for us
|
|
*/
|
|
public function handle()
|
|
{
|
|
$this->mo = unserialize(utf8_decode($this->mo));
|
|
|
|
// Load our details
|
|
$ftns = our_address();
|
|
|
|
// If we are a netmail
|
|
if ($this->mo instanceof Netmail) {
|
|
// @todo generate exception when netmail to system that doesnt exist (node/point) and its this host's responsibility
|
|
Log::info(sprintf('%s:- Processing Netmail [%s] to (%s) [%s] from (%s) [%s].',
|
|
self::LOGKEY,
|
|
$this->mo->msgid ?: '*NO MSGID*',
|
|
$this->mo->to,$this->mo->tftn->ftn,
|
|
$this->mo->from,$this->mo->fftn->ftn,
|
|
));
|
|
|
|
// @todo Enable checks to reject old messages
|
|
|
|
// Check for duplicate messages
|
|
|
|
// FTS-0009.001
|
|
if ($this->mo->msgid) {
|
|
Log::debug(sprintf('%s:- Checking for duplicate from host [%s].',self::LOGKEY,$this->mo->fftn->ftn));
|
|
|
|
$o = Netmail::where('msgid',$this->mo->msgid)
|
|
->where('fftn_id',$this->mo->fftn_id)
|
|
->where('datetime','>',Carbon::now()->subYears(3))
|
|
->single();
|
|
|
|
if ($o) {
|
|
Log::alert(sprintf('%s:! Duplicate netmail #%d [%s] from (%s) [%s] to (%s) - ignoring.',
|
|
self::LOGKEY,
|
|
$o->id,
|
|
$this->mo->msgid,
|
|
$this->mo->from,$this->mo->fftn->ftn,
|
|
$this->mo->to,
|
|
));
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
// @todo Enable checks to see if this is a file request or file send
|
|
|
|
// Strip any local/transit flags
|
|
$this->mo->flags &= ~(Message::FLAG_LOCAL|Message::FLAG_INTRANSIT);
|
|
|
|
// Determine if the message is to this system, or in transit
|
|
if ($ftns->contains($this->mo->tftn)) {
|
|
$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->mo)) {
|
|
$this->mo->flags |= Message::FLAG_RECD;
|
|
$this->mo->save();
|
|
|
|
Log::info(sprintf('%s:= Netmail [%s] from (%s:%s) - was processed by us internally [%d]',
|
|
self::LOGKEY,
|
|
$this->mo->msgid,
|
|
$this->mo->from,
|
|
$this->mo->fftn->ftn,
|
|
$this->mo->id,
|
|
));
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (! $processed) {
|
|
// Check if the netmail is to a user, with netmail forwarding enabled
|
|
$uo = User::active()
|
|
->where(function($query) {
|
|
return $query->whereRaw(sprintf("LOWER(name)='%s'",strtolower(utf8_encode($this->mo->to))))
|
|
->orWhereRaw(sprintf("LOWER(alias)='%s'",strtolower(utf8_encode($this->mo->to))));
|
|
})
|
|
->whereNotNull('system_id')
|
|
->single();
|
|
|
|
if ($uo && ($ao=$uo->system->match($this->mo->tftn->zone)?->pop())) {
|
|
Log::info(sprintf('%s:- Forwarding Netmail [%s] to (%s) [%s] from (%s) [%s].',
|
|
self::LOGKEY,
|
|
$this->mo->msgid ?: '*NO MSGID*',
|
|
$this->mo->to,$ao->ftn,
|
|
$this->mo->from,$this->mo->fftn->ftn,
|
|
));
|
|
|
|
$note = "+--[ FORWARDED MESSAGE ]----------------------------------+\r";
|
|
$note .= "+ This message has been forwarded to you, it was originally sent to you\r";
|
|
$note .= sprintf("+ at [%s]\r",$this->mo->tftn->ftn);
|
|
$note .= "+---------------------------------------------------------+\r\r";
|
|
|
|
$this->mo->msg_src = $note.$this->mo->content;
|
|
$this->mo->tftn_id = $ao->id;
|
|
$this->mo->flags |= Message::FLAG_INTRANSIT;
|
|
$this->mo->save();
|
|
|
|
$processed = TRUE;
|
|
|
|
// Dont send an advisement to an areabot
|
|
if (! in_array(strtolower($this->mo->from),config('fido.areabots')))
|
|
Notification::route('netmail',$this->mo->fftn)->notify(new NetmailForward($this->mo,$ao));
|
|
|
|
// We'll ignore messages from *fix users
|
|
} elseif (in_array(strtolower($this->mo->from),config('fido.areabots'))) {
|
|
$this->mo->flags |= Message::FLAG_RECD;
|
|
$this->mo->save();
|
|
|
|
Log::alert(sprintf('%s:! Ignoring Netmail [%s] to the Hub from (%s:%s) - its from a bot [%d]',
|
|
self::LOGKEY,
|
|
$this->mo->msgid,
|
|
$this->mo->from,
|
|
$this->mo->fftn->ftn,
|
|
$this->mo->id,
|
|
));
|
|
|
|
$processed = TRUE;
|
|
}
|
|
}
|
|
|
|
// If not processed, no users here!
|
|
if (! $processed) {
|
|
Log::alert(sprintf('%s:! Netmail to the Hub from (%s) [%s] but no users here.',self::LOGKEY,$this->mo->from,$this->mo->fftn->ftn));
|
|
|
|
Notification::route('netmail',$this->mo->fftn)->notify(new NetmailHubNoUser($this->mo));
|
|
}
|
|
|
|
// If in transit, store for collection
|
|
} else {
|
|
// @todo In transit loop checking
|
|
// @todo In transit TRACE response
|
|
|
|
$this->mo->flags |= Message::FLAG_INTRANSIT;
|
|
$this->mo->save();
|
|
|
|
Log::info(sprintf('%s:= Netmail [%s] in transit to (%s:%s) from (%s:%s) [%d].',
|
|
self::LOGKEY,
|
|
$this->mo->msgid,
|
|
$this->mo->to,$this->mo->tftn->ftn,
|
|
$this->mo->from,$this->mo->fftn->ftn,
|
|
$this->mo->id,
|
|
));
|
|
}
|
|
|
|
// Else we are echomail
|
|
} else {
|
|
// The packet sender
|
|
$sender = $this->mo->set->get('set_sender');
|
|
|
|
// @todo Check that this does evaluate to true if a message has been rescanned
|
|
$rescanned = $this->mo->kludges->get('RESCANNED',FALSE);
|
|
|
|
// Echoarea doesnt exist, cant import the message
|
|
if (! $this->mo->echoarea) {
|
|
Log::alert(sprintf('%s:! Echoarea [%s] doesnt exist for zone [%d@%s]',self::LOGKEY,$this->mo->set->get('set_echoarea'),$sender->zone->zone_id,$sender->zone->domain->name));
|
|
|
|
Notification::route('netmail',$sender)->notify(new EchoareaNotExist($this->mo));
|
|
return;
|
|
}
|
|
|
|
Log::debug(sprintf('%s:- Processing echomail [%s] in [%s] from [%s].',self::LOGKEY,$this->mo->msgid,$this->mo->echoarea->name,$sender->ftn));
|
|
|
|
// Message from zone is incorrect for echoarea
|
|
if (! $this->mo->echoarea->domain->zones->contains($this->mo->fftn->zone)) {
|
|
Log::alert(sprintf('%s:! The message [%s] is from a different zone [%d] than the packet sender [%d] - not importing',
|
|
self::LOGKEY,
|
|
$this->mo->msgid,
|
|
$this->mo->fftn->zone->zone_id,
|
|
$this->mo->fftn->zone->zone_id));
|
|
|
|
return;
|
|
}
|
|
|
|
// Check for duplicate messages
|
|
// FTS-0009.001
|
|
if ($this->mo->msgid) {
|
|
Log::debug(sprintf('%s:- Checking for duplicate from host id [%d], with msgid [%s] between [%s] and [%s].',
|
|
self::LOGKEY,
|
|
$this->mo->fftn_id,
|
|
$this->mo->msgid,
|
|
$this->mo->datetime->clone()->subYears(3),
|
|
$this->mo->datetime,
|
|
));
|
|
|
|
$x = Echomail::where('msgid',$this->mo->msgid)
|
|
->where('fftn_id',$this->mo->fftn_id)
|
|
->where('datetime','>=',$this->mo->datetime->clone()->subYears(3))
|
|
->where('datetime','<=',$this->mo->datetime);
|
|
|
|
if ($x->count()) {
|
|
// @todo Actually update seenby
|
|
Log::alert(sprintf('%s:! Duplicate echomail (%s) in [%s] from (%s) [%s] to (%s) - ignoring.',
|
|
self::LOGKEY,
|
|
$this->mo->msgid,
|
|
$this->mo->echoarea->name,
|
|
$this->mo->from,$this->mo->fftn->ftn,
|
|
$this->mo->to,
|
|
));
|
|
|
|
// @todo This duplicate message may have gone via a different path, be nice to record it.
|
|
// @todo if we have an export for any of the seenby addresses, remove it
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Find another message with the same msg_crc
|
|
if ($this->mo->msg_crc) {
|
|
$o = Echomail::where('msg_crc',$xx=md5($this->mo->msg_crc))
|
|
->where('fftn_id',$this->mo->fftn_id)
|
|
->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('|')
|
|
));
|
|
}
|
|
|
|
// Can the system send messages to this area?
|
|
if (! $this->mo->echoarea->can_write($sender->security)) {
|
|
Log::alert(sprintf('%s:! FTN [%s] is not allowed to post [%s] to [%s].',self::LOGKEY,$sender->ftn,$this->mo->msgid,$this->mo->echoarea->name));
|
|
if (! $rescanned)
|
|
Notification::route('netmail',$sender)->notify(new EchoareaNoWrite($this->mo));
|
|
|
|
return;
|
|
}
|
|
|
|
// If the node is not subscribed, we'll accept it, but let them know
|
|
if (! $sender->echoareas->contains($this->mo->echoarea)) {
|
|
Log::alert(sprintf('%s:! FTN [%s] is not subscribed to [%s] for [%s].',self::LOGKEY,$sender->ftn,$this->mo->echoarea->name,$this->mo->msgid));
|
|
|
|
if (! $rescanned)
|
|
Notification::route('netmail',$sender)->notify(new EchoareaNotSubscribed($this->mo));
|
|
}
|
|
|
|
// We know about this area, store it
|
|
$this->mo->save();
|
|
|
|
Log::info(sprintf('%s:= Echomail [%s] in [%s] from (%s) [%s] to (%s) - [%s].',
|
|
self::LOGKEY,
|
|
$this->mo->msgid,
|
|
$this->mo->echoarea->name,
|
|
$this->mo->from,$this->mo->fftn->ftn,
|
|
$this->mo->to,
|
|
$this->mo->id,
|
|
));
|
|
|
|
// If the message is to a bot, but not rescanned, or purposely skipbot set, we'll process it
|
|
if ((! $this->skipbot) && (! $rescanned))
|
|
foreach (config('process.echomail') as $class) {
|
|
if ($class::handle($this->mo)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |