Start of processing packets - implemented PING Responce to Netmail
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Classes\FTN;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -9,9 +10,8 @@ use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Validator as ValidatorResult;
|
||||
|
||||
use App\Classes\FTN as FTNBase;
|
||||
use App\Models\Address;
|
||||
use App\Models\{Address,Domain};
|
||||
use App\Rules\TwoByteInteger;
|
||||
use App\Traits\GetNode;
|
||||
|
||||
/**
|
||||
* Class Message
|
||||
@@ -21,14 +21,15 @@ use App\Traits\GetNode;
|
||||
*/
|
||||
class Message extends FTNBase
|
||||
{
|
||||
//use GetNode;
|
||||
private const cast_utf8 = [
|
||||
'message',
|
||||
];
|
||||
|
||||
// Single value kludge items
|
||||
private array $_kludge = [
|
||||
'chrs' => 'CHRS: ',
|
||||
'charset' => 'CHARSET: ',
|
||||
'codepage' => 'CODEPAGE: ',
|
||||
'msgid' => 'MSGID: ',
|
||||
'pid' => 'PID: ',
|
||||
'replyid' => 'REPLY: ',
|
||||
'tid' => 'TID: ',
|
||||
@@ -63,7 +64,7 @@ class Message extends FTNBase
|
||||
'dnet' => [0x06,'v',2], // Destination Net
|
||||
'flags' => [0x08,'v',2], // Message Flags
|
||||
'cost' => [0x0a,'v',2], // Send Cost
|
||||
'date' => [0x0c,'A20',20] // Message Date FTS-0001.016 Date: upto 20 chars null terminated
|
||||
'date' => [0x0c,'a20',20] // Message Date FTS-0001.016 Date: upto 20 chars null terminated
|
||||
];
|
||||
|
||||
private const USER_FROM_LEN = 36; // FTS-0001.016 From Name: upto 36 chars null terminated
|
||||
@@ -74,20 +75,23 @@ class Message extends FTNBase
|
||||
private ?ValidatorResult $errors = NULL; // Packet validation
|
||||
private array $header; // Message Header
|
||||
private Collection $kludge; // Hold kludge items
|
||||
|
||||
private string $user_from; // User message is From
|
||||
private string $user_to; // User message is To
|
||||
private string $subject; // Message subject
|
||||
private string $msgid; // MSG ID
|
||||
private string $echoarea; // FTS-0004.001
|
||||
private string $intl; // Netmail details
|
||||
private string $message; // The actual message content
|
||||
private string $tearline;
|
||||
private string $origin; // FTS-0004.001
|
||||
private ?string $echoarea = NULL; // FTS-0004.001
|
||||
|
||||
private array $zone; // Zone the message belongs to. (src/dst - for netmail)
|
||||
private array $point; // Point the message belongs to (Netmail)
|
||||
private array $netmail; // Netmail details
|
||||
|
||||
private Collection $path; // FTS-0004.001 The message PATH lines
|
||||
private Collection $seenby; // FTS-0004.001 The message SEEN-BY lines
|
||||
private Collection $via; // The path the message has gone using Via lines (Netmail)
|
||||
private Collection $_other; // Temporarily hold attributes we dont process yet.
|
||||
private Collection $unknown; // Temporarily hold attributes we have no logic for.
|
||||
|
||||
// Convert characters into printable chars
|
||||
@@ -136,42 +140,86 @@ class Message extends FTNBase
|
||||
0xfc => 0x207f, 0xfd => 0x00b2, 0xfe => 0x25a0, 0xff => 0x00a0,
|
||||
];
|
||||
|
||||
public function __construct(string $msg)
|
||||
public function __construct(Domain $domain=NULL)
|
||||
{
|
||||
$this->domain = $domain;
|
||||
|
||||
$this->kludge = collect();
|
||||
$this->path = collect();
|
||||
$this->seenby = collect();
|
||||
$this->via = collect();
|
||||
$this->_other = collect();
|
||||
$this->unknown = collect();
|
||||
$this->zone = [];
|
||||
$this->point = [];
|
||||
$this->tearline = '';
|
||||
$this->origin = '';
|
||||
$this->msgid = '';
|
||||
$this->echoarea = '';
|
||||
$this->intl = '';
|
||||
}
|
||||
|
||||
$this->header = unpack($this->unpackheader(self::header),substr($msg,0,self::HEADER_LEN));
|
||||
/**
|
||||
* Parse a message from a packet
|
||||
*
|
||||
* @param string $msg
|
||||
* @param Domain|null $domain
|
||||
* @return static
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public static function parseMessage(string $msg,Domain $domain=NULL): self
|
||||
{
|
||||
$o = new self($domain);
|
||||
|
||||
$o->header = unpack(self::unpackheader(self::header),substr($msg,0,self::HEADER_LEN));
|
||||
|
||||
$ptr = 0;
|
||||
// To User
|
||||
$this->user_to = strstr(substr($msg,self::HEADER_LEN+$ptr),"\x00",TRUE);
|
||||
$ptr += strlen($this->user_to)+1;
|
||||
$o->user_to = strstr(substr($msg,self::HEADER_LEN+$ptr),"\x00",TRUE);
|
||||
$ptr += strlen($o->user_to)+1;
|
||||
|
||||
// From User
|
||||
$this->user_from = strstr(substr($msg,self::HEADER_LEN+$ptr),"\x00",TRUE);
|
||||
$ptr += strlen($this->user_from)+1;
|
||||
$o->user_from = strstr(substr($msg,self::HEADER_LEN+$ptr),"\x00",TRUE);
|
||||
$ptr += strlen($o->user_from)+1;
|
||||
|
||||
// Subject
|
||||
$this->subject = strstr(substr($msg,self::HEADER_LEN+$ptr),"\x00",TRUE);
|
||||
$ptr += strlen($this->subject)+1;
|
||||
$o->subject = strstr(substr($msg,self::HEADER_LEN+$ptr),"\x00",TRUE);
|
||||
$ptr += strlen($o->subject)+1;
|
||||
|
||||
// Check if this is an Echomail
|
||||
if (! strncmp(substr($msg,self::HEADER_LEN+$ptr),'AREA:',5)) {
|
||||
$this->echoarea = substr($msg,self::HEADER_LEN+$ptr+5,strpos($msg,"\r",self::HEADER_LEN+$ptr+5)-(self::HEADER_LEN+$ptr+5));
|
||||
$ptr += strlen($this->echoarea)+5+1;
|
||||
$o->echoarea = substr($msg,self::HEADER_LEN+$ptr+5,strpos($msg,"\r",self::HEADER_LEN+$ptr+5)-(self::HEADER_LEN+$ptr+5));
|
||||
$ptr += strlen($o->echoarea)+5+1;
|
||||
}
|
||||
|
||||
$this->parseMessage(substr($msg,self::HEADER_LEN+$ptr));
|
||||
$o->unpackMessage(substr($msg,self::HEADER_LEN+$ptr));
|
||||
|
||||
if (($x=$this->validate()->getMessageBag())->count())
|
||||
Log::debug('Message fails validation',['result'=>$x]);
|
||||
if (($x=$o->validate($domain))->fails()) {
|
||||
Log::debug('Message fails validation',['result'=>$x->errors()]);
|
||||
throw new \Exception('Message validation fails:'.join(' ',$x->errors()->all()));
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the string into something printable via the web
|
||||
*
|
||||
* @param string $string
|
||||
* @param array $skip
|
||||
* @return string
|
||||
*/
|
||||
public static function tr(string $string,array $skip=[0x0a,0x0d]): string
|
||||
{
|
||||
$tr = [];
|
||||
|
||||
foreach (self::CP437 as $k=>$v) {
|
||||
if (in_array($k,$skip))
|
||||
continue;
|
||||
|
||||
$tr[chr($k)] = '&#'.$v;
|
||||
}
|
||||
|
||||
return strtr($string,$tr);
|
||||
}
|
||||
|
||||
public function __get($key)
|
||||
@@ -194,17 +242,19 @@ class Message extends FTNBase
|
||||
case 'tftn':
|
||||
return parent::__get($key);
|
||||
|
||||
case 'fftn_o':
|
||||
return Address::findFTN($this->fftn);
|
||||
case 'tftn_o':
|
||||
return Address::findFTN($this->tftn);
|
||||
|
||||
case 'date':
|
||||
return sprintf('%s (%s)',Arr::get($this->header,$key),$this->kludge->get('tzutc'));
|
||||
return Carbon::createFromFormat('d M y H:i:s O',
|
||||
sprintf('%s %s',chop(Arr::get($this->header,$key)),($x=$this->kludge->get('tzutc')) < 0 ? $x : '+'.$x));
|
||||
|
||||
case 'flags':
|
||||
case 'cost': return Arr::get($this->header,$key);
|
||||
|
||||
case 'msgid': return $this->kludge->get('msgid');
|
||||
|
||||
case 'message':
|
||||
return utf8_decode($this->{$key});
|
||||
|
||||
case 'subject':
|
||||
case 'user_to':
|
||||
case 'user_from':
|
||||
@@ -212,29 +262,122 @@ class Message extends FTNBase
|
||||
case 'path':
|
||||
case 'seenby':
|
||||
case 'via':
|
||||
case 'msgid':
|
||||
case 'errors':
|
||||
case 'echoarea':
|
||||
return $this->{$key};
|
||||
|
||||
/*
|
||||
case 'tearline':
|
||||
return '--- FTNHub';
|
||||
*/
|
||||
default:
|
||||
throw new \Exception('Unknown key: '.$key);
|
||||
}
|
||||
}
|
||||
|
||||
public function __set($key,$value)
|
||||
{
|
||||
switch ($key) {
|
||||
case 'echoarea':
|
||||
case 'header':
|
||||
case 'intl':
|
||||
case 'message':
|
||||
case 'msgid':
|
||||
case 'subject':
|
||||
case 'user_from':
|
||||
case 'user_to':
|
||||
case 'via':
|
||||
$this->{$key} = $value;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception('Unknown key: '.$key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When we serialise this object, we'll need to utf8_encode some values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __serialize(): array
|
||||
{
|
||||
$values = [];
|
||||
|
||||
$properties = (new \ReflectionClass($this))->getProperties();
|
||||
|
||||
$class = get_class($this);
|
||||
|
||||
foreach ($properties as $property) {
|
||||
if ($property->isStatic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$property->setAccessible(true);
|
||||
|
||||
if (! $property->isInitialized($this)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $property->getName();
|
||||
$encode = in_array($name,self::cast_utf8);
|
||||
|
||||
if ($property->isPrivate()) {
|
||||
$name = "\0{$class}\0{$name}";
|
||||
} elseif ($property->isProtected()) {
|
||||
$name = "\0*\0{$name}";
|
||||
}
|
||||
|
||||
$property->setAccessible(true);
|
||||
$value = $property->getValue($this);
|
||||
|
||||
$values[$name] = $encode ? utf8_encode($value) : $value;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* When we unserialize, we'll restore (utf8_decode) some values
|
||||
*
|
||||
* @param array $values
|
||||
*/
|
||||
public function __unserialize(array $values): void
|
||||
{
|
||||
$properties = (new \ReflectionClass($this))->getProperties();
|
||||
|
||||
$class = get_class($this);
|
||||
|
||||
foreach ($properties as $property) {
|
||||
if ($property->isStatic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $property->getName();
|
||||
$decode = in_array($name,self::cast_utf8);
|
||||
|
||||
if ($property->isPrivate()) {
|
||||
$name = "\0{$class}\0{$name}";
|
||||
} elseif ($property->isProtected()) {
|
||||
$name = "\0*\0{$name}";
|
||||
}
|
||||
|
||||
if (! array_key_exists($name, $values)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$property->setAccessible(true);
|
||||
|
||||
$property->setValue(
|
||||
$this, $decode ? utf8_decode($values[$name]) : $values[$name]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export an FTN message, ready for sending.
|
||||
*
|
||||
* @return string
|
||||
* @todo To rework
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
// if (f->net == 65535) { /* Point packet - Get Net from auxNet */
|
||||
$return = '';
|
||||
|
||||
$return .= pack(join('',collect(self::header)->pluck(1)->toArray()),
|
||||
@@ -243,48 +386,36 @@ class Message extends FTNBase
|
||||
$this->fn,
|
||||
$this->tn,
|
||||
$this->flags,
|
||||
$this->cost
|
||||
$this->cost,
|
||||
$this->date->format('d M y H:i:s'),
|
||||
);
|
||||
|
||||
// @todo use pack for this.
|
||||
$return .= $this->date->format('d M y H:i:s')."\00";
|
||||
$return .= $this->to."\00";
|
||||
$return .= $this->from."\00";
|
||||
$return .= $this->user_to."\00";
|
||||
$return .= $this->user_from."\00";
|
||||
$return .= $this->subject."\00";
|
||||
|
||||
if ($this->type == 'echomail')
|
||||
if ($this->isNetmail())
|
||||
$return .= sprintf("\01INTL %s\r",$this->intl);
|
||||
else
|
||||
$return .= "AREA:".$this->echoarea."\r";
|
||||
|
||||
// Add some kludges
|
||||
$return .= "\01MSGID ".$this->_fqfa." 1"."\r";
|
||||
$return .= sprintf("\01MSGID: %s\r",$this->msgid);
|
||||
|
||||
foreach ($this->_kludge as $k=>$v) {
|
||||
if ($x=$this->kludge->get($k))
|
||||
$return .= chr(1).$v.$x."\r";
|
||||
$return .= sprintf("\01%s %s\r",$v,$x);
|
||||
}
|
||||
|
||||
$return .= $this->message."\r";
|
||||
$return .= $this->tearline."\r";
|
||||
$return .= $this->origin."\r";
|
||||
if ($this->tearline)
|
||||
$return .= $this->tearline."\r";
|
||||
if ($this->origin)
|
||||
$return .= $this->origin."\r";
|
||||
|
||||
switch ($this->type)
|
||||
{
|
||||
case 'echomail':
|
||||
break;
|
||||
|
||||
case 'netmail':
|
||||
foreach ($this->via as $k=>$v)
|
||||
$return .= "\01Via: ".$v."\r";
|
||||
|
||||
// @todo Set product name/version as var
|
||||
$return .= sprintf('%sVia: %s @%s.UTC %s %i.%i',
|
||||
chr(1),
|
||||
'10:0/0',
|
||||
now('UTC')->format('Ymd.His'),
|
||||
'FTNHub',
|
||||
1,1)."\r";
|
||||
|
||||
break;
|
||||
if ($this->isNetmail()) {
|
||||
foreach ($this->via as $v)
|
||||
$return .= sprintf("\01Via %s\r",$v);
|
||||
}
|
||||
|
||||
$return .= "\00";
|
||||
@@ -292,6 +423,16 @@ class Message extends FTNBase
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this message doesnt have an AREATAG, then its a netmail.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isNetmail(): bool
|
||||
{
|
||||
return ! $this->echoarea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of flag descriptions
|
||||
*
|
||||
@@ -299,26 +440,26 @@ class Message extends FTNBase
|
||||
*
|
||||
* http://ftsc.org/docs/fsc-0001.000
|
||||
* AttributeWord bit meaning
|
||||
--- --------------------
|
||||
0 + Private
|
||||
1 + s Crash
|
||||
2 Recd
|
||||
3 Sent
|
||||
4 + FileAttached
|
||||
5 InTransit
|
||||
6 Orphan
|
||||
7 KillSent
|
||||
8 Local
|
||||
9 s HoldForPickup
|
||||
10 + unused
|
||||
11 s FileRequest
|
||||
12 + s ReturnReceiptRequest
|
||||
13 + s IsReturnReceipt
|
||||
14 + s AuditRequest
|
||||
15 s FileUpdateReq
|
||||
|
||||
s - this bit is supported by SEAdog only
|
||||
+ - this bit is not zeroed before packeting
|
||||
* --- --------------------
|
||||
* 0 + Private
|
||||
* 1 + s Crash
|
||||
* 2 Recd
|
||||
* 3 Sent
|
||||
* 4 + FileAttached
|
||||
* 5 InTransit
|
||||
* 6 Orphan
|
||||
* 7 KillSent
|
||||
* 8 Local
|
||||
* 9 s HoldForPickup
|
||||
* 10 + unused
|
||||
* 11 s FileRequest
|
||||
* 12 + s ReturnReceiptRequest
|
||||
* 13 + s IsReturnReceipt
|
||||
* 14 + s AuditRequest
|
||||
* 15 s FileUpdateReq
|
||||
*
|
||||
* s - this bit is supported by SEAdog only
|
||||
* + - this bit is not zeroed before packeting
|
||||
*/
|
||||
/*
|
||||
public function flags(int $flags): array
|
||||
@@ -339,137 +480,6 @@ class Message extends FTNBase
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* If this message doesnt have an AREATAG, then its a netmail.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isNetmail(): bool
|
||||
{
|
||||
return ! $this->echoarea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract information out of the message text.
|
||||
*
|
||||
* @param string $message
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public function parseMessage(string $message): void
|
||||
{
|
||||
// Remove DOS \n\r
|
||||
$message = preg_replace("/\n\r/","\r",$message);
|
||||
|
||||
// Split out the <SOH> lines
|
||||
$result = collect(explode("\01",$message))->filter();
|
||||
|
||||
$this->message = '';
|
||||
|
||||
foreach ($result as $v) {
|
||||
// Search for \r - if that is the end of the line, then its a kludge
|
||||
$x = strpos($v,"\r");
|
||||
$t = '';
|
||||
|
||||
// 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 .= utf8_encode(substr($v,$x+1,$y-$x-1));
|
||||
$this->parseOrigin(substr($v,$y));
|
||||
|
||||
// If this is netmail, the FQFA will have been set by the INTL line, we can skip the rest of this
|
||||
$matches = [];
|
||||
|
||||
// Capture the fully qualified 4D name from the Origin Line - it tells us the ZONE.
|
||||
preg_match('/^.*\((.*)\)$/',$this->origin,$matches);
|
||||
|
||||
// Double check we have an address in the origin line
|
||||
if (! Arr::get($matches,1))
|
||||
throw new InvalidPacketException(sprintf('No address in Origin?',$matches));
|
||||
|
||||
// Double check, our src and origin match
|
||||
$ftn = Address::parseFTN($matches[1]);
|
||||
|
||||
// We'll double check our FTN
|
||||
if (($ftn['n'] !== $this->fn) || ($ftn['f'] !== $this->ff)) {
|
||||
Log::error(sprintf('FTN [%s] doesnt match message header',$matches[1]),['ftn'=>$ftn]);
|
||||
}
|
||||
|
||||
$this->zone['src'] = $ftn['z'];
|
||||
$this->point['src'] = $ftn['p'];
|
||||
|
||||
// The message is the rest?
|
||||
} elseif (strlen($v) > $x+1) {
|
||||
$this->message .= utf8_encode(substr($v,$x+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;
|
||||
}
|
||||
}
|
||||
|
||||
// There is more text.
|
||||
if ($t)
|
||||
continue;
|
||||
|
||||
// From point: <SOH>"FMPT <point number><CR>
|
||||
if ($t = $this->kludge('FMPT ',$v))
|
||||
$this->point['src'] = $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->netmail['intl'] = $t;
|
||||
|
||||
// INTL kludge is in Netmail, so we'll do some validation:
|
||||
list($this->netmail['dst'],$this->netmail['src']) = explode(' ',$t);
|
||||
|
||||
$src = Address::parseFTN($this->netmail['src']);
|
||||
if (($src['n'] !== $this->fn) || ($src['f'] !== $this->ff)) {
|
||||
Log::error(sprintf('INTL src address [%s] doesnt match packet',$this->netmail['src']));
|
||||
} else {
|
||||
// We'll set our source zone
|
||||
$this->zone['src'] = $src['z'];
|
||||
}
|
||||
|
||||
$dst = Address::parseFTN($this->netmail['dst']);
|
||||
if (($dst['n'] !== $this->tn) || ($dst['f'] !== $this->tf)) {
|
||||
Log::error(sprintf('INTL dst address [%s] doesnt match packet',$this->netmail['dst']));
|
||||
} else {
|
||||
// We'll set our source zone
|
||||
$this->zone['dst'] = $dst['z'];
|
||||
}
|
||||
}
|
||||
|
||||
elseif ($t = $this->kludge('PATH: ',$v))
|
||||
$this->path->push($t);
|
||||
|
||||
// To Point: <SOH>TOPT <point number><CR>
|
||||
elseif ($t = $this->kludge('TOPT ',$v))
|
||||
$this->point['dst'] = $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"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the data after the ORIGIN
|
||||
* There may be kludge lines after the origin - notably SEEN-BY
|
||||
@@ -505,23 +515,128 @@ class Message extends FTNBase
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the string into something printable via the web
|
||||
* Extract information out of the message text.
|
||||
*
|
||||
* @param string $string
|
||||
* @param array $skip
|
||||
* @return string
|
||||
* @param string $message
|
||||
* @throws InvalidPacketException
|
||||
*/
|
||||
public static function tr(string $string,array $skip=[0x0a,0x0d]): string
|
||||
public function unpackMessage(string $message): void
|
||||
{
|
||||
$tr = [];
|
||||
foreach (self::CP437 as $k=>$v) {
|
||||
if (in_array($k,$skip))
|
||||
// Remove DOS \n\r
|
||||
$message = preg_replace("/\n\r/","\r",$message);
|
||||
|
||||
// Split out the <SOH> lines
|
||||
$result = collect(explode("\01",$message))->filter();
|
||||
|
||||
$this->message = '';
|
||||
|
||||
foreach ($result as $v) {
|
||||
// Search for \r - if that is the end of the line, then its a kludge
|
||||
$x = strpos($v,"\r");
|
||||
$t = '';
|
||||
|
||||
// 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->parseOrigin(substr($v,$y));
|
||||
|
||||
// If this is netmail, the FQFA will have been set by the INTL line, we can skip the rest of this
|
||||
$matches = [];
|
||||
|
||||
// Capture the fully qualified 4D name from the Origin Line - it tells us the ZONE.
|
||||
preg_match('/^.*\((.*)\)$/',$this->origin,$matches);
|
||||
|
||||
// Double check we have an address in the origin line
|
||||
if (! Arr::get($matches,1))
|
||||
throw new InvalidPacketException('No address in Origin?');
|
||||
|
||||
// Double check, our src and origin match
|
||||
$ftn = Address::parseFTN($matches[1]);
|
||||
|
||||
// We'll double check our FTN
|
||||
if (($ftn['n'] !== $this->fn) || ($ftn['f'] !== $this->ff))
|
||||
Log::error(sprintf('FTN [%s] doesnt match message header',$matches[1]),['ftn'=>$ftn]);
|
||||
|
||||
// http://ftsc.org/docs/fsc-0068.001
|
||||
// MSGID should be the basis of the source
|
||||
$this->zone['src'] = $ftn['z'];
|
||||
$this->point['src'] = $ftn['p'];
|
||||
|
||||
// The message is the rest?
|
||||
} elseif (strlen($v) > $x+1) {
|
||||
$this->message .= substr($v,$x+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;
|
||||
}
|
||||
}
|
||||
|
||||
// There is more text.
|
||||
if ($t)
|
||||
continue;
|
||||
|
||||
$tr[chr($k)] = '&#'.$v;
|
||||
}
|
||||
// From point: <SOH>"FMPT <point number><CR>
|
||||
if ($t = $this->kludge('FMPT ',$v))
|
||||
$this->point['src'] = $t;
|
||||
|
||||
return strtr($string,$tr);
|
||||
/*
|
||||
* 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;
|
||||
|
||||
// INTL kludge is in Netmail, so we'll do some validation:
|
||||
list($dst,$src) = explode(' ',$t);
|
||||
|
||||
$ftn = Address::parseFTN($src);
|
||||
if (($ftn['n'] !== $this->fn) || ($ftn['f'] !== $this->ff)) {
|
||||
Log::error(sprintf('INTL src address [%s] doesnt match packet',$src));
|
||||
|
||||
} else {
|
||||
// We'll set our source zone
|
||||
$this->zone['src'] = $ftn['z'];
|
||||
}
|
||||
|
||||
$ftn = Address::parseFTN($dst);
|
||||
if (($ftn['n'] !== $this->tn) || ($ftn['f'] !== $this->tf)) {
|
||||
Log::error(sprintf('INTL dst address [%s] doesnt match packet',$dst));
|
||||
|
||||
} else {
|
||||
// We'll set our source zone
|
||||
$this->zone['dst'] = $ftn['z'];
|
||||
}
|
||||
}
|
||||
|
||||
elseif ($t = $this->kludge('MSGID: ',$v))
|
||||
$this->msgid = $t;
|
||||
|
||||
elseif ($t = $this->kludge('PATH: ',$v))
|
||||
$this->path->push($t);
|
||||
|
||||
// To Point: <SOH>TOPT <point number><CR>
|
||||
elseif ($t = $this->kludge('TOPT ',$v))
|
||||
$this->point['dst'] = $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"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -529,7 +644,7 @@ class Message extends FTNBase
|
||||
*
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
private function validate(): ValidatorResult
|
||||
public function validate(Domain $domain=NULL): ValidatorResult
|
||||
{
|
||||
// Check lengths
|
||||
$validator = Validator::make([
|
||||
@@ -543,6 +658,8 @@ class Message extends FTNBase
|
||||
'flags' => $this->flags,
|
||||
'cost' => $this->cost,
|
||||
'echoarea' => $this->echoarea,
|
||||
'ozone' => $this->fz,
|
||||
'dzone' => $this->tz,
|
||||
],[
|
||||
'user_from' => 'required|min:1|max:'.self::USER_FROM_LEN,
|
||||
'user_to' => 'required|min:1|max:'.self::USER_TO_LEN,
|
||||
@@ -554,8 +671,19 @@ class Message extends FTNBase
|
||||
'flags' => 'required|numeric',
|
||||
'cost' => 'required|numeric',
|
||||
'echoarea' => 'nullable|max:'.self::AREATAG_LEN,
|
||||
'ozone' => ['required',$this->domain ? 'in:'.$x=join(',',$this->domain->zones->pluck('zone_id')->toArray()): ''],
|
||||
'dzone' => ['required',$this->domain ? 'in:'.$x : '']
|
||||
]);
|
||||
|
||||
if ($domain) {
|
||||
$validator->after(function($validator) {
|
||||
if (! Address::findFTN($this->fftn))
|
||||
$validator->errors()->add('from',sprintf('Undefined Node [%s] sent packet.',$this->fftn));
|
||||
if (! Address::findFTN($this->tftn))
|
||||
$validator->errors()->add('to',sprintf('Undefined Node [%s] for destination.',$this->fftn));
|
||||
});
|
||||
}
|
||||
|
||||
if ($validator->fails())
|
||||
$this->errors = $validator;
|
||||
|
||||
|
Reference in New Issue
Block a user