Compare commits
10 Commits
6c7da7a220
...
b30ab2f999
Author | SHA1 | Date | |
---|---|---|---|
b30ab2f999 | |||
b4a42f6780 | |||
f279d85b08 | |||
46f52dd56d | |||
59ec5f5a0c | |||
29710c37c2 | |||
1650d07d5c | |||
0457b3df25 | |||
731fdb0a44 | |||
6216ada5e5 |
@ -93,6 +93,13 @@ jobs:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Record version
|
||||
run: |
|
||||
pwd
|
||||
ls -al
|
||||
echo ${GITHUB_SHA::8} > VERSION
|
||||
cat VERSION
|
||||
|
||||
- name: Build and Push Docker Image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
|
@ -11,7 +11,7 @@ abstract class FTN
|
||||
public function __get(string $key)
|
||||
{
|
||||
switch ($key) {
|
||||
case 'fftn':
|
||||
case 'fftn_t':
|
||||
return sprintf('%d:%d/%d.%d',
|
||||
$this->fz,
|
||||
$this->fn,
|
||||
@ -19,7 +19,7 @@ abstract class FTN
|
||||
$this->fp,
|
||||
).($this->zone ? sprintf('@%s',$this->zone->domain->name) : '');
|
||||
|
||||
case 'tftn':
|
||||
case 'tftn_t':
|
||||
return sprintf('%d:%d/%d.%d',
|
||||
$this->tz,
|
||||
$this->tn,
|
||||
@ -27,30 +27,16 @@ abstract class FTN
|
||||
$this->tp,
|
||||
).($this->zone ? sprintf('@%s',$this->zone->domain->name) : '');
|
||||
|
||||
case 'fftn_o':
|
||||
return Address::findFTN($this->fftn);
|
||||
case 'tftn_o':
|
||||
return Address::findFTN($this->tftn);
|
||||
case 'fftn':
|
||||
return Address::findFTN($this->fftn_t);
|
||||
case 'tftn':
|
||||
return Address::findFTN($this->tftn_t);
|
||||
|
||||
default:
|
||||
throw new \Exception('Unknown key: '.$key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a line is a kludge line.
|
||||
*
|
||||
* @param string $kludge
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
protected function kludge(string $kludge,string $string)
|
||||
{
|
||||
return (preg_match("/^{$kludge}/",$string))
|
||||
? chop(preg_replace("/^{$kludge}/",'',$string),"\r")
|
||||
: FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function creates our unpack header
|
||||
*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,23 +10,30 @@ use Illuminate\Support\Facades\Notification;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
|
||||
use App\Classes\FTN as FTNBase;
|
||||
use App\Models\{Address,Domain,Software,System,Zone};
|
||||
use App\Exceptions\InvalidPacketException;
|
||||
use App\Models\{Address,Domain,Echomail,Netmail,Software,Zone};
|
||||
use App\Notifications\Netmails\EchomailBadAddress;
|
||||
|
||||
/**
|
||||
* Represents a Fidonet Packet, that contains an array of messages.
|
||||
*
|
||||
* Thus this object is iterable as an array of Message::class.
|
||||
* Thus this object is iterable as an array of Echomail::class or Netmail::class.
|
||||
*/
|
||||
class Packet extends FTNBase implements \Iterator, \Countable
|
||||
abstract class Packet extends FTNBase implements \Iterator, \Countable
|
||||
{
|
||||
private const LOGKEY = 'PKT';
|
||||
|
||||
protected const PACKED_MSG_LEAD = "\02\00";
|
||||
protected const PACKED_END = "\00\00";
|
||||
|
||||
// @todo Rename this regex to something more descriptive, ie: FILENAME_REGEX
|
||||
public const regex = '([[:xdigit:]]{4})(?:-(\d{4,10}))?-(.+)';
|
||||
|
||||
/**
|
||||
* Packet types we support, in specific order for auto-detection to work
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public const PACKET_TYPES = [
|
||||
'2.2' => FTNBase\Packet\FSC45::class,
|
||||
'2+' => FTNBase\Packet\FSC48::class,
|
||||
@ -35,114 +42,28 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
];
|
||||
|
||||
protected array $header; // Packet Header
|
||||
protected ?string $name; // Packet name
|
||||
protected ?string $name = NULL; // Packet name
|
||||
|
||||
public File $file; // Packet filename
|
||||
public Collection $messages; // Messages in the Packet
|
||||
protected Address $fftn_p; // Address the packet is from (when packing messages)
|
||||
protected Address $tftn_p; // Address the packet is to (when packing messages)
|
||||
protected Collection $messages; // Messages in the Packet
|
||||
public Collection $errors; // Messages that fail validation
|
||||
protected int $index; // Our array index
|
||||
protected $pass_p = NULL; // Overwrite the packet password (when packing messages)
|
||||
|
||||
/* ABSTRACT */
|
||||
|
||||
/**
|
||||
* @param string|null $header
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct(string $header=NULL)
|
||||
{
|
||||
$this->messages = collect();
|
||||
$this->errors = collect();
|
||||
$this->domain = NULL;
|
||||
$this->name = NULL;
|
||||
|
||||
if ($header)
|
||||
$this->header = unpack(self::unpackheader(static::HEADER),$header);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
switch ($key) {
|
||||
// From Addresses
|
||||
case 'fz': return Arr::get($this->header,'ozone');
|
||||
case 'fn': return Arr::get($this->header,'onet');
|
||||
case 'ff': return Arr::get($this->header,'onode');
|
||||
case 'fp': return Arr::get($this->header,'opoint');
|
||||
case 'fd': return rtrim(Arr::get($this->header,'odomain',"\x00"));
|
||||
|
||||
// To Addresses
|
||||
case 'tz': return Arr::get($this->header,'dzone');
|
||||
case 'tn': return Arr::get($this->header,'dnet');
|
||||
case 'tf': return Arr::get($this->header,'dnode');
|
||||
case 'tp': return Arr::get($this->header,'dpoint');
|
||||
case 'td': return rtrim(Arr::get($this->header,'ddomain',"\x00"));
|
||||
|
||||
case 'date':
|
||||
return Carbon::create(
|
||||
Arr::get($this->header,'y'),
|
||||
Arr::get($this->header,'m')+1,
|
||||
Arr::get($this->header,'d'),
|
||||
Arr::get($this->header,'H'),
|
||||
Arr::get($this->header,'M'),
|
||||
Arr::get($this->header,'S')
|
||||
);
|
||||
|
||||
case 'password':
|
||||
return rtrim(Arr::get($this->header,$key),"\x00");
|
||||
|
||||
case 'fftn':
|
||||
case 'fftn_o':
|
||||
case 'tftn':
|
||||
case 'tftn_o':
|
||||
return parent::__get($key);
|
||||
|
||||
case 'software':
|
||||
$code = Arr::get($this->header,'prodcode-hi')<<8|Arr::get($this->header,'prodcode-lo');
|
||||
Software::unguard();
|
||||
$o = Software::singleOrNew(['code'=>$code,'type'=>Software::SOFTWARE_TOSSER]);
|
||||
Software::reguard();
|
||||
|
||||
return $o;
|
||||
|
||||
case 'software_ver':
|
||||
return sprintf('%d.%d',Arr::get($this->header,'prodrev-maj'),Arr::get($this->header,'prodrev-min'));
|
||||
|
||||
case 'capability':
|
||||
// This needs to be defined in child classes, since not all children have it
|
||||
return NULL;
|
||||
|
||||
// Packet Type
|
||||
case 'type':
|
||||
return static::TYPE;
|
||||
|
||||
// Packet name:
|
||||
case 'name':
|
||||
return $this->{$key} ?: sprintf('%08x',timew());
|
||||
|
||||
default:
|
||||
throw new \Exception('Unknown key: '.$key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the packet
|
||||
* This function is intended to be implemented in child classes to test if the packet
|
||||
* is defined by the child object
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
* @see self::PACKET_TYPES
|
||||
* @param string $header
|
||||
* @return bool
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
$return = $this->header();
|
||||
|
||||
foreach ($this->messages as $o) {
|
||||
if ($o->packed)
|
||||
$return .= self::PACKED_MSG_LEAD.$o;
|
||||
}
|
||||
|
||||
$return .= "\00\00";
|
||||
|
||||
return $return;
|
||||
}
|
||||
abstract public static function is_type(string $header): bool;
|
||||
abstract protected function header(): string;
|
||||
|
||||
/* STATIC */
|
||||
|
||||
@ -156,19 +77,6 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
return collect(static::HEADER)->sum(function($item) { return Arr::get($item,2); });
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is intended to be implemented in child classes to test if the packet
|
||||
* is defined by the child object
|
||||
*
|
||||
* @see self::PACKET_TYPES
|
||||
* @param string $header
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_type(string $header): bool
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a packet file
|
||||
*
|
||||
@ -224,7 +132,9 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
|
||||
// No message attached
|
||||
} else
|
||||
throw new InvalidPacketException('Not a valid packet, not EOP or SOM'.bin2hex($x));
|
||||
throw new InvalidPacketException('Not a valid packet, not EOP or SOM:'.bin2hex($x));
|
||||
|
||||
Log::info(sprintf('%s:- Packet [%s] is a [%s] packet, dated [%s]',self::LOGKEY,$o->name,get_class($o),$o->date));
|
||||
|
||||
// Work out the packet zone
|
||||
if ($o->fz && ($o->fd || $domain)) {
|
||||
@ -233,16 +143,10 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
->where('zone_id',$o->fz)
|
||||
->where('name',$o->fd ?: $domain->name)
|
||||
->single();
|
||||
|
||||
// We need not knowing the domain, we use the default zone
|
||||
} else {
|
||||
$o->zone = Zone::where('zone_id',$o->fz)
|
||||
->where('default',TRUE)
|
||||
->single();
|
||||
}
|
||||
|
||||
// If zone is not set, then we need to use a default zone - the messages may not be from this zone.
|
||||
if (! $o->zone) {
|
||||
if (empty($o->zone)) {
|
||||
Log::alert(sprintf('%s:! We couldnt work out the packet zone, so we have fallen back to the default for [%d]',self::LOGKEY,$o->fz));
|
||||
|
||||
$o->zone = Zone::where('zone_id',$o->fz)
|
||||
@ -252,7 +156,7 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
|
||||
$message = ''; // Current message we are building
|
||||
$msgbuf = '';
|
||||
$leader = Message::HEADER_LEN+strlen(self::PACKED_MSG_LEAD);
|
||||
$leader = Message::header_len()+strlen(self::PACKED_MSG_LEAD);
|
||||
|
||||
// We loop through reading from the buffer, to find our end of message tag
|
||||
while ((! feof($f) && ($readbuf=fread($f,$leader)))) {
|
||||
@ -269,7 +173,7 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
$msgbuf = substr($msgbuf,$end+3);
|
||||
continue;
|
||||
|
||||
// If we have more to read
|
||||
// If we have more to read
|
||||
} elseif ($read_ptr < $size) {
|
||||
continue;
|
||||
}
|
||||
@ -285,18 +189,112 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
}
|
||||
|
||||
/**
|
||||
* Location of the version
|
||||
*
|
||||
* @return int
|
||||
* @param string|null $header
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function version_offset(): int
|
||||
public function __construct(string $header=NULL)
|
||||
{
|
||||
return Arr::get(collect(static::HEADER)->get('type'),0);
|
||||
$this->messages = collect();
|
||||
$this->errors = collect();
|
||||
|
||||
if ($header)
|
||||
$this->header = unpack(self::unpackheader(static::HEADER),$header);
|
||||
}
|
||||
|
||||
public static function version_offset_len(): int
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
return Arr::get(collect(static::HEADER)->get('type'),2);
|
||||
Log::debug(sprintf('%s:/ Requesting key for Packet::class [%s]',self::LOGKEY,$key));
|
||||
|
||||
switch ($key) {
|
||||
// From Addresses
|
||||
case 'fz': return Arr::get($this->header,'ozone');
|
||||
case 'fn': return Arr::get($this->header,'onet');
|
||||
case 'ff': return Arr::get($this->header,'onode');
|
||||
case 'fp': return Arr::get($this->header,'opoint');
|
||||
case 'fd': return rtrim(Arr::get($this->header,'odomain',"\x00"));
|
||||
|
||||
// To Addresses
|
||||
case 'tz': return Arr::get($this->header,'dzone');
|
||||
case 'tn': return Arr::get($this->header,'dnet');
|
||||
case 'tf': return Arr::get($this->header,'dnode');
|
||||
case 'tp': return Arr::get($this->header,'dpoint');
|
||||
case 'td': return rtrim(Arr::get($this->header,'ddomain',"\x00"));
|
||||
|
||||
case 'date':
|
||||
return Carbon::create(
|
||||
Arr::get($this->header,'y'),
|
||||
Arr::get($this->header,'m')+1,
|
||||
Arr::get($this->header,'d'),
|
||||
Arr::get($this->header,'H'),
|
||||
Arr::get($this->header,'M'),
|
||||
Arr::get($this->header,'S')
|
||||
);
|
||||
|
||||
case 'password':
|
||||
return rtrim(Arr::get($this->header,$key),"\x00");
|
||||
|
||||
case 'fftn_t':
|
||||
case 'fftn':
|
||||
case 'tftn_t':
|
||||
case 'tftn':
|
||||
return parent::__get($key);
|
||||
|
||||
case 'software':
|
||||
$code = Arr::get($this->header,'prodcode-hi')<<8|Arr::get($this->header,'prodcode-lo');
|
||||
Software::unguard();
|
||||
$o = Software::singleOrNew(['code'=>$code,'type'=>Software::SOFTWARE_TOSSER]);
|
||||
Software::reguard();
|
||||
|
||||
return $o;
|
||||
|
||||
case 'software_ver':
|
||||
return sprintf('%d.%d',Arr::get($this->header,'prodrev-maj'),Arr::get($this->header,'prodrev-min'));
|
||||
|
||||
case 'capability':
|
||||
// This needs to be defined in child classes, since not all children have it
|
||||
return NULL;
|
||||
|
||||
// Packet Type
|
||||
case 'type':
|
||||
return static::TYPE;
|
||||
|
||||
// Packet name:
|
||||
case 'name':
|
||||
return $this->{$key} ?: sprintf('%08x',timew());
|
||||
|
||||
case 'messages':
|
||||
return $this->{$key};
|
||||
|
||||
default:
|
||||
throw new \Exception('Unknown key: '.$key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the packet
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
if (empty($this->messages))
|
||||
throw new InvalidPacketException('Refusing to make an empty packet');
|
||||
|
||||
if (empty($this->tftn_p) || empty($this->fftn_p))
|
||||
throw new InvalidPacketException('Cannot generate a packet without a destination address');
|
||||
|
||||
$return = $this->header();
|
||||
|
||||
foreach ($this->messages as $o)
|
||||
$return .= self::PACKED_MSG_LEAD.$o->packet($this->tftn_p);
|
||||
|
||||
$return .= "\00\00";
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/* INTERFACE */
|
||||
@ -309,7 +307,7 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
return $this->messages->count();
|
||||
}
|
||||
|
||||
public function current(): Message
|
||||
public function current(): Echomail|Netmail
|
||||
{
|
||||
return $this->messages->get($this->index);
|
||||
}
|
||||
@ -342,6 +340,7 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
* @param Address $oo
|
||||
* @param Address $o
|
||||
* @param string|null $passwd Override the password used in the packet
|
||||
* @deprecated Use Packet::generate(), which should generate a packet of the right type
|
||||
*/
|
||||
public function addressHeader(Address $oo,Address $o,string $passwd=NULL): void
|
||||
{
|
||||
@ -375,12 +374,38 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
* Add a message to this packet
|
||||
*
|
||||
* @param Message $o
|
||||
* @deprecated No longer used when Address::class is updated
|
||||
*/
|
||||
public function addMail(Message $o): void
|
||||
{
|
||||
$this->messages->push($o);
|
||||
}
|
||||
|
||||
public function for(Address $ao): self
|
||||
{
|
||||
$this->tftn_p = $ao;
|
||||
$this->fftn_p = our_address($ao);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a packet
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate(): string
|
||||
{
|
||||
return (string)$this;
|
||||
}
|
||||
|
||||
public function mail(Collection $msgs): self
|
||||
{
|
||||
$this->messages = $msgs;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a message in a mail packet
|
||||
*
|
||||
@ -393,7 +418,8 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
|
||||
$msg = Message::parseMessage($message,$this->zone);
|
||||
|
||||
// If the message from domain is different to the packet address domain, we'll skip this message
|
||||
// @todo If the message from domain (eg: $msg->fftn->zone->domain) is different to the packet address domain ($pkt->fftn->zone->domain), we'll skip this message
|
||||
Log::debug(sprintf('%s:^ Message [%s] - Packet from domain [%d], Message domain [%d]',self::LOGKEY,$msg->msgid,$this->fftn->zone->domain_id,$msg->fftn->zone->domain_id));
|
||||
|
||||
// If the message is invalid, we'll ignore it
|
||||
if ($msg->errors) {
|
||||
@ -401,14 +427,17 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
|
||||
// If the messages is not for the right zone, we'll ignore it
|
||||
if ($msg->errors->messages()->has('invalid-zone')) {
|
||||
Log::alert(sprintf('%s:! Message is from an invalid zone [%s], packet is from [%s] - ignoring it',self::LOGKEY,$msg->fftn,$msg->zone->domain->name));
|
||||
Log::alert(sprintf('%s:! Message [%s] is from an invalid zone [%s], packet is from [%s] - ignoring it',self::LOGKEY,$msg->msgid,$msg->fftn->zone->zone_id,$this->fftn->zone->zone_id));
|
||||
|
||||
if (! $msg->rescanned->count())
|
||||
Notification::route('netmail',$this->fftn_o)->notify(new EchomailBadAddress($msg));
|
||||
Notification::route('netmail',$this->fftn)->notify(new EchomailBadAddress($msg));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// @todo If the $msg->fftn doesnt exist, we'll need to create it
|
||||
// @todo If the $msg->tftn doesnt exist (netmail), we'll need to create it (ergo intransit)
|
||||
/*
|
||||
// If the to address doenst exist, we'll create a new entry
|
||||
if ($msg->errors->messages()->has('to') && $msg->tzone) {
|
||||
try {
|
||||
@ -470,10 +499,13 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
|
||||
Log::alert(sprintf('%s:- From FTN is not defined, creating new entry for [%s] (%d)',self::LOGKEY,$msg->fboss,$ao->id));
|
||||
}
|
||||
*/
|
||||
|
||||
if ($msg->errors->messages()->has('user_from') || $msg->errors->messages()->has('user_to')) {
|
||||
// If the from/to user is missing
|
||||
if ($msg->errors->messages()->has('from') || $msg->errors->messages()->has('to')) {
|
||||
Log::error(sprintf('%s:! Skipping message [%s] due to errors (%s)...',self::LOGKEY,$msg->msgid,join(',',$msg->errors->messages()->keys())));
|
||||
$this->errors->push($msg);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -481,8 +513,24 @@ class Packet extends FTNBase implements \Iterator, \Countable
|
||||
$this->messages->push($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the packet password
|
||||
*
|
||||
* @param string|null $password
|
||||
* @return self
|
||||
*/
|
||||
public function password(string $password=NULL): self
|
||||
{
|
||||
if ($password && (strlen($password) < 9))
|
||||
$this->pass_p = $password;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @deprecated Is this used? */
|
||||
public function pluck(string $key): Collection
|
||||
{
|
||||
throw new \Exception(sprintf('%s:! This function is deprecated - [%s]',self::LOGKEY,$key));
|
||||
return $this->messages->pluck($key);
|
||||
}
|
||||
}
|
@ -62,34 +62,36 @@ final class FSC48 extends Packet
|
||||
*/
|
||||
protected function header(): string
|
||||
{
|
||||
$oldest = $this->messages->sortBy('datetime')->last();
|
||||
|
||||
try {
|
||||
return pack(collect(self::HEADER)->pluck(1)->join(''),
|
||||
$this->ff, // Orig Node
|
||||
$this->tf, // Dest Node
|
||||
Arr::get($this->header,'y'), // Year
|
||||
Arr::get($this->header,'m'), // Month
|
||||
Arr::get($this->header,'d'), // Day
|
||||
Arr::get($this->header,'H'), // Hour
|
||||
Arr::get($this->header,'M'), // Minute
|
||||
Arr::get($this->header,'S'), // Second
|
||||
0, // Baud
|
||||
2, // Packet Version (should be 2)
|
||||
$this->fp ? 0xffff : $this->fn, // Orig Net (0xFFFF when OrigPoint != 0)
|
||||
$this->tn, // Dest Net
|
||||
(Setup::PRODUCT_ID & 0xff), // Product Code Lo
|
||||
Setup::PRODUCT_VERSION_MAJ, // Product Version Major
|
||||
$this->password, // Packet Password
|
||||
$this->fz, // Orig Zone
|
||||
$this->tz, // Dest Zone
|
||||
$this->fp ? $this->fn : 0x00, // Aux Net
|
||||
Arr::get($this->header,'capvalid',1<<0), // fsc-0039.004 (copy of 0x2c)
|
||||
((Setup::PRODUCT_ID >> 8) & 0xff), // Product Code Hi
|
||||
Setup::PRODUCT_VERSION_MIN, // Product Version Minor
|
||||
Arr::get($this->header,'capword',1<<0), // Capability Word
|
||||
$this->fz, // Orig Zone
|
||||
$this->tz, // Dest Zone
|
||||
$this->fp, // Orig Point
|
||||
$this->tp, // Dest Point
|
||||
$this->fftn_p->node_id, // Orig Node
|
||||
$this->tftn_p->node_id, // Dest Node
|
||||
$oldest->datetime->format('Y'), // Year
|
||||
$oldest->datetime->format('m')-1, // Month
|
||||
$oldest->datetime->format('d'), // Day
|
||||
$oldest->datetime->format('H'), // Hour
|
||||
$oldest->datetime->format('i'), // Minute
|
||||
$oldest->datetime->format('s'), // Second
|
||||
0, // Baud
|
||||
2, // Packet Version (should be 2)
|
||||
$this->fftn_p->point_id ? 0xffff : $this->fftn_p->host_id, // Orig Net (0xFFFF when OrigPoint != 0)
|
||||
$this->tftn_p->host_id, // Dest Net
|
||||
(Setup::PRODUCT_ID & 0xff), // Product Code Lo
|
||||
Setup::PRODUCT_VERSION_MAJ, // Product Version Major
|
||||
$this->pass_p ?: $this->tftn_p->session('pktpass'), // Packet Password
|
||||
$this->fftn_p->zone->zone_id, // Orig Zone
|
||||
$this->tftn_p->zone->zone_id, // Dest Zone
|
||||
$this->fftn_p->point_id ? $this->fftn_p->host_id : 0x00, // Aux Net
|
||||
1<<0, // fsc-0039.004 (copy of 0x2c)
|
||||
((Setup::PRODUCT_ID >> 8) & 0xff), // Product Code Hi
|
||||
Setup::PRODUCT_VERSION_MIN, // Product Version Minor
|
||||
1<<0, // Capability Word
|
||||
$this->fftn_p->zone->zone_id, // Orig Zone
|
||||
$this->tftn_p->zone->zone_id, // Dest Zone
|
||||
$this->fftn_p->point_id, // Orig Point
|
||||
$this->tftn_p->point_id, // Dest Point
|
||||
strtoupper(hexstr(Setup::PRODUCT_ID)), // ProdData
|
||||
);
|
||||
|
||||
|
@ -2,25 +2,23 @@
|
||||
|
||||
namespace App\Classes\FTN;
|
||||
|
||||
use App\Models\Echoarea;
|
||||
use App\Models\{Echoarea,Echomail,Netmail};
|
||||
|
||||
/**
|
||||
* Abstract class to hold the common functions for automatic responding to echomail/netmail messages
|
||||
*/
|
||||
abstract class Process
|
||||
{
|
||||
public static function canProcess(string $echoarea): bool
|
||||
public static function canProcess(Echoarea $eao): bool
|
||||
{
|
||||
$eao = Echoarea::where('name',$echoarea)->single();
|
||||
|
||||
return $eao && $eao->automsgs;
|
||||
return $eao->automsgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return TRUE if the process class handled the message.
|
||||
*
|
||||
* @param Message $msg
|
||||
* @param Echomail|Netmail $mo
|
||||
* @return bool
|
||||
*/
|
||||
abstract public static function handle(Message $msg): bool;
|
||||
abstract public static function handle(Echomail|Netmail $mo): bool;
|
||||
}
|
@ -5,7 +5,8 @@ namespace App\Classes\FTN\Process\Echomail;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\{Message,Process};
|
||||
use App\Classes\FTN\Process;
|
||||
use App\Models\{Echomail,Netmail};
|
||||
use App\Notifications\Echomails\Test as TestNotification;
|
||||
|
||||
/**
|
||||
@ -19,16 +20,16 @@ final class Test extends Process
|
||||
|
||||
private const testing = ['test','testing'];
|
||||
|
||||
public static function handle(Message $msg): bool
|
||||
public static function handle(Echomail|Netmail $mo): bool
|
||||
{
|
||||
if (! self::canProcess($msg->echoarea)
|
||||
|| (strtolower($msg->user_to) !== 'all')
|
||||
|| (! in_array(strtolower($msg->subject),self::testing)))
|
||||
if (! self::canProcess($mo->echoarea)
|
||||
|| (strtolower($mo->to) !== 'all')
|
||||
|| (! in_array(strtolower($mo->subject),self::testing)))
|
||||
return FALSE;
|
||||
|
||||
Log::info(sprintf('%s:- Processing TEST message from (%s) [%s] in [%s]',self::LOGKEY,$msg->user_from,$msg->fftn,$msg->echoarea));
|
||||
Log::info(sprintf('%s:- Processing TEST message from (%s) [%s] in [%s]',self::LOGKEY,$mo->from,$mo->fftn->ftn,$mo->echoarea->name));
|
||||
|
||||
Notification::route('echomail',$msg->echoarea)->notify(new TestNotification($msg));
|
||||
Notification::route('echomail',$mo->echoarea->withoutRelations())->notify(new TestNotification($mo));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ namespace App\Classes\FTN\Process\Netmail;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\{Message,Process};
|
||||
use App\Classes\FTN\Process;
|
||||
use App\Models\{Echomail,Netmail};
|
||||
use App\Notifications\Netmails\Areafix as AreafixNotification;
|
||||
use App\Notifications\Netmails\Areafix\NotConfiguredHere as AreafixNotConfiguredHereNotification;
|
||||
|
||||
@ -18,18 +19,18 @@ final class Areafix extends Process
|
||||
{
|
||||
private const LOGKEY = 'RP-';
|
||||
|
||||
public static function handle(Message $msg): bool
|
||||
public static function handle(Echomail|Netmail $mo): bool
|
||||
{
|
||||
if (strtolower($msg->user_to) !== 'areafix')
|
||||
if (strtolower($mo->to) !== 'areafix')
|
||||
return FALSE;
|
||||
|
||||
Log::info(sprintf('%s:- Processing AREAFIX message from (%s) [%s]',self::LOGKEY,$msg->user_from,$msg->fftn));
|
||||
Log::info(sprintf('%s:- Processing AREAFIX message from (%s) [%s]',self::LOGKEY,$mo->from,$mo->fftn));
|
||||
|
||||
// If this is not a node we manage, then respond with a sorry can help you
|
||||
if ($msg->fftn_o->system->sessions->count())
|
||||
Notification::route('netmail',$msg->fftn_o)->notify(new AreafixNotification($msg));
|
||||
if ($mo->fftn->system->sessions->count())
|
||||
Notification::route('netmail',$mo->fftn)->notify(new AreafixNotification($mo));
|
||||
else
|
||||
Notification::route('netmail',$msg->fftn_o)->notify(new AreafixNotConfiguredHereNotification($msg));
|
||||
Notification::route('netmail',$mo->fftn)->notify(new AreafixNotConfiguredHereNotification($mo));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ namespace App\Classes\FTN\Process\Netmail;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\{Message,Process};
|
||||
use App\Classes\FTN\Process;
|
||||
use App\Models\{Echomail,Netmail};
|
||||
use App\Notifications\Netmails\Ping as PingNotification;
|
||||
|
||||
/**
|
||||
@ -17,14 +18,14 @@ final class Ping extends Process
|
||||
{
|
||||
private const LOGKEY = 'RP-';
|
||||
|
||||
public static function handle(Message $msg): bool
|
||||
public static function handle(Echomail|Netmail $mo): bool
|
||||
{
|
||||
if (strtolower($msg->user_to) !== 'ping')
|
||||
if (strtolower($mo->to) !== 'ping')
|
||||
return FALSE;
|
||||
|
||||
Log::info(sprintf('%s:- Processing PING message from (%s) [%s]',self::LOGKEY,$msg->user_from,$msg->fftn));
|
||||
Log::info(sprintf('%s:- Processing PING message from (%s) [%s]',self::LOGKEY,$mo->from,$mo->fftn->ftn));
|
||||
|
||||
Notification::route('netmail',$msg->fftn_o)->notify(new PingNotification($msg));
|
||||
Notification::route('netmail',$mo->fftn)->notify(new PingNotification($mo));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ final class Mail extends Send
|
||||
public function __get($key) {
|
||||
switch ($key) {
|
||||
case 'dbids':
|
||||
return $this->f->messages->pluck('dbid');
|
||||
return $this->f->messages->pluck('id');
|
||||
|
||||
case 'name':
|
||||
return sprintf('%08x',timew($this->youngest()));
|
||||
@ -111,7 +111,7 @@ final class Mail extends Send
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
public function youngest(): Carbon
|
||||
private function youngest(): Carbon
|
||||
{
|
||||
return $this->f->messages->pluck('date')->sort()->last();
|
||||
}
|
||||
|
@ -128,13 +128,12 @@ class Receive extends Base
|
||||
// If packet is greater than a size, lets queue it
|
||||
if ($this->queue || ($this->receiving->size > config('fido.queue_size',0))) {
|
||||
Log::info(sprintf('%s:- Packet [%s] will be sent to the queue for processing because its [%d] size, or queue forced',self::LOGKEY,$this->receiving->full_name,$this->receiving->size));
|
||||
PacketProcess::dispatch($this->receiving,$this->ao->withoutRelations(),$rcvd_time);
|
||||
|
||||
PacketProcess::dispatch($this->receiving->rel_name,$this->ao->zone->domain,FALSE,$rcvd_time);
|
||||
} else
|
||||
PacketProcess::dispatchSync($this->receiving,$this->ao->withoutRelations(),$rcvd_time);
|
||||
PacketProcess::dispatchSync($this->receiving->rel_name,$this->ao->zone->domain,TRUE,$rcvd_time);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error(sprintf('%s:! Got error dispatching packet [%s] (%d:%s-%s).',self::LOGKEY,$this->receiving->full_name,$e->getLine(),$e->getFile(),$e->getMessage()));
|
||||
Log::error(sprintf('%s:! Got error dispatching packet [%s] (%d:%s-%s).',self::LOGKEY,$this->receiving->rel_name,$e->getLine(),$e->getFile(),$e->getMessage()));
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -249,11 +249,10 @@ class Send extends Base
|
||||
* Add our mail to the send queue
|
||||
*
|
||||
* @param Address $ao
|
||||
* @param bool $update
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function mail(Address $ao,bool $update=TRUE): bool
|
||||
public function mail(Address $ao): bool
|
||||
{
|
||||
$mail = FALSE;
|
||||
|
||||
@ -265,7 +264,7 @@ class Send extends Base
|
||||
}
|
||||
|
||||
// Netmail
|
||||
if ($x=$ao->getNetmail($update)) {
|
||||
if ($x=$ao->getNetmail()) {
|
||||
Log::debug(sprintf('%s:- Netmail(s) added for sending to [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$this->list->push(new Mail($x,self::T_NETMAIL));
|
||||
@ -273,7 +272,7 @@ class Send extends Base
|
||||
}
|
||||
|
||||
// Echomail
|
||||
if ($x=$ao->getEchomail($update)) {
|
||||
if ($x=$ao->getEchomail()) {
|
||||
Log::debug(sprintf('%s:- Echomail(s) added for sending to [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$this->list->push(new Mail($x,self::T_ECHOMAIL));
|
||||
|
@ -11,6 +11,8 @@ use App\Classes\Sock\SocketClient;
|
||||
use App\Classes\Sock\SocketException;
|
||||
use App\Models\{Address,Mailer,Setup,System,SystemLog};
|
||||
|
||||
// @todo after receiving a mail packet/file, dont acknowledge it until we can validate that we can read it properly.
|
||||
|
||||
abstract class Protocol
|
||||
{
|
||||
// Enable extra debugging
|
||||
|
@ -696,8 +696,13 @@ final class Binkp extends BaseProtocol
|
||||
$this->node->ftn_other = $rem_aka;
|
||||
continue;
|
||||
|
||||
// If we only present limited AKAs dont validate password against akas outside of the domains we present
|
||||
} elseif (is_null(our_address($o))) {
|
||||
Log::alert(sprintf('%s:/ AKA domain [%s] is not in our domain(s) [%s] - ignoring',self::LOGKEY,$o->zone->domain->name,our_address()->pluck('zone.domain.name')->unique()->join(',')));
|
||||
continue;
|
||||
|
||||
} elseif (! $o->active) {
|
||||
Log::alert(sprintf('%s:/ AKA is not active [%s], ignoring',self::LOGKEY,$rem_aka));
|
||||
Log::alert(sprintf('%s:/ AKA is not active [%s] - ignoring',self::LOGKEY,$rem_aka));
|
||||
continue;
|
||||
|
||||
} else {
|
||||
@ -705,7 +710,7 @@ final class Binkp extends BaseProtocol
|
||||
}
|
||||
|
||||
} catch (InvalidFTNException $e) {
|
||||
Log::error(sprintf('%s:! AKA is INVALID [%s] (%s), ignoring',self::LOGKEY,$rem_aka,$e->getMessage()));
|
||||
Log::error(sprintf('%s:! AKA is INVALID [%s] (%s) - ignoring',self::LOGKEY,$rem_aka,$e->getMessage()));
|
||||
|
||||
continue;
|
||||
|
||||
@ -1004,6 +1009,9 @@ final class Binkp extends BaseProtocol
|
||||
|
||||
$this->send->close(TRUE,$this->node);
|
||||
}
|
||||
|
||||
} else {
|
||||
Log::error(sprintf('%s:! M_got[skip] not for our file? [%s]',self::LOGKEY,$buf));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -319,11 +319,23 @@ final class EMSI extends BaseProtocol implements CRCInterface,ZmodemInterface
|
||||
Log::debug(sprintf('%s: - Parsing AKA [%s]',self::LOGKEY,$rem_aka));
|
||||
|
||||
try {
|
||||
if (! ($o = Address::findFTN($rem_aka))) {
|
||||
if (! ($o = Address::findFTN($rem_aka,TRUE))) {
|
||||
Log::debug(sprintf('%s: ? AKA is UNKNOWN [%s]',self::LOGKEY,$rem_aka));
|
||||
|
||||
$this->node->ftn_other = $rem_aka;
|
||||
continue;
|
||||
|
||||
// If we only present limited AKAs dont validate password against akas outside of the domains we present
|
||||
} elseif (is_null(our_address($o))) {
|
||||
Log::alert(sprintf('%s:/ AKA domain [%s] is not in our domain(s) [%s] - ignoring',self::LOGKEY,$o->zone->domain->name,our_address()->pluck('zone.domain.name')->unique()->join(',')));
|
||||
continue;
|
||||
|
||||
} elseif (! $o->active) {
|
||||
Log::alert(sprintf('%s:/ AKA is not active [%s] - ignoring',self::LOGKEY,$rem_aka));
|
||||
continue;
|
||||
|
||||
} else {
|
||||
Log::info(sprintf('%s:- Got AKA [%s]',self::LOGKEY,$rem_aka));
|
||||
}
|
||||
|
||||
} catch (InvalidFTNException $e) {
|
||||
|
@ -50,8 +50,13 @@ class PacketAddress extends Command
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$o = $o->where('id',$this->argument('dbid'))->get();
|
||||
echo hex_dump($ao
|
||||
->system
|
||||
->packet($ao)
|
||||
->mail($o->where('id',$this->argument('dbid'))->get())
|
||||
->generate()
|
||||
);
|
||||
|
||||
dd(hex_dump($ao->getPacket($o)));
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ use Illuminate\Support\Facades\Storage;
|
||||
|
||||
use App\Classes\File;
|
||||
use App\Classes\FTN\Packet;
|
||||
use App\Models\Address;
|
||||
use App\Models\{Address,Echomail};
|
||||
|
||||
class PacketInfo extends Command
|
||||
{
|
||||
@ -31,7 +31,7 @@ class PacketInfo extends Command
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \App\Classes\FTN\InvalidPacketException
|
||||
* @throws \App\Exceptions\InvalidPacketException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
@ -55,27 +55,38 @@ class PacketInfo extends Command
|
||||
$this->alert(sprintf('File Name: %s',$x));
|
||||
|
||||
$this->info(sprintf('Packet Type : %s (%s)',$pkt->type,get_class($pkt)));
|
||||
$this->info(sprintf('From : %s to %s',$pkt->fftn,$pkt->tftn));
|
||||
$this->info(sprintf('Dated : %s (%s)',$pkt->date,$pkt->date->timestamp));
|
||||
$this->info(sprintf('Password : %s (%s)',$pkt->password,$pkt->password ? 'SET' : 'NOT set'));
|
||||
$this->info(sprintf('Messages : %d',$pkt->messages->count()));
|
||||
$this->info(sprintf('From : %s to %s',$pkt->fftn->ftn,$pkt->tftn->ftn));
|
||||
$this->info(sprintf('Dated : %s (%s) [%s]',$pkt->date,$pkt->date->timestamp,$pkt->date->tz->toOffsetName()));
|
||||
$this->info(sprintf('Password : %s (%s)',$pkt->password ?: '-',$pkt->password ? 'SET' : 'NOT set'));
|
||||
$this->info(sprintf('Messages : %d',$pkt->count()));
|
||||
$this->info(sprintf('Tosser : %d (%s) version %s',$pkt->software->code,$pkt->software->name,$pkt->software_ver));
|
||||
$this->info(sprintf('Capabilities: %x',$pkt->capability));
|
||||
$this->info(sprintf('Has Errors : %s',$pkt->errors->count() ? 'YES' : 'No'));
|
||||
$this->info(sprintf('Messages : %d',$pkt->count()));
|
||||
|
||||
foreach ($pkt as $msg) {
|
||||
try {
|
||||
$this->warn(sprintf('- Date : %s',$msg->date));
|
||||
$this->warn(sprintf(' - Flags : %s',$msg->flags()->filter()->keys()->join(', ')));
|
||||
$this->warn(sprintf(' - From : %s (%s)',$msg->user_from,$msg->fftn));
|
||||
$this->warn(sprintf(' - To : %s (%s)',$msg->user_to,$msg->tftn));
|
||||
$this->warn(sprintf(' - Subject: %s',$msg->subject));
|
||||
$this->warn(sprintf(' - Area : %s',$msg->echoarea));
|
||||
echo "\n";
|
||||
|
||||
if ($msg->errors)
|
||||
try {
|
||||
$this->warn(sprintf('- Date : %s (%s)',$msg->datetime,$msg->datetime->tz->toOffsetName()));
|
||||
$this->warn(sprintf(' - Errors : %s',$msg->errors?->errors()->count() ? 'YES' : 'No'));
|
||||
$this->warn(sprintf(' - Flags : %s',$msg->flags()->keys()->join(', ')));
|
||||
$this->warn(sprintf(' - Cost : %d',$msg->cost));
|
||||
$this->warn(sprintf(' - From : %s (%s)',$msg->from,$msg->fftn->ftn));
|
||||
if ($msg instanceof Echomail)
|
||||
$this->warn(sprintf(' - To : %s',$msg->to));
|
||||
else
|
||||
$this->warn(sprintf(' - To : %s (%s)',$msg->to,$msg->tftn->ftn));
|
||||
$this->warn(sprintf(' - Subject: %s',$msg->subject));
|
||||
if ($msg instanceof Echomail)
|
||||
$this->warn(sprintf(' - Area : %s',$msg->echoarea->name));
|
||||
|
||||
if ($msg->errors) {
|
||||
echo "\n";
|
||||
$this->error("Errors:");
|
||||
foreach ($msg->errors->errors()->all() as $error)
|
||||
$this->line(' - '.$error);
|
||||
$this->error(' - '.$error);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->error('! ERROR: '.$e->getMessage());
|
||||
@ -88,8 +99,8 @@ class PacketInfo extends Command
|
||||
foreach ($pkt->errors as $msg) {
|
||||
$this->error(sprintf('- Date: %s',$msg->date));
|
||||
$this->error(sprintf(' - FLAGS: %s',$msg->flags()->filter()->keys()->join(', ')));
|
||||
$this->error(sprintf(' - From: %s (%s)',$msg->user_from,$msg->fftn));
|
||||
$this->error(sprintf(' - To: %s (%s)',$msg->user_to,$msg->tftn));
|
||||
$this->error(sprintf(' - From: %s (%s)',$msg->from,$msg->fftn));
|
||||
$this->error(sprintf(' - To: %s (%s)',$msg->to,$msg->tftn));
|
||||
$this->error(sprintf(' - Subject: %s',$msg->subject));
|
||||
|
||||
foreach ($msg->errors->errors()->all() as $error)
|
||||
|
@ -2,15 +2,41 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
use App\Classes\File;
|
||||
use App\Classes\FTN\Packet;
|
||||
use App\Jobs\MessageProcess as Job;
|
||||
use App\Jobs\PacketProcess as Job;
|
||||
use App\Models\Address;
|
||||
|
||||
/**
|
||||
* Things to test
|
||||
* + Packet
|
||||
* - Sender doesnt exist (try and send a bounce message in the same session)
|
||||
* - Sender defined in DB by not ours
|
||||
* - Sender has wrong password
|
||||
* - Packet too old
|
||||
*
|
||||
* + Echomail
|
||||
* - Area doesnt exist (to uplink)
|
||||
* - Sender not subscribed (to uplink)
|
||||
* - Sender cannot post (to uplink)
|
||||
* - Sender has wrong address for echorea domain (to uplink)
|
||||
* - Test message in echoarea
|
||||
* - Echomail from address doesnt match packet envelope (to uplink)
|
||||
* - Echomail too old (to uplink)
|
||||
* - Rescanned dont generate notifications
|
||||
* - Rescanned dont trigger bots
|
||||
* - Some Notifications to an uplink should go to the admin instead?
|
||||
*
|
||||
* + Netmail
|
||||
* - To hub, and user not defined (reject)
|
||||
* - To hub, but user redirect (redirected)
|
||||
* - To areafix (processed)
|
||||
* - To ping (respond)
|
||||
* - With trace turned on (respond)
|
||||
*/
|
||||
class PacketProcess extends Command
|
||||
{
|
||||
/**
|
||||
@ -35,38 +61,29 @@ class PacketProcess extends Command
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
* @throws \App\Classes\FTN\InvalidPacketException
|
||||
* @throws \App\Exceptions\InvalidPacketException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$fs = Storage::disk(config('fido.local_disk'));
|
||||
//$fs = Storage::disk(config('fido.local_disk'));
|
||||
$rel_name = sprintf('%s/%s',config('fido.dir'),$this->argument('file'));
|
||||
|
||||
$f = new File($fs->path($rel_name));
|
||||
//$f = new File($fs->path($rel_name));
|
||||
|
||||
$m = [];
|
||||
if ($this->argument('ftn')) {
|
||||
$a = Address::findFTN($this->argument('ftn'));
|
||||
$ao = Address::findFTN($this->argument('ftn'));
|
||||
|
||||
} elseif (preg_match(sprintf('/^%s\.(.{3})$/',Packet::regex),$this->argument('file'),$m)) {
|
||||
$a = Address::findOrFail(hexdec($m[1]));
|
||||
$ao = Address::findOrFail(hexdec($m[1]));
|
||||
|
||||
} else {
|
||||
$this->error('Unable to determine sender FTN address');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
foreach ($f as $packet) {
|
||||
foreach ($pkt = Packet::process($packet,$f->itemName(),$f->itemSize(),$a?->zone->domain) as $msg) {
|
||||
// @todo Quick check that the packet should be processed by us.
|
||||
$this->info(sprintf('Processing message from [%s] with msgid [%s] in (%s)',$msg->fboss,$msg->msgid,$f->pktName()));
|
||||
Job::dispatchSync($rel_name,$ao->zone->domain,$this->option('dontqueue'));
|
||||
|
||||
// Dispatch job.
|
||||
if ($this->option('dontqueue'))
|
||||
Job::dispatchSync($msg,$f->pktName(),$a,$pkt->fftn_o,Carbon::now(),$this->option('nobot'));
|
||||
else
|
||||
Job::dispatch($msg,$f->pktName(),$a,$pkt->fftn_o,Carbon::now(),$this->option('nobot'));
|
||||
}
|
||||
}
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Models\System;
|
||||
use App\Models\Address;
|
||||
|
||||
class PacketSystem extends Command
|
||||
{
|
||||
@ -14,7 +14,7 @@ class PacketSystem extends Command
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'packet:system'
|
||||
.' {sid : System ID}';
|
||||
.' {ftn : System address}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@ -27,19 +27,19 @@ class PacketSystem extends Command
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \App\Classes\FTN\InvalidPacketException
|
||||
* @throws \App\Exceptions\InvalidPacketException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$so = System::findOrFail($this->argument('sid'));
|
||||
$ao = Address::findFTN($this->argument('ftn'));
|
||||
|
||||
foreach ($so->addresses as $ao) {
|
||||
$pkt = $ao->getEchomail(FALSE);
|
||||
foreach ($ao->system->addresses as $o) {
|
||||
$pkt = $o->getEchomail();
|
||||
$this->info(sprintf('System address [%s] has [%d] messages.',$ao->ftn,$pkt?->count()));
|
||||
|
||||
if ($pkt) {
|
||||
foreach ($pkt as $msg)
|
||||
$this->warn(sprintf('- %s',$msg->msgid));
|
||||
$this->warn(sprintf('- %s (%s)',$msg->msgid,$msg->id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\FTN;
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class NoReadSecurityException extends Exception
|
||||
{
|
||||
}
|
@ -3,7 +3,9 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -14,7 +16,7 @@ use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\ViewErrorBag;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Http\Requests\{AddressMerge,AreafixRequest,SystemRegister};
|
||||
use App\Http\Requests\{AddressMerge,AreafixRequest,SystemEchoareaRequest,SystemRegister,SystemSessionRequest};
|
||||
use App\Jobs\AddressPoll;
|
||||
use App\Models\{Address,Echoarea,Echomail,Filearea,Netmail,Setup,System,Zone};
|
||||
use App\Notifications\Netmails\AddressLink;
|
||||
@ -29,8 +31,6 @@ class SystemController extends Controller
|
||||
*/
|
||||
public function add_edit(SystemRegister $request,System $o)
|
||||
{
|
||||
$this->authorize('update',$o);
|
||||
|
||||
if ($request->post()) {
|
||||
foreach (['name','location','sysop','hold','phone','address','port','active','method','notes','zt_id','pkt_type','heartbeat'] as $key)
|
||||
$o->{$key} = $request->post($key);
|
||||
@ -694,30 +694,20 @@ class SystemController extends Controller
|
||||
/**
|
||||
* Update the systems echoareas
|
||||
*
|
||||
* @param Request $request
|
||||
* @param SystemEchoareaRequest $request
|
||||
* @param System $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function echoareas(Request $request,System $o)
|
||||
public function echoareas(SystemEchoareaRequest $request,System $o)
|
||||
{
|
||||
$ao = $o->addresses->firstWhere('id',$request->address_id);
|
||||
|
||||
if (($request->method() === 'POST') && $request->post()) {
|
||||
session()->flash('accordion','echoarea');
|
||||
|
||||
if ($ao->trashed() && collect($request->get('id'))->diff($ao->echoareas->pluck('id'))->count())
|
||||
return redirect()->back()->withErrors(sprintf('Address [%s] has been deleted, cannot add additional echos',$ao->ftn3d));
|
||||
|
||||
// Ensure we have session details for this address.
|
||||
if (! $ao->session('sespass'))
|
||||
return redirect()->back()->withErrors('System doesnt belong to this network');
|
||||
|
||||
$ao->echoareas()->syncWithPivotValues($request->get('id',[]),['subscribed'=>Carbon::now()]);
|
||||
if (($request->method() === 'POST') && $request->validated()) {
|
||||
$ao->echoareas()->syncWithPivotValues($request->validated('id',[]),['subscribed'=>Carbon::now()]);
|
||||
|
||||
return redirect()->back()->with('success','Echoareas updated');
|
||||
}
|
||||
|
||||
// @todo Allow a NC/RC/ZC to override
|
||||
$eo = Echoarea::active()
|
||||
->where('domain_id',$ao->zone->domain_id)
|
||||
->where(function($query) use ($ao) {
|
||||
@ -836,26 +826,14 @@ class SystemController extends Controller
|
||||
/**
|
||||
* Add Session details
|
||||
*
|
||||
* @param Request $request
|
||||
* @param SystemSessionRequest $request
|
||||
* @param System $o
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function session_add(Request $request,System $o)
|
||||
public function session_add(SystemSessionRequest $request,System $o)
|
||||
{
|
||||
// @todo This should be admin of the zone
|
||||
$this->authorize('update',$o);
|
||||
session()->flash('accordion','session');
|
||||
|
||||
$validate = $request->validate([
|
||||
'zone_id' => 'required|exists:zones,id',
|
||||
'sespass' => 'required|string|min:4',
|
||||
'pktpass' => 'required|string|min:4|max:8',
|
||||
'ticpass' => 'required|string|min:4',
|
||||
'fixpass' => 'required|string|min:4',
|
||||
]);
|
||||
|
||||
$zo = Zone::findOrFail($validate['zone_id']);
|
||||
$zo = Zone::findOrFail($request->zone_id);
|
||||
|
||||
/*
|
||||
// @todo Disabling this, it needs improvement. If the new node is the ZC it becomes the default for the zone (and therefore remove all defaults from other addresses in the same zone), otherwise default should be false
|
||||
@ -866,7 +844,7 @@ class SystemController extends Controller
|
||||
}
|
||||
*/
|
||||
|
||||
$o->sessions()->attach($zo,$validate);
|
||||
$o->sessions()->attach($zo,$request->validated());
|
||||
|
||||
return redirect()->to(sprintf('system/addedit/%d',$o->id));
|
||||
}
|
||||
@ -874,13 +852,14 @@ class SystemController extends Controller
|
||||
/**
|
||||
* Delete address assigned to a host
|
||||
*
|
||||
* @param Address $o
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
* @param System $o
|
||||
* @param Zone $zo
|
||||
* @return RedirectResponse
|
||||
* @throws AuthorizationException
|
||||
*/
|
||||
public function session_del(System $o,Zone $zo)
|
||||
{
|
||||
$this->authorize('admin',$zo);
|
||||
$this->authorize('update_nn',$o);
|
||||
session()->flash('accordion','session');
|
||||
|
||||
$o->sessions()->detach($zo);
|
||||
|
71
app/Http/Requests/SystemEchoareaRequest.php
Normal file
71
app/Http/Requests/SystemEchoareaRequest.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
use App\Models\Domain;
|
||||
|
||||
/**
|
||||
* Validation to register echoareas for a system
|
||||
* o = System::class
|
||||
*
|
||||
* @note This validation only expects to be used with POST
|
||||
* Variables:
|
||||
* + "address_id" => "address" // address_id that will receive the echos
|
||||
* + "domain_id" => "domain" // Of the echoareas
|
||||
* + "id" => array of IDs // The echos being subscribed (or if absent, are removed)
|
||||
*
|
||||
* Rules:
|
||||
* @see AddressAdd::class for description of authorisation
|
||||
*/
|
||||
class SystemEchoareaRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return request()->isMethod('get')
|
||||
|| Gate::allows('update_nn',$this->route('o'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(Request $request): array
|
||||
{
|
||||
if (request()->isMethod('get'))
|
||||
return [];
|
||||
|
||||
session()->flash('accordion','echoarea');
|
||||
return [
|
||||
'address_id'=>[
|
||||
'exists:addresses,id',
|
||||
// Make sure we have session details for the area
|
||||
function ($attribute,$value,$fail) use ($request) {
|
||||
$ao = request()->route('o')->addresses->firstWhere('id',$request->address_id);
|
||||
|
||||
if ((! $ao) || (! $ao->active) || (! $ao->system->zones->pluck('domain_id')->contains($request->domain_id)))
|
||||
$fail('Address must be ACTIVE, and have session details for the domain');
|
||||
},
|
||||
],
|
||||
'domain_id'=>'exists:domains,id',
|
||||
'id'=>[
|
||||
'array',
|
||||
'min:1',
|
||||
// Make sure the echoareas are in the domain
|
||||
function ($attribute,$value,$fail) use ($request) {
|
||||
$do = Domain::findOrFail($request->domain_id);
|
||||
|
||||
if ($do->echoareas->pluck('id')->intersect($value)->count() !== count($value))
|
||||
$fail('Some echaoreas dont exist in the domain?');
|
||||
},
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
@ -22,17 +22,14 @@ class SystemRegister extends FormRequest
|
||||
*/
|
||||
public function authorize(Request $request)
|
||||
{
|
||||
$this->so = new System;
|
||||
if (! $request->post())
|
||||
return TRUE;
|
||||
|
||||
if (is_numeric($request->name)) {
|
||||
$this->so = System::findOrNew($request->name);
|
||||
// Cannot claim this site
|
||||
if ($this->route('o')->id === Setup::findOrFail(config('app.id'))->system_id)
|
||||
return FALSE;
|
||||
|
||||
// Cannot claim this site
|
||||
if ($this->so->id === Setup::findOrFail(config('app.id'))->system_id)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return Gate::allows(is_numeric($request->name) && $this->so->users->count() ? 'update' : 'register',$this->so);
|
||||
return Gate::allows($this->route('o')->users->count() ? 'update_nn' : 'register',$this->route('o'));
|
||||
}
|
||||
|
||||
public function messages(): array
|
||||
|
35
app/Http/Requests/SystemSessionRequest.php
Normal file
35
app/Http/Requests/SystemSessionRequest.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class SystemSessionRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
session()->flash('accordion','session');
|
||||
return Gate::allows('update_nn',$this->route('o'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'zone_id' => 'required|exists:zones,id',
|
||||
'sespass' => 'required|string|min:4',
|
||||
'pktpass' => 'required|string|min:4|max:8',
|
||||
'ticpass' => 'required|string|min:4',
|
||||
'fixpass' => 'required|string|min:4',
|
||||
];
|
||||
}
|
||||
}
|
@ -8,13 +8,12 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Models\{Address,Echoarea,Echomail,Netmail,User};
|
||||
use App\Notifications\Netmails\{EchoareaNotExist,EchoareaNotSubscribed,EchoareaNoWrite,NetmailForward,Reject};
|
||||
use App\Models\{Echomail,Netmail,User};
|
||||
use App\Notifications\Netmails\{EchoareaNotExist,EchoareaNotSubscribed,EchoareaNoWrite,NetmailForward,NetmailHubNoUser};
|
||||
use App\Traits\ParseAddresses;
|
||||
|
||||
class MessageProcess implements ShouldQueue
|
||||
@ -23,20 +22,19 @@ class MessageProcess implements ShouldQueue
|
||||
|
||||
use Dispatchable,InteractsWithQueue,Queueable,SerializesModels,ParseAddresses;
|
||||
|
||||
private Address $sender;
|
||||
private Message $msg;
|
||||
private Address $pktsrc;
|
||||
private Carbon $recvtime;
|
||||
private Echomail|Netmail|string $mo;
|
||||
private bool $skipbot;
|
||||
private string $packet;
|
||||
|
||||
public function __construct(Message $msg,string $packet,Address $sender,Address $pktsrc,Carbon $recvtime,bool $skipbot=FALSE)
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$this->msg = $msg;
|
||||
$this->packet = $packet;
|
||||
$this->sender = $sender;
|
||||
$this->pktsrc = $pktsrc;
|
||||
$this->recvtime = $recvtime;
|
||||
// @todo We need to serialize this model here, because laravel has an error unserializing it (Model Not Found)
|
||||
$this->mo = serialize($mo);
|
||||
$this->skipbot = $skipbot;
|
||||
}
|
||||
|
||||
@ -44,7 +42,7 @@ class MessageProcess implements ShouldQueue
|
||||
{
|
||||
switch ($key) {
|
||||
case 'subject':
|
||||
return sprintf('%s-%s-%s',$this->packet,$this->sender->ftn,$this->msg->msgid);
|
||||
return sprintf('%s-%s-%s',$this->pktname,$this->mo->set->get('set_sender')->ftn,$this->mo->msgid);
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
@ -52,21 +50,25 @@ class MessageProcess implements ShouldQueue
|
||||
}
|
||||
|
||||
/**
|
||||
* When calling MessageProcess - we assume that the packet is from a valid source, and
|
||||
* the destination (netmail/echomail) is also valid
|
||||
* 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($this->mo);
|
||||
|
||||
// Load our details
|
||||
$ftns = our_address();
|
||||
|
||||
// If we are a netmail
|
||||
if ($this->msg->isNetmail()) {
|
||||
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->msg->msgid,
|
||||
$this->msg->user_to,$this->msg->tftn,
|
||||
$this->msg->user_from,$this->msg->fftn,
|
||||
$this->mo->msgid,
|
||||
$this->mo->to,$this->mo->tftn->ftn,
|
||||
$this->mo->from,$this->mo->fftn->ftn,
|
||||
));
|
||||
|
||||
// @todo Enable checks to reject old messages
|
||||
@ -74,89 +76,51 @@ class MessageProcess implements ShouldQueue
|
||||
// Check for duplicate messages
|
||||
|
||||
// FTS-0009.001
|
||||
if ($this->msg->msgid) {
|
||||
$o = Netmail::where('msgid',$this->msg->msgid)
|
||||
->where('fftn_id',($x=$this->msg->fboss_o) ? $x->id : NULL)
|
||||
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();
|
||||
|
||||
Log::debug(sprintf('%s:- Checking for duplicate from host id [%d].',self::LOGKEY,($x=$this->msg->fboss_o) ? $x->id : NULL));
|
||||
|
||||
if ($o) {
|
||||
Log::alert(sprintf('%s:! Duplicate netmail [%s] in [%s] from (%s) [%s] to (%s) - ignorning.',
|
||||
Log::alert(sprintf('%s:! Duplicate netmail #%d [%s] from (%s) [%s] to (%s) - ignoring.',
|
||||
self::LOGKEY,
|
||||
$this->msg->msgid,
|
||||
$this->msg->echoarea,
|
||||
$this->msg->user_from,$this->msg->fftn,
|
||||
$this->msg->user_to,
|
||||
$o->id,
|
||||
$this->mo->msgid,
|
||||
$this->mo->from,$this->mo->fftn->ftn,
|
||||
$this->mo->to,
|
||||
));
|
||||
|
||||
if (! $o->msg_crc)
|
||||
$o->msg_crc = md5($this->msg->message);
|
||||
|
||||
$o->save();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// @todo Enable checks to see if this is a file request or file send
|
||||
|
||||
$o = new Netmail;
|
||||
$o->to = $this->msg->user_to;
|
||||
$o->from = $this->msg->user_from;
|
||||
|
||||
$o->fftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL;
|
||||
$o->tftn_id = ($x=$this->msg->tftn_o) ? $x->id : NULL;
|
||||
|
||||
$o->datetime = $this->msg->date;
|
||||
$o->tzoffset = $this->msg->date->utcOffset();
|
||||
|
||||
$o->flags = $this->msg->flags;
|
||||
$o->cost = $this->msg->cost;
|
||||
$o->msgid = $this->msg->msgid;
|
||||
|
||||
$o->tagline = $this->msg->tagline;
|
||||
$o->tearline = $this->msg->tearline;
|
||||
$o->origin = $this->msg->origin;
|
||||
|
||||
$o->subject = $this->msg->subject;
|
||||
$o->msg = $this->msg->message_src."\r";
|
||||
|
||||
foreach ($this->msg->via as $v)
|
||||
$o->msg .= sprintf("\01Via %s\r",$v);
|
||||
|
||||
$o->msg_src = $this->msg->message_src;
|
||||
$o->msg_crc = md5($this->msg->message);
|
||||
|
||||
$o->set_pkt = $this->packet;
|
||||
$o->set_sender = $this->sender;
|
||||
$o->set_path = $this->msg->via;
|
||||
$o->set_recvtime = $this->recvtime;
|
||||
// Strip any local/transit flags
|
||||
$o->flags &= ~(Message::FLAG_LOCAL|Message::FLAG_INTRANSIT);
|
||||
$this->mo->flags &= ~(Message::FLAG_LOCAL|Message::FLAG_INTRANSIT);
|
||||
|
||||
// Determine if the message is to this system, or in transit
|
||||
if ($ftns->search(function($item) { return $this->msg->tftn === $item->ftn; }) !== FALSE) {
|
||||
// @todo Check if it is a duplicate message
|
||||
// @todo Check if the message is from a system we know about
|
||||
|
||||
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->msg)) {
|
||||
$o->flags |= Message::FLAG_RECD;
|
||||
$o->save();
|
||||
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->msg->msgid,
|
||||
$this->msg->user_from,
|
||||
$this->msg->fftn,
|
||||
$o->id,
|
||||
$this->mo->msgid,
|
||||
$this->mo->from,
|
||||
$this->mo->fftn->ftn,
|
||||
$this->mo->id,
|
||||
));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -165,38 +129,40 @@ class MessageProcess implements ShouldQueue
|
||||
// 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($this->msg->user_to)))
|
||||
->orWhereRaw(sprintf("LOWER(alias)='%s'",strtolower($this->msg->user_to)));
|
||||
return $query->whereRaw(sprintf("LOWER(name)='%s'",strtolower($this->mo->to)))
|
||||
->orWhereRaw(sprintf("LOWER(alias)='%s'",strtolower($this->mo->to)));
|
||||
})
|
||||
->whereNotNull('system_id')
|
||||
->single();
|
||||
|
||||
if ($uo && ($ao=$uo->system->match($this->msg->tftn_o->zone)?->pop())) {
|
||||
if ($uo && ($ao=$uo->system->match($this->mo->tftn->zone)?->pop())) {
|
||||
$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->msg->tftn_o->ftn);
|
||||
$note .= sprintf("+ at [%s]\r",$this->mo->tftn->ftn);
|
||||
$note .= "+---------------------------------------------------------+\r\r";
|
||||
$o->msg = $note.$this->msg->message;
|
||||
$o->tftn_id = $ao->id;
|
||||
$o->flags |= Message::FLAG_INTRANSIT;
|
||||
$o->save();
|
||||
|
||||
$this->mo->msg = $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->msg->user_from),config('fido.areabots')))
|
||||
Notification::route('netmail',$this->msg->fftn_o)->notify(new NetmailForward($this->msg,$ao));
|
||||
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->msg->user_from),config('fido.areabots'))) {
|
||||
$o->flags |= Message::FLAG_RECD;
|
||||
$o->save();
|
||||
} 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->msg->msgid,
|
||||
$this->msg->user_from,
|
||||
$this->msg->fftn,
|
||||
$o->id,
|
||||
$this->mo->msgid,
|
||||
$this->mo->from,
|
||||
$this->mo->fftn->ftn,
|
||||
$this->mo->id,
|
||||
));
|
||||
|
||||
$processed = TRUE;
|
||||
@ -205,99 +171,87 @@ class MessageProcess implements ShouldQueue
|
||||
|
||||
// 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->msg->user_from,$this->msg->fftn));
|
||||
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->msg->fftn_o)->notify(new Reject($this->msg));
|
||||
Notification::route('netmail',$this->mo->fftn)->notify(new NetmailHubNoUser($this->mo));
|
||||
}
|
||||
|
||||
// If in transit, store for collection
|
||||
} else {
|
||||
// @todo Check if the message is to a system we know about
|
||||
// @todo In transit loop checking
|
||||
// @todo In transit TRACE response
|
||||
|
||||
$o->flags |= Message::FLAG_INTRANSIT;
|
||||
$o->save();
|
||||
$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->msg->msgid,
|
||||
$this->msg->user_to,$this->msg->tftn,
|
||||
$this->msg->user_from,$this->msg->fftn,
|
||||
$o->id,
|
||||
$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 {
|
||||
Log::debug(sprintf('%s:- Looking for echomail area [%s] for mail from [%s]',self::LOGKEY,$this->msg->echoarea,$this->msg->fboss));
|
||||
// The packet sender
|
||||
$sender = $this->mo->set->get('set_sender');
|
||||
|
||||
if (! $this->msg->fboss_o) {
|
||||
Log::error(sprintf('%s:! Cannot process message for echomail area [%s] for mail from [%s] with msgid [%s] - no boss object?',self::LOGKEY,$this->msg->echoarea,$this->msg->fboss,$this->msg->msgid));
|
||||
// @todo Check that this does evaulate 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;
|
||||
}
|
||||
|
||||
$ea = Echoarea::where('name',strtoupper($this->msg->echoarea))
|
||||
->where('domain_id',$this->msg->fboss_o->zone->domain_id)
|
||||
->single();
|
||||
Log::debug(sprintf('%s:- Processing echomail [%s] in [%s] from [%s].',self::LOGKEY,$this->mo->msgid,$this->mo->echoarea->name,$sender->ftn));
|
||||
|
||||
if (! $ea) {
|
||||
Log::alert(sprintf('%s:! Echoarea [%s] doesnt exist for zone [%d-%d]',self::LOGKEY,$this->msg->echoarea,$this->msg->fboss_o->zone->domain_id,$this->msg->fboss_o->zone->zone_id));
|
||||
|
||||
Notification::route('netmail',$this->pktsrc)->notify(new EchoareaNotExist($this->msg));
|
||||
return;
|
||||
}
|
||||
|
||||
Log::debug(sprintf('%s:- Processing echomail [%s] in [%s].',self::LOGKEY,$this->msg->msgid,$this->msg->echoarea));
|
||||
|
||||
if (! $this->pktsrc->zone->domain->zones->pluck('zone_id')->contains($this->msg->fboss_o->zone->zone_id)) {
|
||||
// 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->msg->msgid,
|
||||
$this->msg->fboss_o->zone->zone_id,
|
||||
$this->pktsrc->zone->zone_id));
|
||||
$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->msg->msgid) {
|
||||
$o = Echomail::where('msgid',$this->msg->msgid)
|
||||
->where('fftn_id',($x=$this->msg->fboss_o) ? $x->id : NULL)
|
||||
->where('datetime','>=',$this->msg->date->subYears(3))
|
||||
->where('datetime','<=',$this->msg->date)
|
||||
if ($this->mo->msgid) {
|
||||
$o = Echomail::where('msgid',$this->mo->msgid)
|
||||
->where('fftn_id',$this->mo->fftn->id)
|
||||
->where('datetime','>=',$this->mo->date->subYears(3))
|
||||
->where('datetime','<=',$this->mo->date)
|
||||
->single();
|
||||
|
||||
Log::debug(sprintf('%s:- Checking for duplicate from host id [%d].',self::LOGKEY,($x=$this->msg->fboss_o) ? $x->id : NULL));
|
||||
Log::debug(sprintf('%s:- Checking for duplicate from host id [%d].',self::LOGKEY,$this->mo->fftn->id));
|
||||
|
||||
if ($o) {
|
||||
// @todo Actually update seenby
|
||||
Log::alert(sprintf('%s:! Duplicate echomail [%s] in [%s] from (%s) [%s] to (%s) - updating seenby.',
|
||||
self::LOGKEY,
|
||||
$this->msg->msgid,
|
||||
$this->msg->echoarea,
|
||||
$this->msg->user_from,$this->msg->fftn,
|
||||
$this->msg->user_to,
|
||||
$this->mo->msgid,
|
||||
$this->mo->echoarea->name,
|
||||
$this->mo->from,$this->mo->fftn->ftn,
|
||||
$this->mo->to,
|
||||
));
|
||||
|
||||
if (! $o->msg_crc)
|
||||
$o->msg_crc = md5($this->msg->message);
|
||||
|
||||
$o->save();
|
||||
//$o->save();
|
||||
|
||||
// @todo This duplicate message may have gone via a different path, be nice to record it.
|
||||
|
||||
/*
|
||||
// If we didnt get the path on the original message, we'll override it
|
||||
if (! $o->path->count()) {
|
||||
$dummy = collect();
|
||||
$path = $this->parseAddresses('path',$this->msg->path,$this->pktsrc->zone,$dummy);
|
||||
|
||||
/*
|
||||
// If our sender is not in the path, add it
|
||||
if (! $path->contains($this->sender->id)) {
|
||||
Log::alert(sprintf('%s:? Echomail adding sender to PATH [%s] for [%d].',self::LOGKEY,$x->ftn,$o->id));
|
||||
$path->push($this->sender->id);
|
||||
}
|
||||
*/
|
||||
$path = $this->parseAddresses('path',$this->mo->path,$sender->zone,$dummy);
|
||||
|
||||
$ppoid = NULL;
|
||||
foreach ($path as $aoid) {
|
||||
@ -310,23 +264,24 @@ class MessageProcess implements ShouldQueue
|
||||
$ppoid = $po[0]->id;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// @todo if we have an export for any of the seenby addresses, remove it
|
||||
$seenby = $this->parseAddresses('seenby',$this->msg->seenby,$this->pktsrc->zone,$o->rogue_seenby);
|
||||
$x = $o->seenby()->syncWithoutDetaching($seenby);
|
||||
|
||||
//$seenby = $this->parseAddresses('seenby',$this->mo->seenby,$sender->zone,$o->rogue_seenby);
|
||||
//$this->mo->seenby()->syncWithoutDetaching($seenby);
|
||||
|
||||
// In case our rogue_seenby changed
|
||||
if ($o->getDirty())
|
||||
$o->save();
|
||||
//$this->mo->save();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Find another message with the same msg_crc
|
||||
if ($this->msg->message) {
|
||||
$o = Echomail::where('msg_crc',$xx=md5($this->msg->message))
|
||||
->where('fftn_id',($x=$this->msg->fboss_o) ? $x->id : NULL)
|
||||
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();
|
||||
|
||||
@ -338,74 +293,39 @@ class MessageProcess implements ShouldQueue
|
||||
));
|
||||
}
|
||||
|
||||
// If the node is not subscribed
|
||||
if ($this->pktsrc->echoareas->search(function($item) use ($ea) { return $item->id === $ea->id; }) === FALSE) {
|
||||
Log::alert(sprintf('%s:! FTN [%s] is not subscribed to [%s] for [%s].',self::LOGKEY,$this->pktsrc->ftn,$ea->name,$this->msg->msgid));
|
||||
|
||||
if (! $this->msg->rescanned->count())
|
||||
Notification::route('netmail',$this->pktsrc)->notify(new EchoareaNotSubscribed($this->msg));
|
||||
}
|
||||
|
||||
// Can the system send messages to this area?
|
||||
if (! $ea->can_write($this->pktsrc->security)) {
|
||||
Log::alert(sprintf('%s:! FTN [%s] is not allowed to post [%s] to [%s].',self::LOGKEY,$this->pktsrc->ftn,$this->msg->msgid,$ea->name));
|
||||
if (! $this->msg->rescanned->count())
|
||||
Notification::route('netmail',$this->pktsrc)->notify(new EchoareaNoWrite($this->msg));
|
||||
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;
|
||||
}
|
||||
|
||||
// We know about this area, store it
|
||||
$o = new Echomail;
|
||||
$o->init();
|
||||
// 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));
|
||||
|
||||
$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();
|
||||
|
||||
if ($x=$this->msg->fboss_o) {
|
||||
$o->fftn_id = $x->id;
|
||||
|
||||
} else {
|
||||
$o->fftn_id = NULL; // @todo This should be the node that originated the message - but since that node is not in the DB it would be null
|
||||
if (! $rescanned)
|
||||
Notification::route('netmail',$sender)->notify(new EchoareaNotSubscribed($this->mo));
|
||||
}
|
||||
|
||||
$o->echoarea_id = $ea->id;
|
||||
$o->msgid = $this->msg->msgid;
|
||||
$o->replyid = $this->msg->replyid;
|
||||
|
||||
$o->tagline = $this->msg->tagline;
|
||||
$o->tearline = $this->msg->tearline;
|
||||
$o->origin = $this->msg->origin;
|
||||
|
||||
$o->msg = $this->msg->message_src."\r";
|
||||
$o->msg_src = $this->msg->message_src;
|
||||
$o->msg_crc = md5($this->msg->message);
|
||||
|
||||
$o->set_path = $this->msg->path;
|
||||
$o->set_seenby = $this->msg->seenby;
|
||||
$o->set_recvtime = $this->recvtime;
|
||||
$o->set_sender = $this->pktsrc->id;
|
||||
// Record receiving packet and sender
|
||||
$o->set_pkt = $this->packet;
|
||||
|
||||
$o->save();
|
||||
// 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->msg->msgid,
|
||||
$this->msg->echoarea,
|
||||
$this->msg->user_from,$this->msg->fftn,
|
||||
$this->msg->user_to,
|
||||
$o->id,
|
||||
$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) && (! $this->msg->rescanned->count()))
|
||||
if ((! $this->skipbot) && (! $rescanned))
|
||||
foreach (config('process.echomail') as $class) {
|
||||
if ($class::handle($this->msg)) {
|
||||
if ($class::handle($this->mo)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,9 @@ use Illuminate\Support\Facades\Storage;
|
||||
use League\Flysystem\UnableToMoveFile;
|
||||
|
||||
use App\Classes\File;
|
||||
use App\Classes\File\Item;
|
||||
use App\Classes\FTN\{InvalidPacketException,Packet};
|
||||
use App\Models\Address;
|
||||
use App\Classes\FTN\Packet;
|
||||
use App\Exceptions\InvalidPacketException;
|
||||
use App\Models\{Domain,Echomail,Netmail};
|
||||
use App\Notifications\Netmails\PacketPasswordInvalid;
|
||||
|
||||
class PacketProcess implements ShouldQueue
|
||||
@ -26,22 +26,26 @@ class PacketProcess implements ShouldQueue
|
||||
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private Item $file;
|
||||
private Address $ao;
|
||||
private string $filename;
|
||||
private Domain $do;
|
||||
private Carbon $rcvd_time;
|
||||
private bool $interactive;
|
||||
private bool $nobot;
|
||||
|
||||
public function __construct(Item $file,Address $ao,Carbon $rcvd_time)
|
||||
public function __construct(string $filename,Domain $do,bool $interactive=TRUE,Carbon $rcvd_time=NULL,bool $nobot=FALSE)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->ao = $ao;
|
||||
$this->rcvd_time = $rcvd_time;
|
||||
$this->filename = $filename;
|
||||
$this->do = $do;
|
||||
$this->interactive = $interactive;
|
||||
$this->rcvd_time = $rcvd_time ?: Carbon::now();
|
||||
$this->nobot = $nobot;
|
||||
}
|
||||
|
||||
public function __get($key): mixed
|
||||
{
|
||||
switch ($key) {
|
||||
case 'subject':
|
||||
return $this->file->name;
|
||||
return $this->filename;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
@ -54,30 +58,47 @@ class PacketProcess implements ShouldQueue
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Log::info(sprintf('%s:- Processing mail %s [%s]',self::LOGKEY,$this->file->whatType() === Item::IS_PKT ? 'PACKET' : 'ARCHIVE',$this->file->nameas));
|
||||
Log::info(sprintf('%s:- Processing mail [%s]',self::LOGKEY,$this->filename));
|
||||
|
||||
$fs = Storage::disk(config('fido.local_disk'));
|
||||
|
||||
// @todo Catch files that we cannot process, eg: ARJ bundles.
|
||||
try {
|
||||
$f = new File($this->file->full_name);
|
||||
$f = new File($fs->path($this->filename));
|
||||
|
||||
$processed = FALSE;
|
||||
|
||||
foreach ($f as $packet) {
|
||||
$pkt = Packet::process($packet,Arr::get(stream_get_meta_data($packet),'uri'),$f->itemSize(),$this->ao->zone->domain);
|
||||
$pkt = Packet::process($packet,Arr::get(stream_get_meta_data($packet),'uri'),$f->itemSize(),$this->do);
|
||||
|
||||
// Check the messages are from the uplink
|
||||
if ($this->ao->system->addresses->search(function($item) use ($pkt) { return $item->id === $pkt->fftn_o->id; }) === FALSE) {
|
||||
Log::error(sprintf('%s:! Packet [%s] is not from this link? [%d]',self::LOGKEY,$pkt->fftn_o->ftn,$this->ao->system_id));
|
||||
// Check that the packet is from a system that is defined in the DB
|
||||
if (! $pkt->fftn) {
|
||||
Log::error(sprintf('%s:! Packet [%s] is not from a system we know about? [%s]',self::LOGKEY,$this->filename,$pkt->fftn_t));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Check the packet password
|
||||
if (strtoupper($this->ao->session('pktpass')) !== strtoupper($pkt->password)) {
|
||||
Log::error(sprintf('%s:! Packet from [%s] with password [%s] is invalid.',self::LOGKEY,$this->ao->ftn,$pkt->password));
|
||||
if (! our_nodes($this->do)->contains($pkt->fftn)) {
|
||||
Log::error(sprintf('%s:! Packet [%s] is from a system that is not configured with us? [%s] for [%s]',self::LOGKEY,$this->filename,$pkt->fftn_t,$this->do->name));
|
||||
|
||||
Notification::route('netmail',$this->ao)->notify(new PacketPasswordInvalid($pkt->password,$this->file->nameas));
|
||||
// @todo Notification::route('netmail',$pkt->fftn)->notify(new UnexpectedPacketFromYou($this->filename));
|
||||
// @todo Parse the packet for netmails and process them. We'll only accept netmails to us, and ignore all others
|
||||
break;
|
||||
}
|
||||
|
||||
// Check the packet is to our address, if not we'll reject it.
|
||||
if (! our_address($this->do)->contains($pkt->tftn)) {
|
||||
Log::error(sprintf('%s:! Packet [%s] is not to our address? [%s]',self::LOGKEY,$this->filename,$pkt->tftn));
|
||||
|
||||
// @todo Notification::route('netmail',$pkt->fftn)->notify(new UnexpectedPacketToUs($this->filename));
|
||||
break;
|
||||
}
|
||||
|
||||
// Check the packet password
|
||||
if (strtoupper($pkt->fftn->session('pktpass')) !== strtoupper($pkt->password)) {
|
||||
Log::error(sprintf('%s:! Packet from [%s] with password [%s] is invalid.',self::LOGKEY,$pkt->fftn->ftn,$pkt->password));
|
||||
|
||||
Notification::route('netmail',$pkt->fftn)->notify(new PacketPasswordInvalid($pkt->password,$f->pktName()));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -89,37 +110,37 @@ class PacketProcess implements ShouldQueue
|
||||
|
||||
$count = 0;
|
||||
foreach ($pkt as $msg) {
|
||||
Log::info(sprintf('%s:- Mail from [%s] to [%s]',self::LOGKEY,$msg->fftn,$msg->tftn));
|
||||
if ($msg instanceof Netmail)
|
||||
Log::info(sprintf('%s:- Netmail from [%s] to [%s]',self::LOGKEY,$msg->fftn->ftn,$msg->tftn->ftn));
|
||||
elseif ($msg instanceof Echomail)
|
||||
Log::info(sprintf('%s:- Echomail from [%s]',self::LOGKEY,$msg->fftn->ftn));
|
||||
|
||||
// @todo Quick check that the packet should be processed by us.
|
||||
// @todo validate that the packet's zone is in the domain.
|
||||
if ($msg->errors) {
|
||||
Log::error(sprintf('%s:! Message [%s] has [%d] errors, unable to process',self::LOGKEY,$msg->msgid,$msg->errors->errors()->count()));
|
||||
|
||||
/*
|
||||
* // @todo generate exception when echomail for an area that doesnt exist
|
||||
* // @todo generate exception when echomail for an area sender cannot post to
|
||||
* // @todo generate exception when echomail for an area sender not subscribed to
|
||||
* // @todo generate exception when echomail comes from a system not defined here
|
||||
* // @todo generate exception when echomail comes from a system doesnt exist
|
||||
*
|
||||
* // @todo generate exception when netmail to system that doesnt exist (node/point)
|
||||
* // @todo generate exception when netmail from system that doesnt exist (node/point)
|
||||
* // @todo generate warning when netmail comes from a system not defined here
|
||||
*
|
||||
* // @todo generate exception when packet has wrong password
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
$msg->set_sender = $pkt->fftn->withoutRelations();
|
||||
// Record receiving packet and sender
|
||||
$msg->set_pkt = $f->pktName();
|
||||
$msg->set_recvtime = $this->rcvd_time;
|
||||
|
||||
if ($queue || (! $this->interactive))
|
||||
Log::info(sprintf('%s:! Message [%s] will be sent to the queue to process',self::LOGKEY,$msg->msgid));
|
||||
|
||||
try {
|
||||
// Dispatch job.
|
||||
if ($queue)
|
||||
MessageProcess::dispatch($msg,$f->pktName(),$this->ao->withoutRelations(),$pkt->fftn_o->withoutRelations(),$this->rcvd_time);
|
||||
if ($queue || (! $this->interactive))
|
||||
MessageProcess::dispatch($msg->withoutRelations(),$this->nobot);
|
||||
else
|
||||
MessageProcess::dispatchSync($msg,$f->pktName(),$this->ao->withoutRelations(),$pkt->fftn_o->withoutRelations(),$this->rcvd_time);
|
||||
MessageProcess::dispatchSync($msg->withoutRelations(),$this->nobot);
|
||||
|
||||
$count++;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error(sprintf('%s:! Got error dispatching message [%s] (%d:%s-%s).',self::LOGKEY,$msg->msgid,$e->getLine(),$e->getFile(),$e->getMessage()));
|
||||
}
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
if ($count === $pkt->count())
|
||||
@ -127,42 +148,41 @@ class PacketProcess implements ShouldQueue
|
||||
}
|
||||
|
||||
if (! $processed) {
|
||||
Log::alert(sprintf('%s:- Not deleting packet [%s], it doesnt seem to be processed?',self::LOGKEY,$this->file->nameas));
|
||||
Log::alert(sprintf('%s:- Not deleting packet [%s], it doesnt seem to be processed?',self::LOGKEY,$this->filename));
|
||||
|
||||
} else {
|
||||
// If we want to keep the packet, we could do that logic here
|
||||
if (config('fido.packet_keep')) {
|
||||
$dir = sprintf('%s/%s/%s/%s',config('fido.dir'),($x=Carbon::now())->format('Y'),$x->format('m'),$x->format('d'));
|
||||
Log::debug(sprintf('%s:- Moving processed packet [%s] to [%s]',self::LOGKEY,$this->file->rel_name,$dir));
|
||||
Log::debug(sprintf('%s:- Moving processed packet [%s] to [%s]',self::LOGKEY,$this->filename,$dir));
|
||||
|
||||
try {
|
||||
if ($fs->makeDirectory($dir)) {
|
||||
$fs->move($this->file->rel_name,$x=sprintf('%s/%s',$dir,$this->file->pref_name));
|
||||
Log::info(sprintf('%s:- Moved processed packet [%s] to [%s]',self::LOGKEY,$this->file->rel_name,$x));
|
||||
$fs->move($this->filename,$x=sprintf('%s/%s',$dir,$f->itemName()));
|
||||
Log::info(sprintf('%s:- Moved processed packet [%s] to [%s]',self::LOGKEY,$this->filename,$x));
|
||||
|
||||
} else
|
||||
Log::error(sprintf('%s:! Unable to create dir [%s]',self::LOGKEY,$dir));
|
||||
|
||||
} catch (UnableToMoveFile $e) {
|
||||
Log::error(sprintf('%s:! Unable to move packet [%s] to [%s] (%s)',self::LOGKEY,$this->file->full_name,$dir,$e->getMessage()));
|
||||
Log::error(sprintf('%s:! Unable to move packet [%s] to [%s] (%s)',self::LOGKEY,$this->filename,$dir,$e->getMessage()));
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error(sprintf('%s:! Failed moving packet [%s] to [%s] (%s)',self::LOGKEY,$this->file->full_name,$dir,$e->getMessage()));
|
||||
Log::error(sprintf('%s:! Failed moving packet [%s] to [%s] (%s)',self::LOGKEY,$this->filename,$dir,$e->getMessage()));
|
||||
}
|
||||
|
||||
} else {
|
||||
Log::debug(sprintf('%s:- Deleting processed packet [%s]',self::LOGKEY,$this->file->full_name));
|
||||
Log::debug(sprintf('%s:- Deleting processed packet [%s]',self::LOGKEY,$this->filename));
|
||||
|
||||
// @todo Change this to use Storage::disk()
|
||||
unlink($this->file->full_name);
|
||||
$fs->delete($this->filename);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (InvalidPacketException $e) {
|
||||
Log::error(sprintf('%s:- Not deleting packet [%s], as it generated an InvalidPacketException',self::LOGKEY,$this->file->nameas),['e'=>$e->getMessage()]);
|
||||
Log::error(sprintf('%s:- Not deleting packet [%s], as it generated an InvalidPacketException',self::LOGKEY,$this->filename),['e'=>$e->getMessage()]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error(sprintf('%s:- Not deleting packet [%s], as it generated an uncaught exception',self::LOGKEY,$this->file->nameas),['e'=>$e->getMessage()]);
|
||||
Log::error(sprintf('%s:- Not deleting packet [%s], as it generated an uncaught exception',self::LOGKEY,$this->filename),['e'=>$e->getMessage(),'l'=>$e->getLine(),'f'=>$e->getFile()]);
|
||||
}
|
||||
}
|
||||
}
|
@ -978,47 +978,26 @@ class Address extends Model
|
||||
/**
|
||||
* Get echomail for this node
|
||||
*
|
||||
* @param bool $update
|
||||
* @param Collection|null $echomail
|
||||
* @return Packet|null
|
||||
* @throws \Exception
|
||||
* @todo If we export to uplink hubs without our address in the seenby, they should send the message back to
|
||||
* us with their seenby's.
|
||||
*/
|
||||
public function getEchomail(bool $update=TRUE,Collection $echomail=NULL): ?Packet
|
||||
public function getEchomail(): ?Packet
|
||||
{
|
||||
$pkt = NULL;
|
||||
if ($echomail)
|
||||
return $this->getPacket($echomail);
|
||||
if (($num=$this->echomailWaiting())->count()) {
|
||||
$s = Setup::findOrFail(config('app.id'));
|
||||
|
||||
$s = Setup::findOrFail(config('app.id'));
|
||||
|
||||
$num = self::UncollectedEchomail()
|
||||
->select('echomails.id')
|
||||
->where('addresses.id',$this->id)
|
||||
->groupBy(['echomails.id'])
|
||||
->get();
|
||||
|
||||
if ($num->count()) {
|
||||
// Limit to max messages
|
||||
Log::info(sprintf('%s:= Got [%d] echomails for [%s] for sending',self::LOGKEY,$num->count(),$this->ftn));
|
||||
|
||||
// Limit to max messages
|
||||
if ($num->count() > $s->msgs_pkt)
|
||||
Log::notice(sprintf('%s:= Only sending [%d] echomails for [%s]',self::LOGKEY,$s->msgs_pkt,$this->ftn));
|
||||
|
||||
$x = $this->echomailWaiting($s->msgs_pkt);
|
||||
$pkt = $this->getPacket($x);
|
||||
|
||||
if ($pkt && $pkt->count() && $update)
|
||||
DB::table('echomail_seenby')
|
||||
->whereIn('echomail_id',$x->pluck('id'))
|
||||
->where('address_id',$this->id)
|
||||
->whereNull('sent_at')
|
||||
->whereNotNull('export_at')
|
||||
->update(['sent_pkt'=>$pkt->name]);
|
||||
return $this->system->packet($this)->mail($num->take($s->msgs_pkt));
|
||||
}
|
||||
|
||||
return $pkt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1036,52 +1015,47 @@ class Address extends Model
|
||||
/**
|
||||
* Get netmail for this node (including it's children)
|
||||
*
|
||||
* @param bool $update
|
||||
* @return Packet|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getNetmail(bool $update=FALSE): ?Packet
|
||||
public function getNetmail(): ?Packet
|
||||
{
|
||||
$pkt = NULL;
|
||||
if (($num=$this->netmailAlertWaiting())->count()) {
|
||||
Log::debug(sprintf('%s:= Packaging [%d] netmail alerts to [%s]',self::LOGKEY,$num->count(),$this->ftn));
|
||||
|
||||
$s = Setup::findOrFail(config('app.id'));
|
||||
// Find any message that defines a packet password
|
||||
$pass = $num
|
||||
->map(function($item) {
|
||||
$passpos = strpos($item->subject,':');
|
||||
return (($passpos > 0) && ($passpos < 8)) ? substr($item->subject,0,$passpos) : NULL;
|
||||
})
|
||||
->filter()
|
||||
->pop();
|
||||
|
||||
if (($x=$this->netmailAlertWaiting())->count()) {
|
||||
Log::debug(sprintf('%s:= Packaging [%d] netmail alerts to [%s]',self::LOGKEY,$x->count(),$this->ftn));
|
||||
$passpos = strpos($x->last()->subject,':');
|
||||
Log::debug(sprintf('%s:= Overwriting system packet password with [%s] for [%s]',self::LOGKEY,$pass,$this->ftn));
|
||||
|
||||
if ($passpos > 8)
|
||||
Log::alert(sprintf('%s:! Password would be greater than 8 chars? [%d]',self::LOGKEY,$passpos));
|
||||
|
||||
$pkt = $this->getPacket($x,substr($x->last()->subject,0,$passpos));
|
||||
|
||||
if ($pkt && $pkt->count() && $update)
|
||||
DB::table('netmails')
|
||||
->whereIn('id',$x->pluck('id'))
|
||||
->update(['sent_pkt'=>$pkt->name]);
|
||||
|
||||
return $pkt;
|
||||
return $this->system->packet($this,$pass)->mail(
|
||||
$num->filter(fn($item)=>preg_match("/^{$pass}:/",$item->subject))
|
||||
->transform(function($item) use ($pass) {
|
||||
$item->subject = preg_replace("/^{$pass}:/",'',$item->subject);
|
||||
return $item;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (($x=$this->netmailWaiting())
|
||||
->count())
|
||||
{
|
||||
Log::debug(sprintf('%s:= Got [%d] netmails for [%s] for sending',self::LOGKEY,$x->count(),$this->ftn));
|
||||
if (($num=$this->netmailWaiting())->count()) {
|
||||
$s = Setup::findOrFail(config('app.id'));
|
||||
|
||||
if ($x->count() > $s->msgs_pkt) {
|
||||
$x = $x->take($s->msgs_pkt);
|
||||
Log::alert(sprintf('%s:= Only sending [%d] netmails for [%s]',self::LOGKEY,$x->count(),$this->ftn));
|
||||
}
|
||||
Log::debug(sprintf('%s:= Got [%d] netmails for [%s] for sending',self::LOGKEY,$num->count(),$this->ftn));
|
||||
|
||||
$pkt = $this->getPacket($x);
|
||||
// Limit to max messages
|
||||
if ($num->count() > $s->msgs_pkt)
|
||||
Log::alert(sprintf('%s:= Only sending [%d] netmails for [%s]',self::LOGKEY,$num->count(),$this->ftn));
|
||||
|
||||
if ($pkt && $pkt->count() && $update)
|
||||
DB::table('netmails')
|
||||
->whereIn('id',$x->pluck('id'))
|
||||
->update(['sent_pkt'=>$pkt->name]);
|
||||
return $this->system->packet($this)->mail($num->take($s->msgs_pkt));
|
||||
}
|
||||
|
||||
return $pkt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1091,8 +1065,9 @@ class Address extends Model
|
||||
* @param string|null $passwd Override password used in packet
|
||||
* @return Packet|null
|
||||
* @throws \Exception
|
||||
* @deprecated
|
||||
*/
|
||||
public function getPacket(Collection $msgs,string $passwd=NULL): ?Packet
|
||||
private function getPacket(Collection $msgs,string $passwd=NULL): ?Packet
|
||||
{
|
||||
$s = Setup::findOrFail(config('app.id'));
|
||||
$ao = our_address($this);
|
||||
@ -1104,7 +1079,7 @@ class Address extends Model
|
||||
}
|
||||
|
||||
// Get packet type
|
||||
$o = $ao->system->packet();
|
||||
$o = $ao->system->packet($this);
|
||||
$o->addressHeader($ao,$this,$passwd);
|
||||
|
||||
// $oo = Netmail/Echomail Model
|
||||
@ -1151,6 +1126,7 @@ class Address extends Model
|
||||
*
|
||||
* @return Collection
|
||||
* @throws \Exception
|
||||
* @note The packet password to use is on the subject line for these alerts
|
||||
*/
|
||||
public function netmailAlertWaiting(): Collection
|
||||
{
|
||||
|
@ -10,54 +10,77 @@ use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Casts\{CollectionOrNull,CompressedString};
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Interfaces\Packet;
|
||||
use App\Traits\{EncodeUTF8,MsgID,ParseAddresses,QueryCacheableConfig};
|
||||
use App\Traits\{MessageAttributes,MsgID,ParseAddresses,QueryCacheableConfig};
|
||||
|
||||
final class Echomail extends Model implements Packet
|
||||
{
|
||||
use SoftDeletes,EncodeUTF8,MsgID,ParseAddresses,QueryCacheableConfig;
|
||||
use SoftDeletes,MessageAttributes,MsgID,ParseAddresses,QueryCacheableConfig;
|
||||
|
||||
private const LOGKEY = 'ME-';
|
||||
private Collection $set_seenby;
|
||||
private Collection $set_path;
|
||||
private Carbon $set_recvtime;
|
||||
private string $set_pkt;
|
||||
private string $set_sender;
|
||||
private bool $no_export = FALSE;
|
||||
|
||||
private const kludges = [
|
||||
'MSGID:'=>'msgid',
|
||||
'PATH:'=>'set_path',
|
||||
'REPLY:'=>'replyid',
|
||||
'SEEN-BY:'=>'set_seenby',
|
||||
];
|
||||
|
||||
// When generating a packet for this echomail, the packet recipient is our tftn
|
||||
public Address $tftn;
|
||||
|
||||
protected $casts = [
|
||||
'datetime' => 'datetime:Y-m-d H:i:s',
|
||||
'kludges' => CollectionOrNull::class,
|
||||
'msg' => CompressedString::class,
|
||||
'msg_src' => CompressedString::class,
|
||||
'rogue_seenby' => CollectionOrNull::class,
|
||||
'rogue_path' => CollectionOrNull::class,
|
||||
];
|
||||
|
||||
private const cast_utf8 = [
|
||||
'to',
|
||||
'from',
|
||||
'subject',
|
||||
'msg',
|
||||
'msg_src',
|
||||
'origin',
|
||||
'tearline',
|
||||
'tagline',
|
||||
'rogue_path' => CollectionOrNull::class, // @deprecated?
|
||||
];
|
||||
|
||||
public function __set($key,$value)
|
||||
{
|
||||
switch ($key) {
|
||||
case 'kludges':
|
||||
if (! count($value))
|
||||
return;
|
||||
|
||||
if (array_key_exists($value[0],self::kludges)) {
|
||||
$this->{self::kludges[$value[0]]} = $value[1];
|
||||
|
||||
} else {
|
||||
$this->kludges->put($value[0],$value[1]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'no_export':
|
||||
case 'set_path':
|
||||
case 'set_pkt':
|
||||
case 'set_sender':
|
||||
case 'set_recvtime':
|
||||
case 'set_seenby':
|
||||
$this->{$key} = $value;
|
||||
break;
|
||||
|
||||
// Values that we pass to boot() to record how we got this echomail
|
||||
case 'set_pkt':
|
||||
case 'set_recvtime':
|
||||
case 'set_sender':
|
||||
// @todo We'll normalise these values when saving the netmail
|
||||
case 'set_tagline':
|
||||
case 'set_tearline':
|
||||
case 'set_origin':
|
||||
// For us to record the echoarea the message is for, if the area isnt defined (eg: packet dump)
|
||||
case 'set_echoarea':
|
||||
$this->set->put($key,$value);
|
||||
break;
|
||||
|
||||
// The path and seenby the echomail went through to get here
|
||||
case 'set_path':
|
||||
case 'set_seenby':
|
||||
if (! $this->set->has($key))
|
||||
$this->set->put($key,collect());
|
||||
|
||||
$this->set->get($key)->push($value);
|
||||
break;
|
||||
|
||||
default:
|
||||
parent::__set($key,$value);
|
||||
}
|
||||
@ -67,6 +90,12 @@ final class Echomail extends Model implements Packet
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function($model) {
|
||||
if (! is_null($model->errors))
|
||||
throw new \Exception('Cannot save, validation errors exist');
|
||||
});
|
||||
|
||||
// @todo dont save us in the seenby/path, we'll add it dynamically when we send out.
|
||||
// @todo if the message is updated with new SEEN-BY's from another route, we'll delete the pending export for systems (if there is one)
|
||||
static::created(function($model) {
|
||||
$rogue = collect();
|
||||
@ -74,8 +103,10 @@ final class Echomail extends Model implements Packet
|
||||
$path = collect();
|
||||
|
||||
// Parse PATH
|
||||
if ($model->set_path->count())
|
||||
$path = self::parseAddresses('path',$model->set_path,$model->fftn->zone,$rogue);
|
||||
if ($model->set->has('set_path'))
|
||||
$path = self::parseAddresses('path',$model->set->get('set_path'),$model->fftn->zone,$rogue);
|
||||
|
||||
Log::debug(sprintf('%s:^ Message [%d] from point address is [%d]',self::LOGKEY,$model->id,$model->fftn->point_id));
|
||||
|
||||
// Make sure our sender is first in the path
|
||||
if (! $path->contains($model->fftn_id)) {
|
||||
@ -84,9 +115,9 @@ final class Echomail extends Model implements Packet
|
||||
}
|
||||
|
||||
// Make sure our pktsrc is last in the path
|
||||
if (isset($model->set_sender) && (! $path->contains($model->set_sender))) {
|
||||
Log::alert(sprintf('%s:? Echomail adding pktsrc to end of PATH [%s].',self::LOGKEY,$model->set_sender));
|
||||
$path->push($model->set_sender);
|
||||
if ($model->set->has('set_sender') && (! $path->contains($model->set->get('set_sender')->id))) {
|
||||
Log::alert(sprintf('%s:? Echomail adding pktsrc to end of PATH [%s].',self::LOGKEY,$model->set->get('set_sender')->ftn));
|
||||
$path->push($model->set->get('set_sender')->id);
|
||||
}
|
||||
|
||||
// Save the Path
|
||||
@ -105,8 +136,8 @@ final class Echomail extends Model implements Packet
|
||||
|
||||
// @todo move the parseAddress processing into Message::class, and our address to the seenby (and thus no need to add it when we export)
|
||||
// Parse SEEN-BY
|
||||
if ($model->set_seenby->count())
|
||||
$seenby = self::parseAddresses('seenby',$model->set_seenby,$model->fftn->zone,$rogue);
|
||||
if ($model->set->has('set_seenby'))
|
||||
$seenby = self::parseAddresses('seenby',$model->set->get('set_seenby'),$model->fftn->zone,$rogue);
|
||||
|
||||
// Make sure our sender is in the seenby
|
||||
if (! $seenby->contains($model->fftn_id)) {
|
||||
@ -115,9 +146,9 @@ final class Echomail extends Model implements Packet
|
||||
}
|
||||
|
||||
// Make sure our pktsrc is in the seenby
|
||||
if (isset($model->set_sender) && (! $seenby->contains($model->set_sender))) {
|
||||
Log::alert(sprintf('%s:? Echomail adding pktsrc to SEENBY [%s].',self::LOGKEY,$model->set_sender));
|
||||
$seenby->push($model->set_sender);
|
||||
if ($model->set->has('set_sender') && (! $seenby->contains($model->set->get('set_sender')->id))) {
|
||||
Log::alert(sprintf('%s:? Echomail adding pktsrc to SEENBY [%s].',self::LOGKEY,$model->set->get('set_sender')->ftn));
|
||||
$seenby->push($model->set->get('set_sender')->id);
|
||||
}
|
||||
|
||||
if (count($rogue)) {
|
||||
@ -129,26 +160,26 @@ final class Echomail extends Model implements Packet
|
||||
$model->seenby()->sync($seenby);
|
||||
|
||||
// Our last node in the path is our sender
|
||||
if (isset($model->set_pkt) && isset($model->set_recvtime)) {
|
||||
if ($model->set->has('set_pkt') && $model->set->has('set_recvtime')) {
|
||||
if ($path->count()) {
|
||||
DB::update('UPDATE echomail_path set recv_pkt=?,recv_at=? where address_id=? and echomail_id=?',[
|
||||
$model->set_pkt,
|
||||
$model->set_recvtime,
|
||||
$model->set->get('set_pkt'),
|
||||
$model->set->get('set_recvtime'),
|
||||
$path->last(),
|
||||
$model->id,
|
||||
]);
|
||||
|
||||
} else {
|
||||
Log::critical(sprintf('%s:! Wasnt able to set packet details for [%d] to [%s] to [%s], no path information',self::LOGKEY,$model->id,$model->set_pkt,$model->set_recvtime));
|
||||
Log::critical(sprintf('%s:! Wasnt able to set packet details for [%d] to [%s] to [%s], no path information',self::LOGKEY,$model->id,$model->set->get('set_pkt'),$model->set->get('set_recvtime')));
|
||||
}
|
||||
}
|
||||
|
||||
// See if we need to export this message.
|
||||
if ($model->echoarea->sec_read) {
|
||||
$exportto = ($x=$model
|
||||
$exportto = $model
|
||||
->echoarea
|
||||
->addresses
|
||||
->filter(function($item) use ($model) { return $model->echoarea->can_read($item->security); }))
|
||||
->filter(function($item) use ($model) { return $model->echoarea->can_read($item->security); })
|
||||
->pluck('id')
|
||||
->diff($seenby);
|
||||
|
||||
@ -193,90 +224,19 @@ final class Echomail extends Model implements Packet
|
||||
->withPivot(['id','parent_id','recv_pkt','recv_at']);
|
||||
}
|
||||
|
||||
/* METHODS */
|
||||
/* ATTRIBUTES */
|
||||
|
||||
public function init(): void
|
||||
public function getSeenByAttribute(): Collection
|
||||
{
|
||||
$this->set_path = collect();
|
||||
$this->set_seenby = collect();
|
||||
return ((! $this->exists) && $this->set->has('set_seenby'))
|
||||
? $this->set->get('set_seenby')
|
||||
: $this->getRelationValue('seenby');
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
public function getPathAttribute(): Collection
|
||||
{
|
||||
return $this->encode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this model as a packet
|
||||
*/
|
||||
public function packet(Address $ao): Message
|
||||
{
|
||||
Log::info(sprintf('%s:+ Bundling [%s]',self::LOGKEY,$this->id));
|
||||
|
||||
$sysaddress = our_address($this->fftn);
|
||||
|
||||
if (! $sysaddress)
|
||||
throw new \Exception(sprintf('%s:! We dont have an address in this network? (%s)',self::LOGKEY,$this->fftn->zone->domain->name));
|
||||
|
||||
// @todo Dont bundle mail to nodes that have been disabled, or addresses that have been deleted
|
||||
$o = new Message;
|
||||
|
||||
$o->header = [
|
||||
'onode' => $sysaddress->node_id,
|
||||
'dnode' => $ao->node_id,
|
||||
'onet' => $sysaddress->host_id,
|
||||
'dnet' => $ao->host_id,
|
||||
'flags' => 0,
|
||||
'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->name;
|
||||
$o->flags = $this->flags;
|
||||
|
||||
if ($this->kludges)
|
||||
$o->kludge = collect($this->kludges);
|
||||
|
||||
$o->kludge->put('dbid',$this->id);
|
||||
|
||||
$o->msgid = $this->msgid;
|
||||
if ($this->replyid)
|
||||
$o->replyid = $this->replyid;
|
||||
|
||||
$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;
|
||||
|
||||
$o->seenby = $this->seenby->push($sysaddress)->unique()->pluck('ftn2d');
|
||||
|
||||
// Add our address to the path and seenby
|
||||
$o->path = $this->pathorder()->merge($sysaddress->ftn2d);
|
||||
|
||||
$o->packed = TRUE;
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
public function pathorder(string $display='ftn2d',int $start=NULL): Collection
|
||||
{
|
||||
$result = collect();
|
||||
|
||||
if ($x=$this->path->firstWhere('pivot.parent_id',$start)) {
|
||||
$result->push($x->$display);
|
||||
$result->push($this->pathorder($display,$x->pivot->id));
|
||||
}
|
||||
|
||||
return $result->flatten()->filter();
|
||||
return ((! $this->exists) && $this->set->has('set_path'))
|
||||
? $this->set->get('set_path')
|
||||
: $this->getRelationValue('path');
|
||||
}
|
||||
}
|
@ -10,35 +10,30 @@ use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Casts\CompressedString;
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Casts\{CollectionOrNull,CompressedString};
|
||||
use App\Interfaces\Packet;
|
||||
use App\Traits\{EncodeUTF8,MsgID};
|
||||
use App\Pivots\ViaPivot;
|
||||
use App\Traits\{MessageAttributes,MsgID};
|
||||
|
||||
final class Netmail extends Model implements Packet
|
||||
{
|
||||
use SoftDeletes,MsgID,MessageAttributes;
|
||||
|
||||
private const LOGKEY = 'MN-';
|
||||
private const PATH_REGEX = '/^([0-9]+:[0-9]+\/[0-9]+(\..*)?)\s+@([0-9.a-zA-Z]+)\s+(.*)$/';
|
||||
|
||||
use SoftDeletes,EncodeUTF8,MsgID;
|
||||
|
||||
private Collection $set_path;
|
||||
private Address $set_sender;
|
||||
private Carbon $set_recvtime;
|
||||
private string $set_pkt;
|
||||
|
||||
private const cast_utf8 = [
|
||||
'to',
|
||||
'from',
|
||||
'subject',
|
||||
'msg',
|
||||
'msg_src',
|
||||
'origin',
|
||||
'tearline',
|
||||
'tagline',
|
||||
/**
|
||||
* Kludges that we absorb in this model
|
||||
*/
|
||||
private const kludges = [
|
||||
'MSGID:'=>'msgid',
|
||||
'REPLY:'=>'replyid',
|
||||
'Via' => 'set_path',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'datetime' => 'datetime:Y-m-d H:i:s',
|
||||
'kludges' => CollectionOrNull::class,
|
||||
'msg' => CompressedString::class,
|
||||
'msg_src' => CompressedString::class,
|
||||
'sent_at' => 'datetime:Y-m-d H:i:s',
|
||||
@ -47,11 +42,36 @@ final class Netmail extends Model implements Packet
|
||||
public function __set($key,$value)
|
||||
{
|
||||
switch ($key) {
|
||||
case 'set_path':
|
||||
case 'kludges':
|
||||
if (! count($value))
|
||||
return;
|
||||
|
||||
if (array_key_exists($value[0],self::kludges)) {
|
||||
$this->{self::kludges[$value[0]]} = $value[1];
|
||||
|
||||
} else {
|
||||
$this->kludges->put($value[0],$value[1]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Values that we pass to boot() to record how we got this netmail
|
||||
case 'set_pkt':
|
||||
case 'set_recvtime':
|
||||
case 'set_sender':
|
||||
$this->{$key} = $value;
|
||||
// @todo We'll normalise these values when saving the netmail
|
||||
case 'set_tagline':
|
||||
case 'set_tearline':
|
||||
case 'set_origin':
|
||||
$this->set->put($key,$value);
|
||||
break;
|
||||
|
||||
// The path the netmail went through to get here
|
||||
case 'set_path':
|
||||
if (! $this->set->has($key))
|
||||
$this->set->put($key,collect());
|
||||
|
||||
$this->set->get($key)->push($value);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -63,43 +83,47 @@ final class Netmail extends Model implements Packet
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function($model) {
|
||||
if (! is_null($model->errors))
|
||||
throw new \Exception('Cannot save, validation errors exist');
|
||||
});
|
||||
|
||||
static::created(function($model) {
|
||||
$nodes = collect();
|
||||
|
||||
// Parse PATH
|
||||
// <FTN Address> @YYYYMMDD.HHMMSS[.Precise][.Time Zone] <Program Name> <Version> [Serial Number]
|
||||
if (isset($model->set_path)) {
|
||||
if ($model->set_path->count()) {
|
||||
foreach ($model->set_path as $line) {
|
||||
$m = [];
|
||||
if ($model->set->has('set_path')) {
|
||||
foreach ($model->set->get('set_path') as $line) {
|
||||
$m = [];
|
||||
|
||||
if (preg_match('/^([0-9]+:[0-9]+\/[0-9]+(\..*)?)\s+@([0-9.a-zA-Z]+)\s+(.*)$/',$line,$m)) {
|
||||
// Address
|
||||
$ao = Address::findFTN($m[1]);
|
||||
if (preg_match(self::PATH_REGEX,$line,$m)) {
|
||||
// Address
|
||||
// @todo Do we need to add a domain here, since the path line may not include one
|
||||
$ao = Address::findFTN($m[1]);
|
||||
|
||||
// Time
|
||||
$t = [];
|
||||
$datetime = '';
|
||||
// Time
|
||||
$t = [];
|
||||
$datetime = '';
|
||||
|
||||
if (! preg_match('/^([0-9]+\.[0-9]+)(\.?(.*))?$/',$m[3],$t))
|
||||
Log::alert(sprintf('%s:! Unable to determine time from [%s]',self::LOGKEY,$m[3]));
|
||||
else
|
||||
$datetime = Carbon::createFromFormat('Ymd.His',$t[1],$t[3] ?? '');
|
||||
if (! preg_match('/^([0-9]+\.[0-9]+)(\.?(.*))?$/',$m[3],$t))
|
||||
Log::alert(sprintf('%s:! Unable to determine time from [%s]',self::LOGKEY,$m[3]));
|
||||
else
|
||||
$datetime = Carbon::createFromFormat('Ymd.His',$t[1],$t[3] ?? '');
|
||||
|
||||
if (! $ao) {
|
||||
Log::alert(sprintf('%s:! Undefined Node [%s] for Netmail.',self::LOGKEY,$m[1]));
|
||||
//$rogue->push(['node'=>$m[1],'datetime'=>$datetime,'program'=>$m[4]]);
|
||||
if (! $ao) {
|
||||
Log::alert(sprintf('%s:! Undefined Node [%s] in netmail path.',self::LOGKEY,$m[1]));
|
||||
//$rogue->push(['node'=>$m[1],'datetime'=>$datetime,'program'=>$m[4]]);
|
||||
|
||||
} else {
|
||||
$nodes->push(['node'=>$ao,'datetime'=>$datetime,'program'=>$m[4]]);
|
||||
}
|
||||
} else {
|
||||
$nodes->push(['node'=>$ao,'datetime'=>$datetime,'program'=>$m[4]]);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no details (Mystic), we'll create a blank
|
||||
} else {
|
||||
$nodes->push(['node'=>$model->set_sender,'datetime'=>Carbon::now(),'program'=>'Unknown']);
|
||||
}
|
||||
|
||||
// If there are no details (Mystic), we'll create a blank
|
||||
} elseif ($model->set->has('set_sender')) {
|
||||
$nodes->push(['node'=>$model->set->get('set_sender'),'datetime'=>Carbon::now(),'program'=>'Unknown']);
|
||||
}
|
||||
|
||||
// Save the Path
|
||||
@ -118,15 +142,25 @@ final class Netmail extends Model implements Packet
|
||||
}
|
||||
|
||||
// Our last node in the path is our sender
|
||||
if ($nodes->count() && isset($model->set_pkt) && isset($model->set_sender) && isset($model->set_recvtime)) {
|
||||
if ($nodes->count() && $model->set->has('set_pkt') && $model->set->has('set_sender') && $model->set->has('set_recvtime')) {
|
||||
DB::update('UPDATE netmail_path set recv_pkt=?,recv_at=?,recv_id=? where address_id=? and netmail_id=?',[
|
||||
$model->set_pkt,
|
||||
$model->set_recvtime,
|
||||
$model->set_sender->id,
|
||||
$model->set->get('set_pkt'),
|
||||
$model->set->get('set_recvtime'),
|
||||
$model->set->get('set_sender')->id,
|
||||
Arr::get($nodes->last(),'node')->id,
|
||||
$model->id,
|
||||
]);
|
||||
}
|
||||
|
||||
// Save our origin, tearline & tagline
|
||||
if ($model->set->has('set_tagline'))
|
||||
$model->tagline = $model->set->get('set_tagline');
|
||||
if ($model->set->has('set_tearline'))
|
||||
$model->tearline = $model->set->get('set_tearline');
|
||||
if ($model->set->has('set_origin'))
|
||||
$model->origin = $model->set->get('set_origin');
|
||||
|
||||
$model->save();
|
||||
});
|
||||
}
|
||||
|
||||
@ -142,13 +176,8 @@ final class Netmail extends Model implements Packet
|
||||
public function path()
|
||||
{
|
||||
return $this->belongsToMany(Address::class,'netmail_path')
|
||||
->withPivot(['id','parent_id','datetime','program','recv_pkt','recv_id']);
|
||||
}
|
||||
|
||||
public function received()
|
||||
{
|
||||
return $this->belongsToMany(Address::class,'netmail_path','netmail_id','recv_id')
|
||||
->withPivot(['id','parent_id','datetime','program','recv_pkt','recv_id']);
|
||||
->withPivot(['id','parent_id','datetime','program','recv_pkt','recv_id'])
|
||||
->using(ViaPivot::class);
|
||||
}
|
||||
|
||||
public function tftn()
|
||||
@ -158,88 +187,41 @@ final class Netmail extends Model implements Packet
|
||||
->withTrashed();
|
||||
}
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
/**
|
||||
* Enable rendering the path even if the model hasnt been saved
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPathAttribute(): Collection
|
||||
{
|
||||
return ((! $this->exists) && $this->set->has('set_path'))
|
||||
? $this->set->get('set_path')->map(function($item) {
|
||||
$m = [];
|
||||
preg_match(self::PATH_REGEX,$item,$m);
|
||||
return $m[1];
|
||||
})
|
||||
: $this->getRelationValue('path');
|
||||
}
|
||||
|
||||
/* METHODS */
|
||||
|
||||
/**
|
||||
* Return this model as a packet
|
||||
* Render the via line
|
||||
*
|
||||
* @param Address $ao
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function packet(Address $ao,string $strippass=NULL): Message
|
||||
public function via(Address $ao): string
|
||||
{
|
||||
Log::debug(sprintf('%s:+ Bundling [%s]',self::LOGKEY,$this->id));
|
||||
if (! $ao->pivot)
|
||||
throw new \Exception('Cannot render the via line without an address record without a path pivot');
|
||||
|
||||
// @todo Dont bundle mail to nodes that have been disabled, or addresses that have been deleted
|
||||
$o = new Message;
|
||||
|
||||
try {
|
||||
$o->header = [
|
||||
'onode' => $this->fftn->node_id,
|
||||
'dnode' => $this->tftn->node_id,
|
||||
'onet' => $this->fftn->host_id,
|
||||
'dnet' => $this->tftn->host_id,
|
||||
'opoint' => $this->fftn->point_id,
|
||||
'dpoint' => $this->tftn->point_id,
|
||||
'flags' => 0,
|
||||
'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 = (! is_null($strippass)) ? preg_replace('/^'.$strippass.':/','',$this->subject) : $this->subject;
|
||||
|
||||
// INTL kludge
|
||||
$o->intl = sprintf('%s %s',$this->tftn->ftn3d,$this->fftn->ftn3d);
|
||||
$o->flags = $this->flags;
|
||||
|
||||
$o->msgid = $this->msgid
|
||||
? $this->msgid
|
||||
: sprintf('%s %08x',$this->fftn->ftn4d,timew($this->datetime));
|
||||
|
||||
if ($this->replyid)
|
||||
$o->replyid = $this->replyid;
|
||||
|
||||
$o->kludge->put('dbid',$this->id);
|
||||
|
||||
$o->message = $this->msg;
|
||||
$o->tagline = $this->tagline;
|
||||
$o->tearline = $this->tearline;
|
||||
|
||||
// VIA kludge
|
||||
$via = $this->via ?: collect();
|
||||
// Add our address to the VIA line
|
||||
$via->push(
|
||||
sprintf('%s @%s.UTC %s %d.%d/%s %s',
|
||||
our_address($this->fftn)->ftn3d,
|
||||
Carbon::now()->utc()->format('Ymd.His'),
|
||||
str_replace(' ','_',Setup::PRODUCT_NAME),
|
||||
Setup::PRODUCT_VERSION_MAJ,
|
||||
Setup::PRODUCT_VERSION_MIN,
|
||||
(new Setup)->version,
|
||||
Carbon::now()->format('Y-m-d'),
|
||||
));
|
||||
|
||||
$o->via = $via;
|
||||
|
||||
$o->packed = TRUE;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error(sprintf('%s:! Error converting netmail [%s] to a message (%d:%s)',self::LOGKEY,$this->id,$e->getLine(),$e->getMessage()));
|
||||
dump($this);
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
public function pathorder(string $display='ftn2d',int $start=NULL): Collection
|
||||
{
|
||||
$result = collect();
|
||||
|
||||
if ($x=$this->path->firstWhere('pivot.parent_id',$start)) {
|
||||
$result->push($x->$display);
|
||||
$result->push($this->pathorder($display,$x->pivot->id));
|
||||
}
|
||||
|
||||
return $result->flatten()->filter();
|
||||
return sprintf('%s @%s.UTC %s',
|
||||
$ao->ftn3d,
|
||||
$ao->pivot->datetime->format('Ymd.His'),
|
||||
$ao->pivot->program);
|
||||
}
|
||||
}
|
@ -110,7 +110,8 @@ class System extends Model
|
||||
public function sessions()
|
||||
{
|
||||
return $this->belongsToMany(Zone::class)
|
||||
->withPivot(['sespass','pktpass','ticpass','fixpass','zt_ipv4','zt_ipv6','default']);
|
||||
->withPivot(['sespass','pktpass','ticpass','fixpass','zt_ipv4','zt_ipv6','default'])
|
||||
->dontCache();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -251,12 +252,19 @@ class System extends Model
|
||||
/**
|
||||
* Return the packet that this system uses
|
||||
*
|
||||
* @param Address $ao
|
||||
* @param string|null $password
|
||||
* @return Packet
|
||||
*/
|
||||
public function packet(): Packet
|
||||
public function packet(Address $ao,string $password=NULL): Packet
|
||||
{
|
||||
return new (collect(Packet::PACKET_TYPES)
|
||||
->get($this->pkt_type ?: config('fido.packet_default')));
|
||||
// @todo Check that the address is one of the system's addresses
|
||||
|
||||
return
|
||||
(new (collect(Packet::PACKET_TYPES)
|
||||
->get($this->pkt_type ?: config('fido.packet_default'))))
|
||||
->for($ao)
|
||||
->password($password);
|
||||
}
|
||||
|
||||
public function poll(): ?Job
|
||||
|
@ -41,6 +41,6 @@ class EchomailChannel
|
||||
|
||||
$o = $notification->toEchomail($notifiable);
|
||||
|
||||
Log::info(sprintf('%s:= Posted echomail [%s] to [%s]',self::LOGKEY,$o->msgid,$echoarea));
|
||||
Log::info(sprintf('%s:= Posted echomail (%d) [%s] to [%s]',self::LOGKEY,$o->id,$o->msgid,$echoarea->name));
|
||||
}
|
||||
}
|
@ -41,6 +41,6 @@ class NetmailChannel
|
||||
|
||||
$o = $notification->toNetmail($notifiable);
|
||||
|
||||
Log::info(sprintf('%s:= Sent netmail [%s] to [%s]',self::LOGKEY,$o->msgid,$ao->ftn));
|
||||
Log::info(sprintf('%s:= Sent netmail (%d) [%s] to [%s]',self::LOGKEY,$o->id,$o->msgid,$ao->ftn));
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Models\{Echoarea, Echomail, Setup, System};
|
||||
use App\Models\{Echoarea,Echomail,Setup};
|
||||
|
||||
abstract class Echomails extends Notification //implements ShouldQueue
|
||||
{
|
||||
@ -46,26 +46,24 @@ abstract class Echomails extends Notification //implements ShouldQueue
|
||||
*/
|
||||
abstract public function toEchomail(object $notifiable): Echomail;
|
||||
|
||||
protected function setupEchomail(Message $mo,object $notifiable): Echomail
|
||||
protected function setupEchomail(Echomail $mo,object $notifiable): Echomail
|
||||
{
|
||||
$echoarea = $notifiable->routeNotificationFor(static::via);
|
||||
$eo = Echoarea::where('name',$echoarea)->singleOrFail();
|
||||
|
||||
$o = new Echomail;
|
||||
$o->init();
|
||||
$o->from = Setup::PRODUCT_NAME;
|
||||
$o->replyid = $mo->msgid;
|
||||
$o->echoarea_id = $eo->id;
|
||||
$o->echoarea_id = $echoarea->id;
|
||||
|
||||
$o->datetime = Carbon::now();
|
||||
$o->tzoffset = $o->datetime->utcOffset();
|
||||
|
||||
$o->fftn_id = ($x=our_address($mo->fboss_o))->id;
|
||||
$o->fftn_id = ($x=our_address($mo->fftn))->id;
|
||||
$o->flags = (Message::FLAG_LOCAL);
|
||||
|
||||
$o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
|
||||
$o->origin = sprintf('%s (%s)',Setup::PRODUCT_NAME,$x->ftn4d);
|
||||
$o->kludges = collect(['chrs'=>$mo->kludge->get('chrs') ?: 'CP437 2']);
|
||||
$o->kludges->put('CHRS:',$mo->kludges->get('chrs') ?: 'CP437 2');
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ use Carbon\Carbon;
|
||||
use Carbon\CarbonInterface;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\{Fonts\Thick,Fonts\Thin,FTN\Message,Page};
|
||||
use App\Models\{Echomail,System};
|
||||
use App\Classes\{Fonts\Thick,Fonts\Thin,Page};
|
||||
use App\Models\Echomail;
|
||||
use App\Notifications\Echomails;
|
||||
use App\Traits\MessagePath;
|
||||
|
||||
@ -17,14 +17,14 @@ class Test extends Echomails
|
||||
|
||||
private const LOGKEY = 'NNP';
|
||||
|
||||
private Message $mo;
|
||||
private Echomail $mo;
|
||||
|
||||
/**
|
||||
* Reply to a netmail ping request.
|
||||
*
|
||||
* @param Message $mo
|
||||
* @param Echomail $mo
|
||||
*/
|
||||
public function __construct(Message $mo)
|
||||
public function __construct(Echomail $mo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
@ -43,9 +43,9 @@ class Test extends Echomails
|
||||
$o = $this->setupEchomail($this->mo,$notifiable);
|
||||
$echoarea = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
Log::info(sprintf('%s:+ Creating test echomail to [%s]',self::LOGKEY,$echoarea));
|
||||
Log::info(sprintf('%s:+ Creating TEST echomail in [%s]',self::LOGKEY,$echoarea->name));
|
||||
|
||||
$o->to = $this->mo->user_from;
|
||||
$o->to = $this->mo->from;
|
||||
$o->subject = 'Test Reply';
|
||||
|
||||
// Message
|
||||
|
@ -6,7 +6,7 @@ use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System,User};
|
||||
use App\Models\{Netmail,User};
|
||||
use App\Traits\PageTemplate;
|
||||
|
||||
class AddressLink extends Netmails
|
||||
|
@ -4,9 +4,8 @@ namespace App\Notifications\Netmails;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\Netmail;
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class Areafix extends Netmails
|
||||
@ -15,14 +14,14 @@ class Areafix extends Netmails
|
||||
|
||||
private const LOGKEY = 'NAF';
|
||||
|
||||
private Message $mo;
|
||||
private Netmail $mo;
|
||||
|
||||
/**
|
||||
* Reply to an areafix request.
|
||||
*
|
||||
* @param Message $mo
|
||||
* @param Netmail $mo
|
||||
*/
|
||||
public function __construct(Message $mo)
|
||||
public function __construct(Netmail $mo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
@ -43,7 +42,7 @@ class Areafix extends Netmails
|
||||
|
||||
Log::info(sprintf('%s:+ Responding to areafix with netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->to = $this->mo->user_from;
|
||||
$o->to = $this->mo->from;
|
||||
$o->replyid = $this->mo->msgid;
|
||||
$o->subject = 'Areafix Reply';
|
||||
|
||||
|
@ -4,9 +4,8 @@ namespace App\Notifications\Netmails\Areafix;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\Netmail;
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class NotConfiguredHere extends Netmails
|
||||
@ -15,14 +14,14 @@ class NotConfiguredHere extends Netmails
|
||||
|
||||
private const LOGKEY = 'NCH';
|
||||
|
||||
private Message $mo;
|
||||
private Netmail $mo;
|
||||
|
||||
/**
|
||||
* Reply to a areafix, but the system isnt configured here.
|
||||
*
|
||||
* @param Message $mo
|
||||
* @param Netmail $mo
|
||||
*/
|
||||
public function __construct(Message $mo)
|
||||
public function __construct(Netmail $mo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
@ -43,7 +42,7 @@ class NotConfiguredHere extends Netmails
|
||||
|
||||
Log::info(sprintf('%s:+ Responding to areafix for a node [%s] not configured here',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->to = $this->mo->user_from;
|
||||
$o->to = $this->mo->from;
|
||||
$o->replyid = $this->mo->msgid;
|
||||
$o->subject = 'Areafix - Not Configured Here';
|
||||
|
||||
|
@ -5,9 +5,8 @@ namespace App\Notifications\Netmails;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\{Echomail,Netmail};
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class EchoareaNoWrite extends Netmails
|
||||
@ -16,14 +15,14 @@ class EchoareaNoWrite extends Netmails
|
||||
|
||||
private const LOGKEY = 'NNW';
|
||||
|
||||
private Message $mo;
|
||||
private Echomail $mo;
|
||||
|
||||
/**
|
||||
* Send a sysop a message if they attempt to write to an area that they dont have permission.
|
||||
*
|
||||
* @param Message $mo
|
||||
* @param Echomail $mo
|
||||
*/
|
||||
public function __construct(Message $mo)
|
||||
public function __construct(Echomail $mo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
@ -42,9 +41,9 @@ class EchoareaNoWrite extends Netmails
|
||||
$o = $this->setupNetmail($notifiable);
|
||||
$ao = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
Log::info(sprintf('%s:+ Creating ECHOMAIL NO WRITE netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||
Log::info(sprintf('%s:+ Creating ECHOAREA NO WRITE netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->subject = 'Echomail rejected - '.$this->mo->msgid;
|
||||
$o->subject = sprintf('Echomail #%s rejected to %s',$this->mo->msgid,$this->mo->echoarea->name);
|
||||
|
||||
// Message
|
||||
$msg = $this->page(FALSE,'nowrite');
|
||||
@ -52,13 +51,13 @@ class EchoareaNoWrite extends Netmails
|
||||
$msg->addText(
|
||||
sprintf("Your echomail with ID [%s] to [%s] here was received here on [%s] and it looks like you sent it on [%s].\r\r",
|
||||
$this->mo->msgid,
|
||||
$this->mo->user_to,
|
||||
$this->mo->to,
|
||||
Carbon::now()->utc()->toDateTimeString(),
|
||||
$this->mo->date->utc()->toDateTimeString(),
|
||||
)
|
||||
);
|
||||
|
||||
$msg->addText(sprintf("It appears that you do not have permission to post in this echoarea using the address [%s], so the message from your system was rejected.\r\r",$ao->ftn));
|
||||
$msg->addText(sprintf("It appears that you do not have permission to post in [%s] using the address [%s], so the message from your system was rejected.\r\r",$this->mo->echoarea->name,$ao->ftn));
|
||||
$msg->addText("Please contact the ZC if you think this is a mistake.\r\r");
|
||||
|
||||
$msg->addText($this->message_path($this->mo));
|
||||
|
@ -7,7 +7,7 @@ use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\{Echomail,Netmail};
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class EchoareaNotExist extends Netmails
|
||||
@ -16,14 +16,14 @@ class EchoareaNotExist extends Netmails
|
||||
|
||||
private const LOGKEY = 'NNW';
|
||||
|
||||
private Message $mo;
|
||||
private Echomail $mo;
|
||||
|
||||
/**
|
||||
* Send a sysop a message if they attempt to write to an area that doesnt exist.
|
||||
*
|
||||
* @param Message $mo
|
||||
*/
|
||||
public function __construct(Message $mo)
|
||||
public function __construct(Echomail $mo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
@ -42,9 +42,9 @@ class EchoareaNotExist extends Netmails
|
||||
$o = $this->setupNetmail($notifiable);
|
||||
$ao = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
Log::info(sprintf('%s:+ Creating ECHOMAIL NOT EXIST netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||
Log::info(sprintf('%s:+ Creating ECHOAREA NOT EXIST netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->subject = 'Echoarea doesnt exist - '.$this->mo->echoarea;
|
||||
$o->subject = 'Echoarea doesnt exist - '.$this->mo->set->get('set_echoarea');
|
||||
|
||||
// Message
|
||||
$msg = $this->page(FALSE,'nothere');
|
||||
@ -52,13 +52,13 @@ class EchoareaNotExist extends Netmails
|
||||
$msg->addText(
|
||||
sprintf("Your echomail with ID [%s] to [%s] here was received here on [%s] and it looks like you sent it on [%s].\r\r",
|
||||
$this->mo->msgid,
|
||||
$this->mo->user_to,
|
||||
$this->mo->to,
|
||||
Carbon::now()->utc()->toDateTimeString(),
|
||||
$this->mo->date->utc()->toDateTimeString(),
|
||||
)
|
||||
);
|
||||
|
||||
$msg->addText("It appears that the echoarea that this message is for doesnt exist, so the message from your system was rejected.\r\r");
|
||||
$msg->addText(sprintf("It appears that the echoarea [%s] that this message is for doesnt exist, so the message from your system was rejected.\r\r",$this->mo->set->get('set_echoarea')));
|
||||
$msg->addText("Please contact the ZC if you think this is a mistake.\r\r");
|
||||
|
||||
$msg->addText($this->message_path($this->mo));
|
||||
|
@ -5,9 +5,8 @@ namespace App\Notifications\Netmails;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\{Echomail,Netmail};
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class EchoareaNotSubscribed extends Netmails
|
||||
@ -16,14 +15,14 @@ class EchoareaNotSubscribed extends Netmails
|
||||
|
||||
private const LOGKEY = 'NNW';
|
||||
|
||||
private Message $mo;
|
||||
private Echomail $mo;
|
||||
|
||||
/**
|
||||
* Send a sysop a message if they write to an area that they hadnt previously subscribed to.
|
||||
*
|
||||
* @param Message $mo
|
||||
* @param Echomail $mo
|
||||
*/
|
||||
public function __construct(Message $mo)
|
||||
public function __construct(Echomail $mo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
@ -42,17 +41,17 @@ class EchoareaNotSubscribed extends Netmails
|
||||
$o = $this->setupNetmail($notifiable);
|
||||
$ao = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
Log::info(sprintf('%s:+ Creating ECHOMAIL NOT SUBSCRIBED netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||
Log::info(sprintf('%s:+ Creating ECHOAREA NOT SUBSCRIBED netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->subject = 'Echoarea not subscribed - '.$this->mo->echoarea;
|
||||
$o->subject = 'Echoarea not subscribed - '.$this->mo->echoarea->name;
|
||||
|
||||
// Message
|
||||
$msg = $this->page(FALSE,'nothere');
|
||||
$msg = $this->page(FALSE,'nosub');
|
||||
|
||||
$msg->addText(
|
||||
sprintf("Your echomail with ID [%s] to [%s] here was received here on [%s] and it looks like you sent it on [%s].\r\r",
|
||||
$this->mo->msgid,
|
||||
$this->mo->user_to,
|
||||
$this->mo->to,
|
||||
Carbon::now()->utc()->toDateTimeString(),
|
||||
$this->mo->date->utc()->toDateTimeString(),
|
||||
)
|
||||
|
@ -7,7 +7,7 @@ use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\Netmail;
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class EchomailBadAddress extends Netmails
|
||||
@ -52,7 +52,7 @@ class EchomailBadAddress extends Netmails
|
||||
$msg->addText(
|
||||
sprintf("Your echomail with ID [%s] to [%s] here was received here on [%s] and it looks like you sent it on [%s].\r\r",
|
||||
$this->mo->msgid,
|
||||
$this->mo->user_to,
|
||||
$this->mo->to,
|
||||
Carbon::now()->utc()->toDateTimeString(),
|
||||
$this->mo->date->utc()->toDateTimeString(),
|
||||
)
|
||||
|
@ -4,9 +4,8 @@ namespace App\Notifications\Netmails;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Address,Netmail,System};
|
||||
use App\Models\{Address,Netmail};
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class NetmailForward extends Netmails
|
||||
@ -16,15 +15,15 @@ class NetmailForward extends Netmails
|
||||
private const LOGKEY = 'NNP';
|
||||
|
||||
private Address $ao;
|
||||
private Message $mo;
|
||||
private Netmail $mo;
|
||||
|
||||
/**
|
||||
* Reply to a netmail ping request.
|
||||
*
|
||||
* @param Message $mo
|
||||
* @param Netmail $mo
|
||||
* @param Address $ao
|
||||
*/
|
||||
public function __construct(Message $mo,Address $ao)
|
||||
public function __construct(Netmail $mo,Address $ao)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
@ -44,9 +43,9 @@ class NetmailForward extends Netmails
|
||||
$o = $this->setupNetmail($notifiable);
|
||||
$ao = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
Log::info(sprintf('%s:+ Advising [%s@%s] that netmail to [%s] will be forwarded to [%s].',self::LOGKEY,$this->mo->user_from,$ao->ftn,$this->mo->user_to,$this->ao->ftn));
|
||||
Log::info(sprintf('%s:+ Advising [%s@%s] that netmail to [%s] will be forwarded to [%s].',self::LOGKEY,$this->mo->from,$ao->ftn,$this->mo->to,$this->ao->ftn));
|
||||
|
||||
$o->to = $this->mo->user_from;
|
||||
$o->to = $this->mo->from;
|
||||
$o->replyid = $this->mo->msgid;
|
||||
$o->subject = sprintf('Your netmail is being forwarded to %s',$this->ao->ftn3d);
|
||||
|
||||
@ -56,10 +55,10 @@ class NetmailForward extends Netmails
|
||||
$msg->addText("Howdy, Clrghouz is not a BBS, so users cannot login to collect netmail.\r\r\r");
|
||||
$msg->addText(sprintf("Never fear, your msg [%s] to [%s] has been forwarded, to [%s].\r\r",
|
||||
$this->mo->msgid,
|
||||
$this->mo->user_to,
|
||||
$this->mo->to,
|
||||
$this->ao->ftn3d,
|
||||
));
|
||||
$msg->addText(sprintf("To avoid receiving this netmail, send messages to [%s] to [%s].\r\r",$this->mo->user_to,$this->ao->ftn3d));
|
||||
$msg->addText(sprintf("To avoid receiving this netmail, send messages to [%s] to [%s].\r\r",$this->mo->to,$this->ao->ftn3d));
|
||||
|
||||
$o->msg = $msg->render();
|
||||
$o->tagline = 'Thank you so much for your mail. I love it already.';
|
||||
|
@ -5,25 +5,24 @@ namespace App\Notifications\Netmails;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\Netmail;
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class Reject extends Netmails
|
||||
class NetmailHubNoUser extends Netmails
|
||||
{
|
||||
use MessagePath,PageTemplate;
|
||||
|
||||
private const LOGKEY = 'NNP';
|
||||
|
||||
private Message $mo;
|
||||
private Netmail $mo;
|
||||
|
||||
/**
|
||||
* Reply to a netmail ping request.
|
||||
*
|
||||
* @param Message $mo
|
||||
* @param Netmail $mo
|
||||
*/
|
||||
public function __construct(Message $mo)
|
||||
public function __construct(Netmail $mo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
@ -42,9 +41,9 @@ class Reject extends Netmails
|
||||
$o = $this->setupNetmail($notifiable);
|
||||
$ao = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
Log::info(sprintf('%s:+ Creating reject netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||
Log::info(sprintf('%s:+ Creating HUB NO USER netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->to = $this->mo->user_from;
|
||||
$o->to = $this->mo->from;
|
||||
$o->replyid = $this->mo->msgid;
|
||||
$o->subject = 'Message Undeliverable - '.$this->mo->msgid;
|
||||
|
||||
@ -54,7 +53,7 @@ class Reject extends Netmails
|
||||
$msg->addText(
|
||||
sprintf("Your netmail with ID [%s] to [%s] here was received here on [%s] and it looks like you sent it on [%s].\r\r",
|
||||
$this->mo->msgid,
|
||||
$this->mo->user_to,
|
||||
$this->mo->to,
|
||||
Carbon::now()->utc()->toDateTimeString(),
|
||||
$this->mo->date->utc()->toDateTimeString(),
|
||||
)
|
@ -6,7 +6,7 @@ use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Notifications\Netmails;
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\Netmail;
|
||||
use App\Traits\PageTemplate;
|
||||
|
||||
class PacketPasswordInvalid extends Netmails
|
||||
|
@ -8,7 +8,7 @@ use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\Netmail;
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class Ping extends Netmails
|
||||
@ -17,14 +17,14 @@ class Ping extends Netmails
|
||||
|
||||
private const LOGKEY = 'NNP';
|
||||
|
||||
private Message $mo;
|
||||
private Netmail $mo;
|
||||
|
||||
/**
|
||||
* Reply to a netmail ping request.
|
||||
*
|
||||
* @param Message $mo
|
||||
*/
|
||||
public function __construct(Message $mo)
|
||||
public function __construct(Netmail $mo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
@ -45,7 +45,7 @@ class Ping extends Netmails
|
||||
|
||||
Log::info(sprintf('%s:+ Creating PING netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->to = $this->mo->user_from;
|
||||
$o->to = $this->mo->from;
|
||||
$o->replyid = $this->mo->msgid;
|
||||
$o->subject = 'Ping Reply';
|
||||
|
||||
|
@ -5,9 +5,8 @@ namespace App\Notifications\Netmails;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\Netmail;
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class PollingFailed extends Netmails
|
||||
|
@ -5,7 +5,7 @@ namespace App\Notifications\Netmails;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Netmail,System};
|
||||
use App\Models\Netmail;
|
||||
use App\Traits\PageTemplate;
|
||||
|
||||
class Test extends Netmails
|
||||
|
12
app/Pivots/ViaPivot.php
Normal file
12
app/Pivots/ViaPivot.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Pivots;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
class ViaPivot extends Pivot
|
||||
{
|
||||
protected $casts = [
|
||||
'datetime' => 'datetime',
|
||||
];
|
||||
}
|
@ -6,6 +6,21 @@ use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
use App\Models\{System,User};
|
||||
|
||||
/**
|
||||
* This handles updating system records
|
||||
*
|
||||
* Authorisation is defined by function_role_only, where
|
||||
* - function = create,delete,update
|
||||
* - role = admin,zc,rc,nc,hc,nn,pt
|
||||
* - only = only that role can do (no hierarchy permission)
|
||||
* ie:
|
||||
* - admin - only site admin can do (user = admin)
|
||||
* - zc - only ZC can perform (user has an address that is a ZC)
|
||||
* - rc - only RC (or ZC) ...
|
||||
* - hc - only HC (or ZC/RC) ...
|
||||
* - nn - only NN (or ZC/RC/HC) ...
|
||||
* - pt - only PT (or ZC/RC/HC/NN) ...
|
||||
*/
|
||||
class SystemPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
@ -49,7 +64,7 @@ class SystemPolicy
|
||||
* @param System $system
|
||||
* @return bool
|
||||
*/
|
||||
public function update(User $user, System $system): bool
|
||||
public function update_nn(User $user,System $system): bool
|
||||
{
|
||||
// Site Admins can always edit
|
||||
if ($user->isAdmin())
|
||||
@ -59,7 +74,8 @@ class SystemPolicy
|
||||
if (! $system->exists)
|
||||
return FALSE;
|
||||
|
||||
return $system->users->contains($user)
|
||||
&& (($system->addresses->count() === 0) || ($system->addresses->where('validated',TRUE)->count()));
|
||||
// @todo Permit ZC, RC, NC, HUB user
|
||||
|
||||
return $system->users->contains($user) && $system->akas->count();
|
||||
}
|
||||
}
|
@ -89,7 +89,7 @@ trait EncodeUTF8
|
||||
return $this->attributes[$key];
|
||||
}
|
||||
|
||||
return parent::getAttribute($key);
|
||||
return Arr::get($this->_encoded,$key) ? $this->attributes[$key] : parent::getAttribute($key);
|
||||
}
|
||||
|
||||
public function setAttribute($key,$value)
|
||||
|
197
app/Traits/MessageAttributes.php
Normal file
197
app/Traits/MessageAttributes.php
Normal file
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Common Attributes used by message packets (and thus their Models)
|
||||
*/
|
||||
namespace App\Traits;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Validation\Validator as ValidatorResult;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Models\Address;
|
||||
|
||||
trait MessageAttributes
|
||||
{
|
||||
use EncodeUTF8;
|
||||
|
||||
// Items we need to set when creating()
|
||||
public Collection $set;
|
||||
// Validation Errors
|
||||
public ?ValidatorResult $errors = NULL;
|
||||
|
||||
private const cast_utf8 = [
|
||||
'to',
|
||||
'from',
|
||||
'subject',
|
||||
'msg',
|
||||
'msg_src',
|
||||
'origin',
|
||||
'tearline',
|
||||
'tagline',
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// Init
|
||||
$this->set = collect();
|
||||
}
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
public function getContentAttribute(): string
|
||||
{
|
||||
if ($this->msg_src)
|
||||
return $this->msg_src."\r";
|
||||
|
||||
// If we have a msg_src attribute, we'll use that
|
||||
$result = $this->msg."\r\r";
|
||||
|
||||
if ($this->tagline)
|
||||
$result .= sprintf("%s\r",$this->tagline);
|
||||
|
||||
if ($this->tearline)
|
||||
$result .= sprintf("%s\r",$this->tearline);
|
||||
|
||||
if ($this->origin)
|
||||
$result .= sprintf("%s",$this->origin);
|
||||
|
||||
return rtrim($result,"\r")."\r";
|
||||
}
|
||||
|
||||
public function getDateAttribute(): Carbon
|
||||
{
|
||||
return $this->datetime->utcOffset($this->tzoffset);
|
||||
}
|
||||
|
||||
public function getOriginAttribute(string $val=NULL): ?string
|
||||
{
|
||||
if ($this->exists && (! $val))
|
||||
return $val;
|
||||
|
||||
// If $val is not set, then it may be an unsaved object
|
||||
return sprintf(' * Origin: %s',
|
||||
((! $this->exists) && $this->set->has('set_origin'))
|
||||
? $this->set->get('set_origin')
|
||||
: $val);
|
||||
}
|
||||
|
||||
public function getTaglineAttribute(string $val=NULL): ?string
|
||||
{
|
||||
if ($this->exists && (! $val))
|
||||
return $val;
|
||||
|
||||
// If $val is not set, then it may be an unsaved object
|
||||
return sprintf('... %s',
|
||||
((! $this->exists) && $this->set->has('set_tagline'))
|
||||
? $this->set->get('set_tagline')
|
||||
: $val);
|
||||
}
|
||||
|
||||
public function getTearlineAttribute(string $val=NULL): ?string
|
||||
{
|
||||
if ($this->exists && (! $val))
|
||||
return $val;
|
||||
|
||||
// If $val is not set, then it may be an unsaved object
|
||||
return sprintf('--- %s',
|
||||
((! $this->exists) && $this->set->has('set_tearline'))
|
||||
? $this->set->get('set_tearline')
|
||||
: $val);
|
||||
}
|
||||
|
||||
/* METHODS */
|
||||
|
||||
/**
|
||||
* Return an array of flag descriptions
|
||||
*
|
||||
* @return Collection
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
public function flags(): Collection
|
||||
{
|
||||
return collect([
|
||||
'private' => $this->isFlagSet(Message::FLAG_PRIVATE),
|
||||
'crash' => $this->isFlagSet(Message::FLAG_CRASH),
|
||||
'recd' => $this->isFlagSet(Message::FLAG_RECD),
|
||||
'sent' => $this->isFlagSet(Message::FLAG_SENT),
|
||||
'fileattach' => $this->isFlagSet(Message::FLAG_FILEATTACH),
|
||||
'intransit' => $this->isFlagSet(Message::FLAG_INTRANSIT),
|
||||
'orphan' => $this->isFlagSet(Message::FLAG_ORPHAN),
|
||||
'killsent' => $this->isFlagSet(Message::FLAG_KILLSENT),
|
||||
'local' => $this->isFlagSet(Message::FLAG_LOCAL),
|
||||
'hold' => $this->isFlagSet(Message::FLAG_HOLD),
|
||||
'unused-10' => $this->isFlagSet(Message::FLAG_UNUSED_10),
|
||||
'filereq' => $this->isFlagSet(Message::FLAG_FREQ),
|
||||
'receipt-req' => $this->isFlagSet(Message::FLAG_RETRECEIPT),
|
||||
'receipt' => $this->isFlagSet(Message::FLAG_ISRETRECEIPT),
|
||||
'audit' => $this->isFlagSet(Message::FLAG_AUDITREQ),
|
||||
'fileupdate' => $this->isFlagSet(Message::FLAG_FILEUPDATEREQ),
|
||||
'pktpasswd' => $this->isFlagSet(Message::FLAG_PKTPASSWD),
|
||||
])->filter();
|
||||
}
|
||||
|
||||
public function isFlagSet($flag): bool
|
||||
{
|
||||
return ($this->flags & $flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this model as a packet
|
||||
*/
|
||||
public function packet(Address $ao): Message
|
||||
{
|
||||
Log::debug(sprintf('%s:+ Bundling [%s]',self::LOGKEY,$this->id),['type'=>get_class($this)]);
|
||||
|
||||
// For netmails, our tftn is the next hop
|
||||
$this->tftn = $ao;
|
||||
|
||||
// @todo Dont bundle mail to nodes that have been disabled, or addresses that have been deleted
|
||||
return Message::packMessage($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return our path in order
|
||||
*
|
||||
* @param string $display
|
||||
* @param int|NULL $start
|
||||
* @return Collection
|
||||
*/
|
||||
public function pathorder(string $display='ftn2d',int $start=NULL): Collection
|
||||
{
|
||||
$result = collect();
|
||||
|
||||
if ($x=$this->path->firstWhere('pivot.parent_id',$start)) {
|
||||
$result->push($x->$display);
|
||||
$result->push($this->pathorder($display,$x->pivot->id));
|
||||
}
|
||||
|
||||
return $result->flatten()->filter();
|
||||
}
|
||||
}
|
@ -5,42 +5,40 @@
|
||||
*/
|
||||
namespace App\Traits;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Models\{Echomail,Netmail};
|
||||
|
||||
trait MessagePath
|
||||
{
|
||||
protected function message_path(Message $mo): string
|
||||
protected function message_path(Echomail|Netmail $mo): string
|
||||
{
|
||||
$reply = "This is your original message:\r\r";
|
||||
|
||||
$reply .= "+--[ BEGIN MESSAGE ]----------------------------------+\r";
|
||||
$reply .= sprintf("TO: %s\r",$mo->user_to);
|
||||
$reply .= sprintf("TO: %s\r",$mo->to);
|
||||
$reply .= sprintf("SUBJECT: %s\r",$mo->subject);
|
||||
$reply .= str_replace("\r---","\r#--",$mo->message)."\r";
|
||||
$reply .= str_replace("\r---","\r#--",$mo->msg)."\r";
|
||||
|
||||
$reply .= "+--[ CONTROL LINES ]----------------------------------+\r";
|
||||
$reply .= sprintf("DATE: %s\r",$mo->date->format('Y-m-d H:i:s'));
|
||||
$reply .= sprintf("MSGID: %s\r",$mo->msgid);
|
||||
|
||||
foreach ($mo->kludge as $k=>$v)
|
||||
$reply .= sprintf("@%s: %s\r",strtoupper($k),$v);
|
||||
foreach ($mo->kludges as $k=>$v)
|
||||
$reply .= sprintf("%s %s\r",$k,$v);
|
||||
|
||||
$reply .= "+--[ PATH ]-------------------------------------------+\r";
|
||||
|
||||
if ($mo->isNetmail()) {
|
||||
if ($mo->via->count())
|
||||
foreach ($mo->via as $via)
|
||||
$reply .= sprintf("VIA: %s\r",$via);
|
||||
else
|
||||
$reply .= "No path information? This would be normal if this message came directly to the hub\r";
|
||||
if ($mo->path->count())
|
||||
if ($mo instanceof Netmail) {
|
||||
foreach ($mo->path as $o)
|
||||
$reply .= sprintf("VIA: %s\r",$mo->via($o));
|
||||
|
||||
} else {
|
||||
if ($mo->path->count())
|
||||
foreach ($mo->path as $via)
|
||||
$reply .= sprintf("VIA: %s\r",$via);
|
||||
else
|
||||
$reply .= "No path information? This would be normal if this message came directly to the hub\r";
|
||||
}
|
||||
} else {
|
||||
foreach ($mo->path as $o)
|
||||
$reply .= sprintf("VIA: %s\r",$o->ftn);
|
||||
}
|
||||
|
||||
else
|
||||
$reply .= "No path information? This would be normal if this message came directly to the hub\r";
|
||||
|
||||
$reply .= "+--[ END MESSAGE ]------------------------------------+\r\r";
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
"keywords": ["framework","laravel"],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.1|8.2|8.3",
|
||||
"php": "^8.2|8.3",
|
||||
"ext-bz2": "*",
|
||||
"ext-pcntl": "*",
|
||||
"ext-sockets": "*",
|
||||
|
@ -21,7 +21,7 @@ return new class extends Migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('netmail', function (Blueprint $table) {
|
||||
Schema::table('netmails', function (Blueprint $table) {
|
||||
$table->dropColumn('origin');
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('netmails', function (Blueprint $table) {
|
||||
$table->json('kludges')->nullable();
|
||||
});
|
||||
Schema::table('echomails', function (Blueprint $table) {
|
||||
$table->tinyInteger('cost')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('netmails', function (Blueprint $table) {
|
||||
$table->dropColumn('kludges');
|
||||
});
|
||||
Schema::table('echomails', function (Blueprint $table) {
|
||||
$table->dropColumn('cost');
|
||||
});
|
||||
}
|
||||
};
|
@ -1,3 +1,8 @@
|
||||
@php
|
||||
use App\Models\Netmail;
|
||||
use App\Classes\FTN\Message;
|
||||
@endphp
|
||||
|
||||
@extends('layouts.app')
|
||||
@section('htmlheader_title')
|
||||
Verify Packet
|
||||
@ -82,7 +87,7 @@
|
||||
<div class="col-12">
|
||||
<h4 class="accordion-header">
|
||||
<span class="accordion-button" id="pktmsg" data-bs-toggle="collapse" data-bs-target="#collapse_msg_{{ $loop->parent->parent->index }}_{{ $loop->index }}" aria-expanded="false">
|
||||
@if($msg->isNetmail()) Netmail @else Echomail <strong>{{ $msg->echoarea }}</strong> @endif : {{ $msg->msgid }}
|
||||
@if($msg instanceof Netmail) Netmail @else Echomail <strong>{{ $msg->echoarea->name }}</strong> @endif : {{ $msg->msgid }}
|
||||
</span>
|
||||
</h4>
|
||||
|
||||
@ -98,48 +103,40 @@
|
||||
|
||||
<div class="row pb-2">
|
||||
<div class="col-4">
|
||||
DATE: <strong class="highlight">{{ $msg->date }}</strong>
|
||||
DATE: <strong class="highlight">{{ $msg->datetime }}</strong>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
FLAGS: <strong class="highlight">{{ $msg->flags()->filter()->keys()->join(', ') }}</strong>
|
||||
FLAGS: <strong class="highlight">{{ $msg->flags()->keys()->join(', ') }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row pb-2">
|
||||
<div class="col-4">
|
||||
FROM: <strong class="highlight">{!! \App\Classes\FTN\Message::tr($msg->user_from) !!}</strong> (<strong class="highlight">{{ $msg->fftn }}</strong>)
|
||||
FROM: <strong class="highlight">{!! Message::tr($msg->from) !!}</strong> (<strong class="highlight">{{ $msg->fftn->ftn }}</strong>)
|
||||
</div>
|
||||
<div class="col-4">
|
||||
TO: <strong class="highlight">{!! \App\Classes\FTN\Message::tr($msg->user_to) !!}</strong>@if($msg->isNetmail()) (<strong class="highlight">{{ $msg->tftn }}</strong>) @endif
|
||||
TO: <strong class="highlight">{!! Message::tr($msg->to) !!}</strong>@if($msg instanceof Netmail) (<strong class="highlight">{{ $msg->tftn->ftn }}</strong>) @endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
SUBJECT: <strong class="highlight">{!! \App\Classes\FTN\Message::tr($msg->subject) !!}</strong>
|
||||
SUBJECT: <strong class="highlight">{!! Message::tr($msg->subject) !!}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
<div class="pad pb-0">
|
||||
<pre class="highlight">{!! \App\Classes\FTN\Message::tr($msg->message).sprintf("\r * Origin: %s",$msg->origin) !!}</pre>
|
||||
<pre class="highlight">{!! Message::tr($msg->msg_src) !!}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($msg->tagline)
|
||||
@if($msg instanceof Netmail)
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
TAGLINE: <br><strong class="highlight">{{ $msg->tagline }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($msg->isNetmail())
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
VIA: <br><strong class="highlight">{!! $msg->via->join('</strong><br><strong class="highlight">') !!}</strong>
|
||||
VIA: <br><strong class="highlight">{!! $msg->path->join('</strong> -> <strong class="highlight">') !!}</strong>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
@ -159,7 +156,7 @@
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
<strong>KLUDGES:</strong> <br>
|
||||
@foreach ($msg->kludge->sort(function($v,$k) { return $k; })->reverse() as $k => $v)
|
||||
@foreach ($msg->kludges->sort(function($v,$k) { return $k; })->reverse() as $k => $v)
|
||||
<strong class="highlight">{{ $k }}</strong> {{ $v }}<br>
|
||||
@endforeach
|
||||
</div>
|
||||
|
@ -217,7 +217,9 @@
|
||||
@if(($x=$oo->systems->where('pivot.default',TRUE))->count() && ($x->first()->id !== $o->id))
|
||||
<i class="bi bi-dash-square"></i>
|
||||
@else
|
||||
<span class="default" itemid="{{ $oo->id }}"><i class="bi bi-{{ $x->count() ? 'check-square' : 'square' }}"></i></span>
|
||||
@can('admin')
|
||||
<span class="default" itemid="{{ $oo->id }}"><i class="bi bi-{{ $x->count() ? 'check-square' : 'square' }}"></i></span>
|
||||
@endcan
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $oo->pivot->sespass }}</td>
|
||||
@ -239,7 +241,9 @@
|
||||
<p>No session details exist</p>
|
||||
@endif
|
||||
|
||||
@include('system.widget.form-session')
|
||||
@can('update_nn',$o)
|
||||
@include('system.widget.form-session')
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -603,6 +607,7 @@
|
||||
@section('page-scripts')
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
@can('admin')
|
||||
$('.default').click(function () {
|
||||
var item = this;
|
||||
icon = $(item).find('i');
|
||||
@ -634,6 +639,7 @@
|
||||
cache: false
|
||||
})
|
||||
});
|
||||
@endcan
|
||||
$('data.validated').on('click',function(item) {
|
||||
that = $(this);
|
||||
var values = item.delegateTarget.value.split(':');
|
||||
|
@ -42,7 +42,7 @@
|
||||
<tbody>
|
||||
@foreach (\App\Models\System::active()->with(['addresses.zone.domain'])->get() as $oo)
|
||||
<tr>
|
||||
<td><a href="{{ url('system/addedit',[$oo->id]) }}" @cannot('update',$oo)class="disabled" @endcannot>{{ $oo->id }}</a></td>
|
||||
<td><a href="{{ url('system/addedit',[$oo->id]) }}" @cannot('update_nn',$oo)class="disabled" @endcannot>{{ $oo->id }}</a></td>
|
||||
<td>{{ $oo->name }} @if(! $oo->active)<span class="float-end"><small>[i]</small></span>@endif</td>
|
||||
<td>{{ $oo->sysop }}</td>
|
||||
<td>{{ $oo->location }}</td>
|
||||
|
@ -36,7 +36,7 @@
|
||||
@endif
|
||||
</span>
|
||||
|
||||
@can('update',$o)
|
||||
@can('update_nn',$o)
|
||||
<div class="col-2">
|
||||
<button type="submit" name="submit" class="btn btn-success float-end">Add</button>
|
||||
</div>
|
||||
|
@ -36,7 +36,7 @@
|
||||
@endif
|
||||
</span>
|
||||
|
||||
@can('update',$o)
|
||||
@can('update_nn',$o)
|
||||
<div class="col-2">
|
||||
<button type="submit" name="submit" class="btn btn-success float-end">Add</button>
|
||||
</div>
|
||||
|
@ -1,6 +1,10 @@
|
||||
<!-- $o = System::class -->
|
||||
@if(($x=\App\Models\Zone::active()
|
||||
->whereIn('id',$o->zones->pluck('id'))
|
||||
@php
|
||||
use App\Models\Zone;
|
||||
@endphp
|
||||
|
||||
@if(($x=Zone::active()
|
||||
->whereIn('id',$o->addresses->pluck('zone.id'))
|
||||
->whereNotIn('id',$o->sessions->pluck('id'))
|
||||
->with(['domain'])
|
||||
->get())->count())
|
||||
@ -42,7 +46,7 @@
|
||||
<label for="sespass" class="form-label">Session Password</label>
|
||||
<div class="input-group has-validation">
|
||||
<span class="input-group-text"><i class="bi bi-lock"></i></span>
|
||||
<input type="text" style="width: 35%;" class="form-control @error('sespass') is-invalid @enderror" id="sespass" placeholder="Session" name="sespass" value="{{ old('sespass') }}" @cannot('update',$o)disabled @endcannot required>
|
||||
<input type="text" style="width: 35%;" class="form-control @error('sespass') is-invalid @enderror" id="sespass" placeholder="Session" name="sespass" value="{{ old('sespass') }}" required>
|
||||
<span class="invalid-feedback" role="alert">
|
||||
@error('sespass')
|
||||
{{ $message }}
|
||||
@ -58,7 +62,7 @@
|
||||
<label for="pktpass" class="form-label">Packet Password</label>
|
||||
<div class="input-group has-validation">
|
||||
<span class="input-group-text"><i class="bi bi-box"></i></span>
|
||||
<input type="text" style="width: 35%;" class="form-control @error('pktpass') is-invalid @enderror" id="pktpass" placeholder="Packet" name="pktpass" value="{{ old('pktpass') }}" @cannot('update',$o)disabled @endcannot required>
|
||||
<input type="text" style="width: 35%;" class="form-control @error('pktpass') is-invalid @enderror" id="pktpass" placeholder="Packet" name="pktpass" value="{{ old('pktpass') }}" required>
|
||||
<span class="invalid-feedback" role="alert">
|
||||
@error('pktpass')
|
||||
{{ $message }}
|
||||
@ -76,7 +80,7 @@
|
||||
<label for="fixpass" class="form-label">Areafix Password</label>
|
||||
<div class="input-group has-validation">
|
||||
<span class="input-group-text"><i class="bi bi-card-text"></i></span>
|
||||
<input type="text" style="width: 35%;" class="form-control @error('fixpass') is-invalid @enderror" id="fixpass" placeholder="Areafix" name="fixpass" value="{{ old('fixpass') }}" @cannot('update',$o)disabled @endcannot required>
|
||||
<input type="text" style="width: 35%;" class="form-control @error('fixpass') is-invalid @enderror" id="fixpass" placeholder="Areafix" name="fixpass" value="{{ old('fixpass') }}" required>
|
||||
<span class="invalid-feedback" role="alert">
|
||||
@error('fixpass')
|
||||
{{ $message }}
|
||||
@ -92,7 +96,7 @@
|
||||
<label for="ticpass" class="form-label">TIC Password</label>
|
||||
<div class="input-group has-validation">
|
||||
<span class="input-group-text"><i class="bi bi-archive"></i></span>
|
||||
<input type="text" style="width: 35%;" class="form-control @error('ticpass') is-invalid @enderror" id="ticpass" placeholder="TIC" name="ticpass" value="{{ old('ticpass') }}" @cannot('update',$o)disabled @endcannot required>
|
||||
<input type="text" style="width: 35%;" class="form-control @error('ticpass') is-invalid @enderror" id="ticpass" placeholder="TIC" name="ticpass" value="{{ old('ticpass') }}" required>
|
||||
<span class="invalid-feedback" role="alert">
|
||||
@error('ticpass')
|
||||
{{ $message }}
|
||||
@ -118,11 +122,9 @@
|
||||
@endif
|
||||
</span>
|
||||
|
||||
@can('update',$o)
|
||||
<div class="col-2">
|
||||
<button type="submit" name="submit" class="btn btn-success float-end">Add</button>
|
||||
</div>
|
||||
@endcan
|
||||
<div class="col-2">
|
||||
<button type="submit" name="submit" class="btn btn-success float-end">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,10 +1,11 @@
|
||||
@php
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Models\{Echomail,Netmail};
|
||||
@endphp
|
||||
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
TO: <strong class="highlight">{!! Message::tr($msg->to) !!}</strong> @if ($msg instanceof \App\Models\Netmail)(<strong class="highlight">{{ $msg->tftn->ftn }}</strong>)@endif
|
||||
TO: <strong class="highlight">{!! Message::tr($msg->to) !!}</strong> @if ($msg instanceof Netmail)(<strong class="highlight">{{ $msg->tftn->ftn }}</strong>)@endif
|
||||
</div>
|
||||
<div class="col-4">
|
||||
DATE: <strong class="highlight">{{ $msg->datetime->format('Y-m-d H:i:s') }}</strong>
|
||||
@ -16,19 +17,30 @@ use App\Classes\FTN\Message;
|
||||
FROM: <strong class="highlight">{!! Message::tr($msg->from) !!}</strong> (<strong class="highlight">{{ $msg->fftn->ftn }}</strong>)
|
||||
</div>
|
||||
<div class="col-4">
|
||||
MSGID: <strong class="highlight">{{ $msg->msgid }}</strong>@if($x=\App\Models\Echomail::where('replyid',$msg->msgid)->count()) (<strong class="highlight">{{$x}}</strong> replies)@endif @if($msg->replyid)<br>REPLY: <strong class="highlight">{{ $msg->replyid }}</strong>@endif
|
||||
MSGID: <strong class="highlight">{{ $msg->msgid }}</strong>@if($x=Echomail::where('replyid',$msg->msgid)->count()) (<strong class="highlight">{{$x}}</strong> replies)@endif @if($msg->replyid)<br>REPLY: <strong class="highlight">{{ $msg->replyid }}</strong>@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row pt-1 pb-2">
|
||||
<div class="col-4">
|
||||
SUBJECT: <strong class="highlight">{!! Message::tr($msg->subject) !!}</strong>
|
||||
@if($msg->flags()->count())
|
||||
<div class="row pt-1">
|
||||
<div class="offset-4 col-8">
|
||||
FLAGS: <strong class="highlight">{!! $msg->flags()->keys()->map(fn($item)=>strtoupper($item))->join('</strong>, <strong class="highlight">') !!}</strong>
|
||||
</div>
|
||||
</div>
|
||||
@if ($msg instanceof \App\Models\Echomail)
|
||||
<div class="col-4">
|
||||
@endif
|
||||
|
||||
@if ($msg instanceof Echomail)
|
||||
<div class="row pt-1 pb-2">
|
||||
<div class="offset-4 col-4">
|
||||
ECHOAREA: <strong class="highlight">{{ $msg->echoarea->name }}</strong> (<strong class="highlight">{{ $msg->echoarea->domain->name }}</strong>)
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="row pt-1 pb-2">
|
||||
<div class="col-8">
|
||||
SUBJECT: <strong class="highlight">{!! Message::tr($msg->subject) !!}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row pb-2">
|
||||
@ -39,48 +51,60 @@ use App\Classes\FTN\Message;
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($msg instanceof \App\Models\Echomail)
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
KLUDGES: <br>
|
||||
@foreach($msg->kludges as $k=>$v)
|
||||
<strong class="highlight">{{ $k }}</strong> {{ $v }}<br>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($msg instanceof Echomail)
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
SEENBY: <br><strong class="highlight">{!! $msg->seenby->pluck('ftn2d')->join('</strong>, <strong class="highlight">') !!}</strong>
|
||||
</div>
|
||||
|
||||
@if ($msg->rogue_seenby->count())
|
||||
<br><small>[<strong>NOTE</strong>: Some seen-by values couldnt be identified - ({{ $msg->rogue_seenby->join(',') }})]</small>
|
||||
@if($msg->rogue_seenby->count())
|
||||
<br><small>[<strong>NOTE</strong>: Some seen-by values couldnt be identified - ({{ $msg->rogue_seenby->transform(fn($item)=>str_replace('0:','',$item))->join(',') }})]</small>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($msg->flags & Message::FLAG_LOCAL)
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
<strong class="highlight">Local message</strong>
|
||||
</div>
|
||||
<!-- @todo for the nodes we export to, highlight those that we have actually sent it, vs those that havent received it yet -->
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
PATH: <br><strong class="highlight">{!! $msg->pathorder()->join('</strong> -> <strong class="highlight">') !!}</strong>
|
||||
|
||||
@if(($msg instanceof Echomail) && $msg->rogue_path->count())
|
||||
<br><small>[<strong>NOTE</strong>: Some path values couldnt be identified - ({{ $msg->rogue_path->join(',') }})]</small>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@elseif ((! $msg->flags) || ($msg->flags & (Message::FLAG_INTRANSIT|Message::FLAG_RECD)))
|
||||
<!-- @todo for the nodes we export to, highlight those that we have actually sent it, vs those that havent received it yet -->
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
PATH: <br><strong class="highlight">{!! $msg->pathorder()->join('</strong> -> <strong class="highlight">') !!}</strong>
|
||||
|
||||
@if (($msg instanceof \App\Models\Echomail) && $msg->rogue_path->count())
|
||||
<br><small>[<strong>NOTE</strong>: Some path values couldnt be identified - ({{ $msg->rogue_path->join(',') }})]</small>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
<div class="row pb-2">
|
||||
<div class="col-8">
|
||||
@if($msg instanceof Netmail)
|
||||
RECEIVED:<br>
|
||||
@if ($msg instanceof \App\Models\Netmail)
|
||||
@foreach ($msg->received as $path)
|
||||
<strong class="highlight">{{ $path->pivot->recv_pkt }}</strong> from <strong class="highlight">{{ $path->ftn }}</strong> {{ $msg->created_at }}
|
||||
@endforeach
|
||||
@elseif ($msg instanceof \App\Models\Echomail)
|
||||
<strong class="highlight">{{ ($x=$msg->path->sortBy('pivot.parent_id')->last())->pivot->recv_pkt }}</strong> from <strong class="highlight">{{ $x->ftn }}</strong> {{ $x->pivot->recv_at }}
|
||||
@endif
|
||||
</div>
|
||||
@foreach ($msg->path as $path)
|
||||
<strong class="highlight">{{ $path->pivot->recv_pkt }}</strong> from <strong class="highlight">{{ $path->ftn }}</strong> {{ $msg->created_at }}
|
||||
@endforeach
|
||||
@elseif ($msg instanceof Echomail)
|
||||
RECEIVED:<br>
|
||||
<strong class="highlight">{{ ($x=$msg->path->sortBy('pivot.parent_id')->last())->pivot->recv_pkt }}</strong> from <strong class="highlight">{{ $x->ftn }}</strong> {{ $x->pivot->recv_at }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($msg instanceof Netmail)
|
||||
<div class="col-8">
|
||||
SENT:
|
||||
@if($msg->sent_pkt && $msg->sent_at)
|
||||
<strong class="highlight">{{ $msg->sent_at }}</strong> (<strong class="highlight">{{ $msg->sent_pkt }}.pkt</strong>)
|
||||
@else
|
||||
<strong class="highlight">NOT SENT</strong>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@ -89,18 +113,16 @@ use App\Classes\FTN\Message;
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
var msg = new Uint8Array({!! json_encode(array_values(unpack('C*',str_replace("\r","\n",$msg->msg)))) !!});
|
||||
var msg = new Uint8Array({!! json_encode(array_values(unpack('C*',str_replace("\r","\n",$msg->content)))) !!});
|
||||
retina = window.devicePixelRatio > 1;
|
||||
|
||||
AnsiLove.renderBytes(
|
||||
msg,
|
||||
function (canvas, sauce) {
|
||||
console.log(canvas);
|
||||
document.getElementById("canvas").appendChild(canvas);
|
||||
},
|
||||
{'font': '80x25', 'bits': 8, 'icecolors': 0, 'columns': 80}
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
@append
|
Loading…
Reference in New Issue
Block a user