Better catching bad TZUTC in messages, continue parsing mail bundles in an archive if a packet has an error
All checks were successful
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 36s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 1m48s
Create Docker Image / Final Docker Image Manifest (push) Successful in 10s

This commit is contained in:
2024-10-22 17:08:48 +11:00
parent eb61c5ea6e
commit 86a15872b8
4 changed files with 246 additions and 206 deletions

View File

@@ -89,7 +89,7 @@ class Message extends FTNBase
public const AREATAG_LEN = 35; //
private array $header; // Message Header
private int $tzutc = 0; // TZUTC that needs to be converted to be used by Carbon @see self::kludges
private Collection $kludges; // TZUTC that needs to be converted to be used by Carbon @see self::kludges
private Echomail|Netmail $mo; // The object storing this packet message
private Address $us; // Our address for this message
@@ -294,6 +294,7 @@ class Message extends FTNBase
public function __construct(Zone $zone)
{
$this->zone = $zone;
$this->kludges = collect();
}
public function __get($key)
@@ -476,11 +477,25 @@ class Message extends FTNBase
break;
case 'tzutc':
return $this->kludges->get($key);
default:
throw new \Exception('Unknown key: '.$key);
}
}
public function __set(string $key,mixed $value): void
{
switch ($key) {
case 'tzutc':
if (! is_numeric($value))
throw new InvalidPacketException('TZUTC is not numeric '.$value);
$this->kludges->put($key,$value);
}
}
/**
* Export an FTN message, ready for sending.
*
@@ -654,147 +669,158 @@ class Message extends FTNBase
// First find our kludge lines
$ptr_start = 0;
$ptr_end = 0;
while (substr($message,$ptr_start,1) === "\x01") {
$ptr_end = strpos($message,"\r",$ptr_start);
try {
while (substr($message,$ptr_start,1) === "\x01") {
$ptr_end = strpos($message,"\r",$ptr_start);
$m = [];
$kludge = ($x=substr($message,$ptr_start+1,$ptr_end-$ptr_start-1));
preg_match('/^([^\s]+:?)+\s+(.*)$/',$kludge,$m);
$m = [];
$kludge = ($x=substr($message,$ptr_start+1,$ptr_end-$ptr_start-1));
preg_match('/^([^\s]+:?)+\s+(.*)$/',$kludge,$m);
$ptr_start = $ptr_end+1;
if (! $m) {
Log::alert(sprintf('%s:! Invalid Kluge Line [%s]',self::LOGKEY,$x));
continue;
}
// Catch any kludges we need to process here
if (array_key_exists($m[1],self::kludges)) {
// Some earlier mystic message had a blank value for TZUTC
if ((($m[1]) === 'TZUTC:') && (! $m[2]))
$m[2] = '0000';
$this->{self::kludges[$m[1]]} = $m[2];
} else
$o->kludges = [$m[1],$m[2]];
}
// Next our message content ends with '\r * Origin: ... \r' or <soh>...
// FTS-0004.001
if ($ptr_end=strrpos($message,"\r * Origin: ",$ptr_start)) {
// Find the <cr>
$ptr_end = strpos($message,"\r",$ptr_end+1);
// If there is no ptr_end, then this is not an origin
if (! $ptr_end)
throw new InvalidPacketException('Couldnt find the end of the origin');
} elseif (! $ptr_end=strpos($message,"\r\x01",$ptr_start)) {
$ptr_end = strlen($message);
}
$remaining = substr($message,$ptr_end+1);
// At this point, the remaining part of the message should start with \x01, PATH or SEEN-BY
if ((substr($remaining,0,9) !== 'SEEN-BY: ') && (substr($remaining,0,5) !== 'PATH:') && ($x=strpos($remaining,"\x01")) !== 0) {
if ($x)
$ptr_end += $x;
else
$ptr_end += strlen($remaining);
}
// Process the message content
if ($content=substr($message,$ptr_start,$ptr_end-$ptr_start)) {
$o->msg_src = $content;
$o->msg_crc = md5($content);
$ptr_content_start = 0;
// See if we have a tagline
if ($ptr_content_end=strrpos($content,"\r... ",$ptr_content_start)) {
$o->msg = substr($content,$ptr_content_start,$ptr_content_end+1);
$ptr_content_start = $ptr_content_end+5;
$ptr_content_end = strpos($content,"\r",$ptr_content_start);
// If there is no terminating "\r", then that's it
if (! $ptr_content_end) {
$o->set_tagline = substr($content,$ptr_content_start);
$ptr_content_start = strlen($content);
} else {
$o->set_tagline = substr($content,$ptr_content_start,$ptr_content_end-$ptr_content_start);
$ptr_content_start = $ptr_content_end;
}
}
// See if we have a tearline
if ($ptr_content_end=strrpos($content,"\r--- ",$ptr_content_start)) {
if (! $ptr_content_start)
$o->msg = substr($content,$ptr_content_start,$ptr_content_end+1);
$ptr_content_start = $ptr_content_end+5;
$ptr_content_end = strpos($content,"\r",$ptr_content_start);
// If there is no terminating "\r", then that's it
if (! $ptr_content_end) {
$o->set_tearline = substr($content,$ptr_content_start);
$ptr_content_start = strlen($content);
} else {
$o->set_tearline = substr($content,$ptr_content_start,$ptr_content_end-$ptr_content_start);
$ptr_content_start = $ptr_content_end;
}
}
// See if we have an origin
if ($ptr_content_end=strrpos($content,"\r * Origin: ",$ptr_content_start)) {
if (! $ptr_content_start)
$o->msg = substr($content,$ptr_content_start,$ptr_content_end);
$ptr_content_start = $ptr_content_end+12;
$ptr_content_end = strpos($content,"\r",$ptr_content_start);
// If there is no terminating "\r", then that's it
if (! $ptr_content_end) {
$o->set_origin = substr($content,$ptr_content_start);
$ptr_content_start = strlen($content);
} else {
$o->set_origin = substr($content,$ptr_content_start,$ptr_content_end-$ptr_content_start);
$ptr_content_start = $ptr_content_end+1;
}
}
// If there wasnt any tagline/tearline/origin, then the whole content is the message
if (! $ptr_content_start) {
$o->msg = $content;
$ptr_content_start = $ptr_end-$ptr_start;
}
// Trim any right \r from the message
$o->msg = rtrim($o->msg,"\r");
// Quick validation that we are done
if ($ptr_content_start !== strlen($content)) {
Log::alert(sprintf('%s:! We failed parsing the message.',self::LOGKEY));
$o->msg = substr($message,0,$ptr_end);
}
}
$ptr_start = $ptr_end+1;
if (! $m) {
Log::alert(sprintf('%s:! Invalid Kluge Line [%s]',self::LOGKEY,$x));
continue;
}
// Finally work out control kludges
foreach (collect(explode("\r",substr($message,$ptr_start)))->filter() as $line) {
// If the line starts with <soh> ignore it
if (substr($line,0,1) === "\x01")
$line = ltrim($line,"\x01");
// Catch any kludges we need to process here
if (array_key_exists($m[1],self::kludges)) {
// Some earlier mystic message had a blank value for TZUTC
if ((($m[1]) === 'TZUTC:') && (! $m[2]))
$m[2] = '0000';
$this->{self::kludges[$m[1]]} = $m[2];
} else
$m = [];
preg_match('/^([^\s]+:?)+\s+(.*)$/',$line,$m);
$o->kludges = [$m[1],$m[2]];
}
// Next our message content ends with '\r * Origin: ... \r' or <soh>...
// FTS-0004.001
if ($ptr_end=strrpos($message,"\r * Origin: ",$ptr_start)) {
// Find the <cr>
$ptr_end = strpos($message,"\r",$ptr_end+1);
// If there is no ptr_end, then this is not an origin
if (! $ptr_end)
throw new InvalidPacketException('Couldnt find the end of the origin');
} elseif (! $ptr_end=strpos($message,"\r\x01",$ptr_start)) {
$ptr_end = strlen($message);
}
$remaining = substr($message,$ptr_end+1);
// At this point, the remaining part of the message should start with \x01, PATH or SEEN-BY
if ((substr($remaining,0,9) !== 'SEEN-BY: ') && (substr($remaining,0,5) !== 'PATH:') && ($x=strpos($remaining,"\x01")) !== 0) {
if ($x)
$ptr_end += $x;
else
$ptr_end += strlen($remaining);
}
// Process the message content
if ($content=substr($message,$ptr_start,$ptr_end-$ptr_start)) {
$o->msg_src = $content;
$o->msg_crc = md5($content);
$ptr_content_start = 0;
// See if we have a tagline
if ($ptr_content_end=strrpos($content,"\r... ",$ptr_content_start)) {
$o->msg = substr($content,$ptr_content_start,$ptr_content_end+1);
$ptr_content_start = $ptr_content_end+5;
$ptr_content_end = strpos($content,"\r",$ptr_content_start);
// If there is no terminating "\r", then that's it
if (! $ptr_content_end) {
$o->set_tagline = substr($content,$ptr_content_start);
$ptr_content_start = strlen($content);
} else {
$o->set_tagline = substr($content,$ptr_content_start,$ptr_content_end-$ptr_content_start);
$ptr_content_start = $ptr_content_end;
}
}
// See if we have a tearline
if ($ptr_content_end=strrpos($content,"\r--- ",$ptr_content_start)) {
if (! $ptr_content_start)
$o->msg = substr($content,$ptr_content_start,$ptr_content_end+1);
} catch (\Exception $e) {
Log::error(sprintf('%s:! Error parsing message, now at offset [0x%02x] (%s)',
self::LOGKEY,
$ptr_start,
$e->getMessage()),['dump'=>hex_dump($message)]);
$ptr_content_start = $ptr_content_end+5;
$ptr_content_end = strpos($content,"\r",$ptr_content_start);
// If there is no terminating "\r", then that's it
if (! $ptr_content_end) {
$o->set_tearline = substr($content,$ptr_content_start);
$ptr_content_start = strlen($content);
} else {
$o->set_tearline = substr($content,$ptr_content_start,$ptr_content_end-$ptr_content_start);
$ptr_content_start = $ptr_content_end;
}
}
// See if we have an origin
if ($ptr_content_end=strrpos($content,"\r * Origin: ",$ptr_content_start)) {
if (! $ptr_content_start)
$o->msg = substr($content,$ptr_content_start,$ptr_content_end);
$ptr_content_start = $ptr_content_end+12;
$ptr_content_end = strpos($content,"\r",$ptr_content_start);
// If there is no terminating "\r", then that's it
if (! $ptr_content_end) {
$o->set_origin = substr($content,$ptr_content_start);
$ptr_content_start = strlen($content);
} else {
$o->set_origin = substr($content,$ptr_content_start,$ptr_content_end-$ptr_content_start);
$ptr_content_start = $ptr_content_end+1;
}
}
// If there wasnt any tagline/tearline/origin, then the whole content is the message
if (! $ptr_content_start) {
$o->msg = $content;
$ptr_content_start = $ptr_end-$ptr_start;
}
// Trim any right \r from the message
$o->msg = rtrim($o->msg,"\r");
// Quick validation that we are done
if ($ptr_content_start !== strlen($content)) {
Log::alert(sprintf('%s:! We failed parsing the message.',self::LOGKEY));
$o->msg = substr($message,0,$ptr_end);
}
}
$ptr_start = $ptr_end+1;
// Finally work out control kludges
foreach (collect(explode("\r",substr($message,$ptr_start)))->filter() as $line) {
// If the line starts with <soh> ignore it
if (substr($line,0,1) === "\x01")
$line = ltrim($line,"\x01");
$m = [];
preg_match('/^([^\s]+:?)+\s+(.*)$/',$line,$m);
$o->kludges = [$m[1],$m[2]];
throw new InvalidPacketException('Error parsing message');
}
return $o;

View File

@@ -174,6 +174,7 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
|| (($end=strpos($msgbuf,"\x00".self::PACKED_END,$leader)) !== FALSE))
{
// Parse our message
Log::debug(sprintf('%s:- Message at offset [%d] in [%s]',self::LOGKEY,$read_ptr-strlen($readbuf),$name));
$o->parseMessage(substr($msgbuf,0,$end));
$msgbuf = substr($msgbuf,$end+3);