251 lines
6.3 KiB
PHP
251 lines
6.3 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace App\Classes;
|
||
|
|
||
|
use App\Exceptions\InvalidFidoPacketException;
|
||
|
|
||
|
class FTNMessage extends FTN
|
||
|
{
|
||
|
private $src = NULL;
|
||
|
private $dst = NULL;
|
||
|
private $flags = NULL;
|
||
|
private $cost = 0;
|
||
|
|
||
|
private $from = NULL; // FTS-0001.016 From Name: upto 36 chars null terminated
|
||
|
private $to = NULL; // FTS-0001.016 To Name: upto 36 chars null terminated
|
||
|
private $subject = NULL; // FTS-0001.016 Subject: upto 72 chars null terminated
|
||
|
private $date = NULL; // FTS-0001.016 Date: upto 20 chars null terminated
|
||
|
|
||
|
private $message = NULL; // The actual message content
|
||
|
private $echoarea = NULL; // FTS-0004.001
|
||
|
private $intl = NULL;
|
||
|
private $msgid = NULL;
|
||
|
private $reply = NULL; // Message thread reply source
|
||
|
private $origin = NULL; // FTS-0004.001
|
||
|
|
||
|
private $kludge = []; // Hold kludge items
|
||
|
private $path = []; // FTS-0004.001
|
||
|
private $seenby = []; // FTS-0004.001
|
||
|
private $via = [];
|
||
|
private $_other = [];
|
||
|
private $unknown = [];
|
||
|
|
||
|
private $fqfa = NULL; // Fully qualified fidonet source where packet originated
|
||
|
private $fqfd = NULL; // Fully qualified fidonet destination address (Netmail)
|
||
|
|
||
|
// Single value kludge items
|
||
|
private $_kludge = [
|
||
|
'chrs' => 'CHRS: ',
|
||
|
'charset' => 'CHARSET: ',
|
||
|
'codepage' => 'CODEPAGE: ',
|
||
|
'pid' => 'PID: ',
|
||
|
'tid' => 'TID: ',
|
||
|
];
|
||
|
|
||
|
public function __construct(string $header)
|
||
|
{
|
||
|
// Initialise vars
|
||
|
$this->kludge = collect(); // The message kludge lines
|
||
|
$this->path = collect(); // The message PATH lines
|
||
|
$this->seenby = collect(); // The message SEEN-BY lines
|
||
|
$this->via = collect(); // The path the message has gone using Via lines
|
||
|
$this->_other = collect(); // Temporarily hold attributes we dont process yet.
|
||
|
$this->unknown = collect(); // Temporarily hold attributes we have no logic for.
|
||
|
|
||
|
// FTS-0001.016 Message header 12 bytes
|
||
|
// node, net, flags, cost
|
||
|
$struct = [
|
||
|
'onode'=>[0x00,'v',2],
|
||
|
'dnode'=>[0x02,'v',2],
|
||
|
'onet'=>[0x04,'v',2],
|
||
|
'dnet'=>[0x06,'v',2],
|
||
|
'flags'=>[0x08,'v',2],
|
||
|
'cost'=>[0x0a,'v',2],
|
||
|
];
|
||
|
|
||
|
$result = unpack($this->unpackheader($struct),$header);
|
||
|
|
||
|
$this->src = sprintf('%s/%s',array_get($result,'onet'),array_get($result,'onode'));
|
||
|
$this->dst = sprintf('%s/%s',array_get($result,'dnet'),array_get($result,'dnode'));
|
||
|
$this->flags = array_get($result,'flags');
|
||
|
$this->cost = array_get($result,'cost');
|
||
|
}
|
||
|
|
||
|
public function __get($k)
|
||
|
{
|
||
|
return $this->{$k};
|
||
|
}
|
||
|
|
||
|
public function __set($k,$v)
|
||
|
{
|
||
|
switch ($k)
|
||
|
{
|
||
|
case 'message':
|
||
|
// Remove DOS \n\r
|
||
|
$v = preg_replace("/\n\r/","\r",$v);
|
||
|
|
||
|
$this->parsemessage($v);
|
||
|
break;
|
||
|
|
||
|
case 'origin':
|
||
|
$this->parseorigin($v);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
$this->{$k} = $v;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function parsemessage(string $message)
|
||
|
{
|
||
|
// Split out the <SOH> lines
|
||
|
$result = collect(explode("\01",$message))->filter();
|
||
|
|
||
|
foreach ($result as $k => $v)
|
||
|
{
|
||
|
// Search for \r - if that is the end of the line, then its a kludge
|
||
|
$x = strpos($v,"\r");
|
||
|
|
||
|
// If there are more characters, then put the kludge back into the result, so that we process it.
|
||
|
if ($x != strlen($v)-1)
|
||
|
{
|
||
|
/**
|
||
|
* Anything after the origin line is also kludge data.
|
||
|
*/
|
||
|
if ($y = strpos($v,"\r * Origin: "))
|
||
|
{
|
||
|
$this->message .= substr($v,$x+1,$y-$x-1);
|
||
|
$this->__set('origin',substr($v,$y));
|
||
|
$matches = [];
|
||
|
|
||
|
preg_match('/^.*\((.*)\)$/',$this->origin,$matches);
|
||
|
|
||
|
if (($this->type() == 'Netmail' AND array_get($matches,1) != $this->fqfa) OR ! array_get($matches,1))
|
||
|
throw new InvalidFidoPacketException(sprintf('Source address mismatch? [%s,%s]',$this->fqfa,array_get($matches,1)));
|
||
|
|
||
|
$this->fqfa = array_get($matches,1);
|
||
|
}
|
||
|
|
||
|
$v = substr($v,0,$x+1);
|
||
|
}
|
||
|
|
||
|
foreach ($this->_kludge as $a => $b) {
|
||
|
if ($t = $this->kludge($b, $v)) {
|
||
|
$this->kludge->put($a,$t);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($t)
|
||
|
continue;
|
||
|
|
||
|
if ($t = $this->kludge('AREA:',$v))
|
||
|
$this->echoarea = $t;
|
||
|
|
||
|
// From point: <SOH>"FMPT <point number><CR>
|
||
|
elseif ($t = $this->kludge('FMPT ',$v))
|
||
|
$this->_other->push($t);
|
||
|
|
||
|
/*
|
||
|
* The INTL control paragraph shall be used to give information about
|
||
|
* the zone numbers of the original sender and the ultimate addressee
|
||
|
* of a message.
|
||
|
*
|
||
|
* <SOH>"INTL "<destination address>" "<origin address><CR>
|
||
|
*/
|
||
|
elseif ($t = $this->kludge('INTL ',$v))
|
||
|
{
|
||
|
$this->intl = $t;
|
||
|
list($this->fqfd,$this->fqfa) = explode(' ',$t);
|
||
|
}
|
||
|
|
||
|
elseif ($t = $this->kludge('MSGID: ',$v))
|
||
|
$this->msgid = $t;
|
||
|
|
||
|
elseif ($t = $this->kludge('PATH: ',$v))
|
||
|
$this->path->push($t);
|
||
|
|
||
|
elseif ($t = $this->kludge('REPLY: ',$v))
|
||
|
$this->reply = $t;
|
||
|
|
||
|
// To Point: <SOH>TOPT <point number><CR>
|
||
|
elseif ($t = $this->kludge('TOPT ',$v))
|
||
|
$this->_other->push($t);
|
||
|
|
||
|
// Time Zone of the sender.
|
||
|
elseif ($t = $this->kludge('TZUTC: ',$v))
|
||
|
$this->tzutc= $t;
|
||
|
|
||
|
// <SOH>Via <FTN Address> @YYYYMMDD.HHMMSS[.Precise][.Time Zone] <Program Name> <Version> [Serial Number]<CR>
|
||
|
elseif ($t = $this->kludge('Via ',$v))
|
||
|
$this->via->push($t);
|
||
|
|
||
|
// We got a kludge line we dont know about
|
||
|
else {
|
||
|
$this->unknown->push(chop($v,"\r"));
|
||
|
|
||
|
//dd(['v'=>$v,'t'=>$t]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Process the data after the ORIGIN
|
||
|
* There may be kludge lines after the origin - notably SEEN-BY
|
||
|
*
|
||
|
* @param string $message
|
||
|
*/
|
||
|
public function parseorigin(string $message)
|
||
|
{
|
||
|
// Split out each line
|
||
|
$result = collect(explode("\r",$message))->filter();
|
||
|
|
||
|
foreach ($result as $k => $v) {
|
||
|
|
||
|
foreach ($this->_kludge as $a => $b) {
|
||
|
if ($t = $this->kludge($b, $v)) {
|
||
|
$this->kludge->put($a, $t);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($t = $this->kludge('SEEN-BY: ', $v))
|
||
|
$this->seenby->push($t);
|
||
|
|
||
|
elseif ($t = $this->kludge('PATH: ', $v))
|
||
|
$this->path->push($t);
|
||
|
|
||
|
elseif ($t = $this->kludge(' \* Origin: ',$v))
|
||
|
$this->origin = $t;
|
||
|
|
||
|
// We got unknown Kludge lines in the origin
|
||
|
else {
|
||
|
$this->unknown->push($v);
|
||
|
|
||
|
//dd(['v'=>$v,'t'=>$t,'message'=>$message]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function description()
|
||
|
{
|
||
|
switch ($this->type())
|
||
|
{
|
||
|
case 'Echomail': return sprintf('Echomail: '.$this->echoarea);
|
||
|
case 'Netmail': return sprintf('Netmail: %s->%s',$this->fqfa,$this->fqfd);
|
||
|
default:
|
||
|
return 'UNKNOWN';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function type()
|
||
|
{
|
||
|
if ($this->echoarea)
|
||
|
return 'Echomail';
|
||
|
|
||
|
if ($this->intl)
|
||
|
return 'Netmail';
|
||
|
|
||
|
return 'UNKNOWN';
|
||
|
}
|
||
|
}
|