Some message optimisation, added Echomail processing

This commit is contained in:
Deon George 2021-07-31 00:35:52 +10:00
parent 6f26bc4c71
commit d937547599
15 changed files with 476 additions and 134 deletions

View File

@ -23,6 +23,7 @@ class Message extends FTNBase
{ {
private const cast_utf8 = [ private const cast_utf8 = [
'message', 'message',
'message_src',
]; ];
// Single value kludge items // Single value kludge items
@ -30,10 +31,10 @@ class Message extends FTNBase
'chrs' => 'CHRS: ', 'chrs' => 'CHRS: ',
'charset' => 'CHARSET: ', 'charset' => 'CHARSET: ',
'codepage' => 'CODEPAGE: ', 'codepage' => 'CODEPAGE: ',
'mid' => 'MID: ',
'pid' => 'PID: ', 'pid' => 'PID: ',
'replyid' => 'REPLY: ', 'replyid' => 'REPLY: ',
'tid' => 'TID: ', 'tid' => 'TID: ',
'tzutc' => 'TZUTC: ',
]; ];
// Flags for messages // Flags for messages
@ -72,20 +73,29 @@ class Message extends FTNBase
private const SUBJECT_LEN = 71; // FTS-0001.016 Subject: upto 72 chars null terminated private const SUBJECT_LEN = 71; // FTS-0001.016 Subject: upto 72 chars null terminated
private const AREATAG_LEN = 35; // private const AREATAG_LEN = 35; //
private ?ValidatorResult $errors = NULL; // Packet validation private ?ValidatorResult $errors; // Packet validation
private array $header; // Message Header private array $header; // Message Header
private Collection $kludge; // Hold kludge items private Collection $kludge; // Hold kludge items
private string $user_from; // User message is From private string $user_from; // User message is From
private string $user_to; // User message is To private string $user_to; // User message is To
private string $subject; // Message subject private string $subject; // Message subject
private string $msgid; // MSG ID private string $msgid; // MSG ID
private string $reply; // Reply ID
private string $echoarea; // FTS-0004.001 private string $echoarea; // FTS-0004.001
private string $intl; // Netmail details private string $intl; // Netmail details
private string $message; // The actual message content
private string $message; // The parsed message content
private string $message_src; // The actual message part
private string $tagline;
private string $tearline; private string $tearline;
private string $origin; // FTS-0004.001 private string $origin; // FTS-0004.001
private int $tzutc;
private array $zone; // Zone the message belongs to. (src/dst - for netmail) private array $zone; // Zone the message belongs to. (src/dst - for netmail)
private array $point; // Point the message belongs to (Netmail) private array $point; // Point the message belongs to (Netmail)
@ -145,17 +155,26 @@ class Message extends FTNBase
$this->domain = $domain; $this->domain = $domain;
$this->kludge = collect(); $this->kludge = collect();
$this->msgid = '';
$this->reply = '';
$this->echoarea = '';
$this->intl = '';
$this->tearline = '';
$this->tagline = '';
$this->origin = '';
$this->tzutc = 0;
$this->zone = [];
$this->point = [];
$this->path = collect(); $this->path = collect();
$this->seenby = collect(); $this->seenby = collect();
$this->via = collect(); $this->via = collect();
$this->unknown = collect(); $this->unknown = collect();
$this->zone = [];
$this->point = [];
$this->tearline = '';
$this->origin = '';
$this->msgid = '';
$this->echoarea = '';
$this->intl = '';
} }
/** /**
@ -249,25 +268,35 @@ class Message extends FTNBase
case 'date': case 'date':
return Carbon::createFromFormat('d M y H:i:s O', return Carbon::createFromFormat('d M y H:i:s O',
sprintf('%s %s',chop(Arr::get($this->header,$key)),(! is_null($x=$this->kludge->get('tzutc')) && ($x < 0)) ? $x : '+'.($x ?: '0000'))); sprintf('%s %s%04d',chop(Arr::get($this->header,$key)),($this->tzutc < 0) ? '-' : '+',abs($this->tzutc)));
case 'flags': case 'flags':
case 'cost': case 'cost':
return Arr::get($this->header,$key); return Arr::get($this->header,$key);
case 'message': case 'tzutc':
case 'tearline':
case 'origin':
case 'subject':
case 'user_to': case 'user_to':
case 'user_from': case 'user_from':
case 'subject':
case 'echoarea':
case 'msgid':
case 'reply':
case 'message':
case 'message_src':
case 'tearline':
case 'tagline':
case 'origin':
case 'kludge': case 'kludge':
case 'path': case 'path':
case 'seenby': case 'seenby':
case 'via': case 'via':
case 'msgid':
case 'errors': case 'errors':
case 'echoarea':
return $this->{$key}; return $this->{$key};
default: default:
@ -278,16 +307,25 @@ class Message extends FTNBase
public function __set($key,$value) public function __set($key,$value)
{ {
switch ($key) { switch ($key) {
case 'echoarea': case 'flags':
case 'header': case 'header':
case 'intl': case 'tzutc':
case 'message':
case 'tearline':
case 'origin':
case 'msgid':
case 'subject':
case 'user_from': case 'user_from':
case 'user_to': case 'user_to':
case 'subject':
case 'msgid':
case 'reply':
case 'echoarea':
case 'intl':
case 'message':
case 'tagline':
case 'tearline':
case 'origin':
case 'via': case 'via':
$this->{$key} = $value; $this->{$key} = $value;
break; break;
@ -403,28 +441,46 @@ class Message extends FTNBase
$return .= $this->user_from."\00"; $return .= $this->user_from."\00";
$return .= $this->subject."\00"; $return .= $this->subject."\00";
if (! $this->isNetmail())
$return .= sprintf("AREA:%s\r",$this->echoarea);
// If the message is local, then our kludges are not in the msg itself, we'll add them
if ($this->isFlagSet(self::FLAG_LOCAL)) {
if ($this->isNetmail()) if ($this->isNetmail())
$return .= sprintf("\01INTL %s\r",$this->intl); $return .= sprintf("\01INTL %s\r",$this->intl);
else
$return .= "AREA:".$this->echoarea."\r"; $return .= sprintf("\01TZUTC: %s\r",str_replace('+','',$this->date->getOffsetString('')));
// Add some kludges // Add some kludges
$return .= sprintf("\01MSGID: %s\r",$this->msgid); $return .= sprintf("\01MSGID: %s\r",$this->msgid);
if ($this->reply)
$return .= sprintf("\01REPLY: %s\r",$this->reply);
foreach ($this->_kludge as $k=>$v) { foreach ($this->_kludge as $k=>$v) {
if ($x=$this->kludge->get($k)) if ($x=$this->kludge->get($k))
$return .= sprintf("\01%s%s\r",$v,$x); $return .= sprintf("\01%s%s\r",$v,$x);
} }
$return .= $this->message."\r"; $return .= $this->message."\r";
if ($this->tagline)
$return .= sprintf("... %s\r",$this->tagline);
if ($this->tearline) if ($this->tearline)
$return .= $this->tearline."\r"; $return .= sprintf("--- %s\r",$this->tearline);
if ($this->origin) if ($this->origin)
$return .= $this->origin."\r"; $return .= sprintf(" * Origin: %s\r",$this->origin);
} else {
dump([__METHOD__=>'NOT LOCAL']);
$return .= $this->message."\r";
}
if ($this->isNetmail()) { if ($this->isNetmail()) {
foreach ($this->via as $v) foreach ($this->via as $v)
$return .= sprintf("\01Via %s\r",$v); $return .= sprintf("\01Via %s\r",$v);
} else {
// @todo Add echomail SEEN-BY and PATH
} }
$return .= "\00"; $return .= "\00";
@ -543,14 +599,17 @@ class Message extends FTNBase
$message = preg_replace("/\n\r/","\r",$message); $message = preg_replace("/\n\r/","\r",$message);
// Split out the <SOH> lines // Split out the <SOH> lines
$result = collect(explode("\01",$message))->filter(); $result = collect(explode("\x01",$message))->filter();
$this->message = ''; $this->message = '';
$this->message_src = '';
$srcpos = 0;
foreach ($result as $v) { foreach ($result as $v) {
// Search for \r - if that is the end of the line, then its a kludge // Search for \r - if that is the end of the line, then its a kludge
$x = strpos($v,"\r"); $x = strpos($v,"\r");
$t = ''; $t = '';
$srcpos += 1+$x+1; // SOH+text+\r
// If there are more characters, then put the kludge back into the result, so that we process it. // If there are more characters, then put the kludge back into the result, so that we process it.
if ($x != strlen($v)-1) { if ($x != strlen($v)-1) {
@ -559,6 +618,10 @@ class Message extends FTNBase
$this->message .= substr($v,$x+1,$y-$x-1); $this->message .= substr($v,$x+1,$y-$x-1);
$this->parseOrigin(substr($v,$y)); $this->parseOrigin(substr($v,$y));
// Capture the raw message, in case we send it on
// length = src, remove current 1+$x+1, add soh, $y + origin_start + origin_length + 0d
$this->message_src .= substr($message,0,$srcpos-(1+$x+1)+1+$y+12+strlen($this->origin)+1);
// If this is netmail, the FQFA will have been set by the INTL line, we can skip the rest of this // If this is netmail, the FQFA will have been set by the INTL line, we can skip the rest of this
$matches = []; $matches = [];
@ -573,8 +636,9 @@ class Message extends FTNBase
$ftn = Address::parseFTN($matches[1]); $ftn = Address::parseFTN($matches[1]);
// We'll double check our FTN // We'll double check our FTN
if (($ftn['n'] !== $this->fn) || ($ftn['f'] !== $this->ff)) if ($this->isNetmail() && ($ftn['n'] !== $this->fn) || ($ftn['f'] !== $this->ff)) {
Log::error(sprintf('FTN [%s] doesnt match message header',$matches[1]),['ftn'=>$ftn]); Log::error(sprintf('FTN [%s] doesnt match message header',$matches[1]),['ftn'=>$ftn,'fn'=>$this->fn,'ff'=>$this->ff]);
}
// http://ftsc.org/docs/fsc-0068.001 // http://ftsc.org/docs/fsc-0068.001
// MSGID should be the basis of the source // MSGID should be the basis of the source
@ -584,6 +648,7 @@ class Message extends FTNBase
// The message is the rest? // The message is the rest?
} elseif (strlen($v) > $x+1) { } elseif (strlen($v) > $x+1) {
$this->message .= substr($v,$x+1); $this->message .= substr($v,$x+1);
$this->message_src .= substr($v,$x+1);
} }
$v = substr($v,0,$x+1); $v = substr($v,0,$x+1);
@ -636,6 +701,9 @@ class Message extends FTNBase
} }
} }
elseif ($t = $this->kludge('TZUTC: ',$v))
$this->tzutc = $t;
elseif ($t = $this->kludge('MSGID: ',$v)) elseif ($t = $this->kludge('MSGID: ',$v))
$this->msgid = $t; $this->msgid = $t;

View File

@ -157,6 +157,10 @@ class Packet extends FTNBase
$message = ''; $message = '';
} }
// If our message is still set, then we have an unprocessed message
if ($message)
$o->parseMessage($message,$domain);
return $o; return $o;
} }
@ -300,7 +304,7 @@ class Packet extends FTNBase
* *
* @param Message $o * @param Message $o
*/ */
public function addNetmail(Message $o): void public function addMail(Message $o): void
{ {
$this->messages->push($o); $this->messages->push($o);
} }
@ -354,7 +358,7 @@ class Packet extends FTNBase
Log::error(sprintf('%s:%s Skipping...',self::LOGKEY,join('|',$msg->errors->messages()->get('from')))); Log::error(sprintf('%s:%s Skipping...',self::LOGKEY,join('|',$msg->errors->messages()->get('from'))));
} else { } else {
$this->messages->push(Message::parseMessage($message,$domain)); $this->messages->push($msg);
} }
} }
} }

View File

@ -28,6 +28,7 @@ final class Ping extends Process
return FALSE; return FALSE;
Log::info(sprintf('Processing PING message from (%s) [%s]',$msg->user_from,$msg->fftn)); Log::info(sprintf('Processing PING message from (%s) [%s]',$msg->user_from,$msg->fftn));
$ftns = Setup::findOrFail(config('app.id'))->system->match($msg->fftn_o->zone);
$reply = sprintf("Your ping was received here on %s and it looks like you sent it on %s. If that is correct, then it took %s to get here.\r", $reply = sprintf("Your ping was received here on %s and it looks like you sent it on %s. If that is correct, then it took %s to get here.\r",
$msg->date->toDateTimeString(), $msg->date->toDateTimeString(),
@ -45,13 +46,18 @@ final class Ping extends Process
$o->to = $msg->user_from; $o->to = $msg->user_from;
$o->from = Setup::PRODUCT_NAME; $o->from = Setup::PRODUCT_NAME;
$o->subject = 'Ping Reply'; $o->subject = 'Ping Reply';
$o->fftn_id = ($x=$msg->tftn_o) ? $x->id : NULL; $o->datetime = Carbon::now();
$o->tftn_id = ($x=$msg->fftn_o) ? $x->id : NULL; $o->tzoffset = $o->datetime->utcOffset();
$o->msg = static::format_msg($reply,self::$logo);
$o->reply = $msg->msgid;
$o->reply = $msg->msgid;
$o->fftn_id = $ftns->id;
$o->tftn_id = ($x=$msg->fftn_o) ? $x->id : NULL;
$o->flags = Message::FLAG_LOCAL;
$o->cost = 0;
$o->msg = static::format_msg($reply,self::$logo);
$o->tagline = 'My ping pong opponent was not happy with my serve. He kept returning it.'; $o->tagline = 'My ping pong opponent was not happy with my serve. He kept returning it.';
$o->tearline = sprintf('--- %s (%s)',Setup::PRODUCT_NAME,(new Setup)->version); $o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
$o->save(); $o->save();
return TRUE; return TRUE;

View File

@ -0,0 +1,77 @@
<?php
namespace App\Classes\FTN\Process;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Support\Facades\Log;
use App\Classes\FTN\{Message,Process};
use App\Models\{Echomail,Setup};
/**
* Process messages to Test
*
* @package App\Classes\FTN\Process
*/
final class Test extends Process
{
private static array $logo = [
'Ú¿ÚÄ¿ÚÄ¿Ú¿',
' ³ ³ÄÙÀÄ¿ ³ ',
' Á ÀÄÙÀÄÙ Á '
];
private const testing = ['test','testing'];
public static function handle(Message $msg): bool
{
if ((strtolower($msg->user_to) !== 'all') || ! in_array(strtolower($msg->subject),self::testing))
return FALSE;
Log::info(sprintf('Processing TEST message from (%s) [%s]',$msg->user_from,$msg->fftn));
$ftns = Setup::findOrFail(config('app.id'))->system->match($msg->fftn_o->zone);
$reply = sprintf("Your test was received here on %s and it looks like you sent it on %s. If that is correct, then it took %s to get here.\r",
$msg->date->toDateTimeString(),
Carbon::now()->toDateTimeString(),
$msg->date->diffForHumans(['parts'=>3,'syntax'=>CarbonInterface::DIFF_ABSOLUTE])
);
$reply .= "\r";
$reply .= "\r";
$reply .= "------------------------------ BEING MESSAGE ------------------------------\r";
$reply .= sprintf("TO: %s\r",$msg->user_to);
$reply .= sprintf("SUBJECT: %s\r",$msg->subject);
$reply .= $msg->message."\r";
$reply .= "------------------------------ CONTROL LINES ------------------------------\r";
$reply .= sprintf("DATE: %s\r",$msg->date->format('Y-m-d H:i:s'));
$reply .= sprintf("MSGID: %s\r",$msg->msgid);
foreach ($msg->kludge as $k=>$v)
$reply .= sprintf("@%s: %s\n",strtoupper($k),$v);
foreach ($msg->via as $via)
$reply .= sprintf("VIA: %s\n",$via);
$reply .= "------------------------------ END MESSAGE ------------------------------\r";
$o = new Echomail;
$o->to = $msg->user_from;
$o->from = Setup::PRODUCT_NAME;
$o->subject = 'Test Reply';
$o->datetime = Carbon::now();
$o->tzoffset = $o->datetime->utcOffset();
$o->echoarea = $msg->echoarea;
$o->reply = $msg->msgid;
$o->fftn_id = $ftns->id;
$o->flags = Message::FLAG_LOCAL;
$o->msg = static::format_msg($reply,self::$logo);
$o->tagline = 'I ate a clock yesterday, it was very time-consuming.';
$o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
$o->origin = sprintf('%s (%s)',Setup::PRODUCT_NAME,$ftns->ftn4d);
$o->save();
return TRUE;
}
}

View File

@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\Exception\FileException; use Symfony\Component\HttpFoundation\File\Exception\FileException;
use App\Classes\FTN\InvalidPacketException;
use App\Classes\FTN\Packet; use App\Classes\FTN\Packet;
use App\Jobs\ProcessPacket; use App\Jobs\ProcessPacket;
use App\Models\Address; use App\Models\Address;
@ -83,7 +84,7 @@ final class Receive extends Item
if (! $this->f) if (! $this->f)
throw new Exception('No file to close'); throw new Exception('No file to close');
if (! $this->file_pos != $this->receiving->file_size) if ($this->file_pos != $this->receiving->file_size)
Log::warning(sprintf('%s: - Closing [%s], but missing [%d] bytes',__METHOD__,$this->receiving->file_name,$this->receiving->file_size-$this->file_pos)); Log::warning(sprintf('%s: - Closing [%s], but missing [%d] bytes',__METHOD__,$this->receiving->file_name,$this->receiving->file_size-$this->file_pos));
$this->receiving->received = TRUE; $this->receiving->received = TRUE;
@ -100,7 +101,15 @@ final class Receive extends Item
case self::IS_PKT: case self::IS_PKT:
Log::info(sprintf('%s: - Processing mail packet [%s]',__METHOD__,$this->file)); Log::info(sprintf('%s: - Processing mail packet [%s]',__METHOD__,$this->file));
try {
$po = Packet::open(new File($this->file),$this->ao->zone->domain); $po = Packet::open(new File($this->file),$this->ao->zone->domain);
} catch (InvalidPacketException $e) {
Log::error(sprintf('%s: - Not deleting packet [%s], as it generated an exception',__METHOD__,$this->file));
break;
}
foreach ($po->messages as $msg) { foreach ($po->messages as $msg) {
Log::info(sprintf('%s: - Mail from [%s] to [%s]',__METHOD__,$msg->fftn,$msg->tftn)); Log::info(sprintf('%s: - Mail from [%s] to [%s]',__METHOD__,$msg->fftn,$msg->tftn));

11
app/Interfaces/Packet.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace App\Interfaces;
use App\Classes\FTN\Message;
use App\Models\Address;
interface Packet
{
public function Packet(Address $ao): Message;
}

View File

@ -10,7 +10,7 @@ use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Classes\FTN\{Message,Process}; use App\Classes\FTN\{Message,Process};
use App\Models\{Netmail,Setup}; use App\Models\{Echomail,Netmail,Setup};
class ProcessPacket implements ShouldQueue class ProcessPacket implements ShouldQueue
{ {
@ -86,13 +86,19 @@ class ProcessPacket implements ShouldQueue
$o->to = $this->msg->user_from; $o->to = $this->msg->user_from;
$o->from = Setup::PRODUCT_NAME; $o->from = Setup::PRODUCT_NAME;
$o->subject = 'Message Undeliverable - '.$this->msg->msgid; $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->fftn_id = ($x=$this->msg->tftn_o) ? $x->id : NULL;
$o->tftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL; $o->tftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL;
$o->msg = Process::format_msg($reply,$reject);
$o->reply = $this->msg->msgid; $o->reply = $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->tagline = 'Do you think it was fate which brought us together? Nah, bad luck :(';
$o->tearline = sprintf('--- %s (%s)',Setup::PRODUCT_NAME,(new Setup)->version); $o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
$o->save(); $o->save();
} }
@ -108,32 +114,62 @@ class ProcessPacket implements ShouldQueue
// @todo In transit loop checking // @todo In transit loop checking
// @todo In transit TRACE response // @todo In transit TRACE response
$o = new Netmail(); $o = new Netmail;
$o->to = $this->msg->user_to; $o->to = $this->msg->user_to;
$o->from = $this->msg->user_from; $o->from = $this->msg->user_from;
$o->subject = $this->msg->subject; $o->subject = $this->msg->subject;
$o->fftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL; $o->datetime = $this->msg->date;
$o->tftn_id = ($x=$this->msg->tftn_o) ? $x->id : NULL; $o->tzoffset = $this->msg->date->utcOffset();
$o->msg = $this->msg->message;
$o->tearline = $this->msg->tearline;
$o->origin = $this->msg->origin;
$o->kluge = json_encode($this->msg->kludge);
$o->flags = $this->msg->flags; $o->flags = $this->msg->flags;
$o->cost = $this->msg->cost; $o->cost = $this->msg->cost;
$o->msgid = $this->msg->msgid;
$o->fftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL;
$o->tftn_id = ($x=$this->msg->tftn_o) ? $x->id : NULL;
$o->msg = $this->msg->message_src;
$o->save(); $o->save();
} }
// Else we are echomail // Else we are echomail
} else { } else {
dump('echomail'); Log::info(sprintf('Echomail [%s] in [%s] from (%s) [%s] to (%s).',
// Determine if we know about this echo area $this->msg->msgid,
// Can the sender create it if it doesnt exist? $this->msg->echoarea,
// Create it, or $this->msg->user_to,$this->msg->tftn,
$this->msg->user_from,
));
// Else record in bad area // @todo Determine if we know about this echo area
// @todo Can the sender create it if it doesnt exist?
// - Create it, or
// - Else record in bad area
// We know about this area, store it // We know about this area, store it
$o = new Echomail;
$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->fftn_o) ? $x->id : NULL;
$o->echoarea = $this->msg->echoarea;
$o->msgid = $this->msg->msgid;
$o->msg = $this->msg->message_src;
// @todo Record Path
// @todo Record SeenBy
$o->save();
// If the message is to a bot, we'll process it
foreach (config('process.echomail') as $class) {
if ($class::handle($this->msg)) {
break;
}
}
} }
} }
} }

View File

@ -4,6 +4,7 @@ namespace App\Models;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@ -151,6 +152,26 @@ class Address extends Model
return ($o && $o->system->active) ? $o : NULL; return ($o && $o->system->active) ? $o : NULL;
} }
/**
* Get echomail for this node
*
* @return Packet|null
*/
public function getEchomail(): ?Packet
{
if (($x=Echomail::select('*') //where('tftn_id',$this->id)
->where(function($q) {
return $q->whereNull('sent')
->orWhere('sent',FALSE);
}))
->count())
{
return $this->getPacket($x->get());
}
return NULL;
}
/** /**
* Get netmail for this node (including it's children) * Get netmail for this node (including it's children)
* *
@ -164,11 +185,25 @@ class Address extends Model
->orWhere('sent',FALSE); ->orWhere('sent',FALSE);
})) }))
->count()) ->count())
{
return $this->getPacket($x->get());
}
return NULL;
}
/**
* Return a packet of mail
*
* @param Collection $c
* @return Packet
*/
private function getPacket(Collection $c): Packet
{ {
$o = new Packet($this); $o = new Packet($this);
foreach ($x->get() as $oo) { foreach ($c as $oo) {
$o->addNetmail($oo->packet()); $o->addMail($oo->packet($this));
$oo->packet = $o->name; $oo->packet = $o->name;
$oo->sent = TRUE; $oo->sent = TRUE;
@ -179,9 +214,6 @@ class Address extends Model
return $o; return $o;
} }
return NULL;
}
/** /**
* Parse a string and split it out as an FTN array * Parse a string and split it out as an FTN array
* *

View File

@ -2,25 +2,77 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Carbon\Exceptions\Exception;
use Jenssegers\Mongodb\Eloquent\Model;
use Jenssegers\Mongodb\Eloquent\SoftDeletes;
class Echomail extends Model use App\Classes\FTN\Message;
use App\Interfaces\Packet;
use App\Traits\{MsgID,UseMongo};
class Echomail extends Model implements Packet
{ {
protected $dates = ['date']; use SoftDeletes,MsgID,UseMongo;
protected $fillable = ['date','msgid','from_ftn'];
public function kludges() protected $dates = ['datetime'];
/* RELATIONS */
public function fftn()
{ {
return $this->belongsToMany(Kludge::class); return $this
->setConnection('pgsql')
->belongsTo(Address::class)
->withTrashed();
} }
public function seenbys() /* METHODS */
{
return $this->belongsToMany(Seenby::class,NULL,NULL,'node_id');
}
public function paths() /**
* Return this model as a packet
*/
public function packet(Address $ao): Message
{ {
return $this->belongsToMany(Path::class,NULL,NULL,'node_id'); // @todo Dont bundle mail to nodes that have been disabled, or addresses that have been deleted
$o = new Message;
$o->header = [
'onode' => $this->fftn->node_id,
'dnode' => $ao->node_id,
'onet' => $this->fftn->host_id,
'dnet' => $ao->host_id,
'flags' => 0, // @todo?
'cost' => 0,
'date'=>$this->datetime->format('d M y H:i:s'),
];
$o->tzutc = $this->datetime->utcOffset($this->tzoffset)->getOffsetString('');
$o->user_to = $this->to;
$o->user_from = $this->from;
$o->subject = $this->subject;
$o->echoarea = $this->echoarea;
$o->flags = $this->flags;
$o->kludge->put('mid',$this->id);
$o->msgid = $this->msgid;
if ($this->reply)
$o->reply = $this->reply;
$o->message = $this->msg;
if ($this->tagline)
$o->tagline = $this->tagline;
if ($this->tearline)
$o->tearline = $this->tearline;
if ($this->origin)
$o->origin = $this->origin;
// @todo SEENBY
// @todo PATH
return $o;
} }
} }

View File

@ -7,26 +7,15 @@ use Jenssegers\Mongodb\Eloquent\Model;
use Jenssegers\Mongodb\Eloquent\SoftDeletes; use Jenssegers\Mongodb\Eloquent\SoftDeletes;
use App\Classes\FTN\Message; use App\Classes\FTN\Message;
use App\Interfaces\Packet;
use App\Traits\UseMongo;
class Netmail extends Model class Netmail extends Model implements Packet
{ {
use SoftDeletes; use SoftDeletes,UseMongo;
//protected $connection = 'mongodb';
protected $dates = ['datetime','sent_at']; protected $dates = ['datetime','sent_at'];
/**
* Resolve a connection instance.
* We need to do this, because our relations are in pgsql and somehow loading a relation changes this models
* connection information. Using protected $connection is not enough.
*
* @param string|null $connection
*/
public static function resolveConnection($connection = null)
{
return static::$resolver->connection('mongodb');
}
/* RELATIONS */ /* RELATIONS */
public function fftn() public function fftn()
@ -44,49 +33,47 @@ class Netmail extends Model
->belongsTo(Address::class); ->belongsTo(Address::class);
} }
/* ATTRIBUTES */
public function getMsgAttribute($value): string
{
return utf8_decode($value);
}
public function setMsgAttribute($value): void
{
$this->attributes['msg'] = utf8_encode($value);
}
/* METHODS */ /* METHODS */
/** /**
* Return this model as a packet * Return this model as a packet
*/ */
public function packet(): Message public function packet(Address $ao): Message
{ {
$o = new Message;
// @todo Dont bundle mail to nodes that have been disabled, or addresses that have been deleted // @todo Dont bundle mail to nodes that have been disabled, or addresses that have been deleted
$o = new Message;
$o->header = [ $o->header = [
'onode' => $this->fftn->node_id, 'onode' => $this->fftn->node_id,
'dnode' => $this->tftn->node_id, 'dnode' => $ao->node_id,
'onet' => $this->fftn->host_id, 'onet' => $this->fftn->host_id,
'dnet' => $this->tftn->host_id, 'dnet' => $ao->host_id,
'flags' => 0, // @todo? 'flags' => 0, // @todo?
'cost' => 0, 'cost' => 0,
'date'=>$this->created_at->format('d M y H:i:s'), 'date'=>$this->datetime->format('d M y H:i:s'),
]; ];
$o->tzutc = $this->datetime->utcOffset($this->tzoffset)->getOffsetString('');
$o->user_to = $this->to; $o->user_to = $this->to;
$o->user_from = $this->from; $o->user_from = $this->from;
$o->subject = $this->subject; $o->subject = $this->subject;
$o->message = $this->msg;
if ($this->tagline)
$o->message .= "\r... ".$this->tagline."\r";
$o->tearline .= $this->tearline; // INTL kludge
// @todo Point handling FMPT/TOPT
$o->intl = sprintf('%s %s',$this->tftn->ftn3d,$this->fftn->ftn3d);
$o->flags = $this->flags;
$o->msgid = sprintf('%s %08x',$this->fftn->ftn3d,crc32($this->id)); $o->msgid = sprintf('%s %08x',$this->fftn->ftn3d,crc32($this->id));
if ($this->reply)
$o->reply = $this->reply;
$o->message = $this->msg;
if ($this->tagline)
$o->message .= $this->tagline;
if ($this->tearline)
$o->tearline .= $this->tearline;
// VIA kludge // VIA kludge
$via = $this->via ?: collect(); $via = $this->via ?: collect();
@ -103,12 +90,6 @@ class Netmail extends Model
$o->via = $via; $o->via = $via;
// INTL kludge
// @todo Point handling FMPT/TOPT
$o->intl = sprintf('%s %s',$this->tftn->ftn3d,$this->fftn->ftn3d);
// TZUTC
$o->kludge->put('tzutc',str_replace('+','',$this->created_at->getOffsetString('')));
return $o; return $o;
} }

25
app/Traits/MsgID.php Normal file
View File

@ -0,0 +1,25 @@
<?php
/**
* Add MsgID to new models
*/
namespace App\Traits;
use Illuminate\Support\Arr;
use App\Models\Setup;
trait MsgID
{
public function save(array $options = [])
{
if (! $this->exists) {
$ftns = Setup::findOrFail(config('app.id'))->system->match($this->fftn->zone);
if (is_null(Arr::get($this->attributes,'msgid')))
$this->attributes['msgid'] = sprintf('%s %08x',$ftns->ftn4d,timew());
}
return parent::save($options);
}
}

33
app/Traits/UseMongo.php Normal file
View File

@ -0,0 +1,33 @@
<?php
/**
* Models that store data in Mongo
*/
namespace App\Traits;
trait UseMongo
{
/**
* Resolve a connection instance.
* We need to do this, because our relations are in pgsql and somehow loading a relation changes this models
* connection information. Using protected $connection is not enough.
*
* @param string|null $connection
*/
public static function resolveConnection($connection = null)
{
return static::$resolver->connection('mongodb');
}
/* ATTRIBUTES */
public function getMsgAttribute($value): string
{
return utf8_decode($value);
}
public function setMsgAttribute($value): void
{
$this->attributes['msg'] = utf8_encode($value);
}
}

View File

@ -8,6 +8,8 @@
"php": "^8.0", "php": "^8.0",
"ext-pcntl": "*", "ext-pcntl": "*",
"ext-sockets": "*", "ext-sockets": "*",
"ext-zlib": "*",
"ext-zip": "*",
"eduardokum/laravel-mail-auto-embed": "^1.0", "eduardokum/laravel-mail-auto-embed": "^1.0",
"fideloper/proxy": "^4.4", "fideloper/proxy": "^4.4",
"fruitcake/laravel-cors": "^2.0", "fruitcake/laravel-cors": "^2.0",

View File

@ -1,6 +1,12 @@
<?php <?php
return [ return [
// Echmail
'echomail' => [
\App\Classes\FTN\Process\Test::class,
],
// Netmail
'robots' => [ 'robots' => [
\App\Classes\FTN\Process\Ping::class, \App\Classes\FTN\Process\Ping::class,
], ],

View File

@ -104,7 +104,7 @@
<div class="row pb-2"> <div class="row pb-2">
<div class="col-8"> <div class="col-8">
<div class="pad pb-0"> <div class="pad pb-0">
<pre class="highlight">{!! \App\Classes\FTN\Message::tr($msg->message) !!}</pre> <pre class="highlight">{!! \App\Classes\FTN\Message::tr($msg->message).sprintf("\r * Origin: %s",$msg->origin) !!}</pre>
</div> </div>
</div> </div>
</div> </div>