diff --git a/app/Casts/CompressedString.php b/app/Casts/CompressedString.php index b14248c..6480c3a 100644 --- a/app/Casts/CompressedString.php +++ b/app/Casts/CompressedString.php @@ -14,11 +14,11 @@ class CompressedString implements CastsAttributes * @param string $key * @param mixed $value * @param array $attributes - * @return string|null + * @return string */ - public function get($model,string $key,$value,array $attributes): ?string + public function get($model,string $key,$value,array $attributes): string { - return $value ? zstd_uncompress(base64_decode($value)) : NULL; + return $value ? zstd_uncompress(base64_decode($value)) : ''; } /** @@ -28,10 +28,10 @@ class CompressedString implements CastsAttributes * @param string $key * @param mixed $value * @param array $attributes - * @return string|null + * @return string */ - public function set($model,string $key,$value,array $attributes): ?string + public function set($model,string $key,$value,array $attributes): string { - return $value ? base64_encode(zstd_compress($value)) : NULL; + return $value ? base64_encode(zstd_compress($value)) : ''; } } \ No newline at end of file diff --git a/app/Classes/FTN/Message.php b/app/Classes/FTN/Message.php index 15d32a7..b0a8016 100644 --- a/app/Classes/FTN/Message.php +++ b/app/Classes/FTN/Message.php @@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Validator as ValidatorResult; use App\Classes\FTN as FTNBase; +use App\Http\Controllers\DomainController; use App\Models\{Address,Domain,Zone}; use App\Rules\{TwoByteInteger,TwoByteIntegerWithZero}; use App\Traits\EncodeUTF8; @@ -97,7 +98,7 @@ class Message extends FTNBase private string $msgid; // MSG ID private string $replyid; // Reply ID - private string $gateid; // MSG ID if the message came via gate + private string $gateid; // MSG ID if the message came via gate private string $echoarea; // FTS-0004.001 private string $intl; // Netmail details @@ -632,7 +633,7 @@ class Message extends FTNBase /** * Parse the Seenby/path lines and return a collection of addresses * - * @param string $type + * @param string $type Type of address, ie: seenby/path * @param Collection $addresses * @param Collection $rogue * @return Collection @@ -658,7 +659,7 @@ class Message extends FTNBase $node = (int)$item; }; - $ftn = sprintf('%d:%d/%d',$this->fz,$net&0x7fff,$node&0x7fff); + $ftn = sprintf('%d:%d/%d',$this->fz,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX); // @todo This should be enhanced to include the address at the time of the message. if ($aos->has($ftn)) $ao = $aos->get($ftn); @@ -712,6 +713,48 @@ class Message extends FTNBase } } + /** + * Parse the via address and return a collection of addresses + * + * @YYYYMMDD.HHMMSS[.Precise][.Time Zone] [Serial Number] + * + * @param Collection $via + * @param Collection $rogue + * @return Collection + */ + private function parseVia(Collection $via,Collection &$rogue): Collection + { + $nodes = collect(); + + foreach ($via 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]); + + // 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 (! $ao) { + Log::alert(sprintf('%s:! Undefined Node [%s] for Netmail.',self::LOGKEY,$m[1])); + //$rogue->push(['node'=>$m[1],'datetime'=>$datetime,'program'=>$m[4]]); + + } else { + $nodes->push(['node'=>$ao,'datetime'=>$datetime,'program'=>$m[4]]); + } + } + } + + return $nodes; + } + /** * Extract information out of the message text. * @@ -904,6 +947,10 @@ class Message extends FTNBase // Parse PATH if ($this->path->count()) $this->pathaddress = $this->parseAddresses('path',$this->path,$this->rogue_path); + + // Parse VIA + if ($this->via->count()) + $this->pathaddress = $this->parseVia($this->via,$this->rogue_path); } /** diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 00da20f..dc056c3 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Gate; use App\Classes\File; use App\Classes\FTN\Packet; -use App\Models\{Address,Domain,Echomail,Setup}; +use App\Models\{Address,Domain,Echomail,Netmail,Setup}; class HomeController extends Controller { @@ -97,7 +97,7 @@ class HomeController extends Controller list($zone_id,$host_id,$node_id,$point_id,$domain) = sscanf($request->query('term'),'%d:%d/%d.%d@%s'); - # Look for Systems + // Look for Systems foreach (Address::select(['systems.name',DB::raw('systems.id AS system_id'),'zones.zone_id','region_id','host_id','node_id','point_id']) ->join('zones',['zones.id'=>'addresses.zone_id']) ->rightjoin('systems',['systems.id'=>'addresses.system_id']) @@ -124,7 +124,7 @@ class HomeController extends Controller $result->push(['id'=>$o->system_id,'name'=>$o->name.($ftn ? ' '.$ftn : ''),'value'=>url('system/view',[$o->system_id]),'category'=>'Systems']); } - # Look for Messages + // Look for Echomail foreach (Echomail::select(['id','fftn_id','from']) ->where('msgid','like','%'.$request->query('term').'%') ->orWhere('replyid','like','%'.$request->query('term').'%') @@ -133,6 +133,16 @@ class HomeController extends Controller $result->push(['id'=>$o->id,'name'=>sprintf('%s (%s)',$o->from,$o->fftn->ftn3d),'value'=>url('echomail/view',[$o->id]),'category'=>'Echomail']); } + // Look for Netmail + if (Gate::check('admin')) + foreach (Netmail::select(['id','fftn_id','from']) + ->where('msgid','like','%'.$request->query('term').'%') + ->orWhere('replyid','like','%'.$request->query('term').'%') + ->get() as $o) + { + $result->push(['id'=>$o->id,'name'=>sprintf('%s (%s)',$o->from,$o->fftn->ftn3d),'value'=>url('netmail/view',[$o->id]),'category'=>'Netmail']); + } + return $result->unique(['id'])->take(10)->values(); } diff --git a/app/Http/Controllers/NetmailController.php b/app/Http/Controllers/NetmailController.php new file mode 100644 index 0000000..cd0af3c --- /dev/null +++ b/app/Http/Controllers/NetmailController.php @@ -0,0 +1,19 @@ +middleware('auth'); + } + + public function view(Netmail $o) + { + return view('netmail.view') + ->with('o',$o); + } +} \ No newline at end of file diff --git a/app/Jobs/MessageProcess.php b/app/Jobs/MessageProcess.php index 51867bd..f09c6df 100644 --- a/app/Jobs/MessageProcess.php +++ b/app/Jobs/MessageProcess.php @@ -54,6 +54,7 @@ class MessageProcess implements ShouldQueue $o = $this->create_netmail($this->msg); $o->recv_pkt = $this->packet; + $o->set_path = $this->msg->pathaddress; // Determine if the message is to this system, or in transit if ($ftns->search(function($item) { return $this->msg->tftn == $item->ftn; }) !== FALSE) { diff --git a/app/Models/Netmail.php b/app/Models/Netmail.php index a205c27..d9fbb9b 100644 --- a/app/Models/Netmail.php +++ b/app/Models/Netmail.php @@ -5,8 +5,11 @@ namespace App\Models; use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +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\Interfaces\Packet; use App\Traits\{EncodeUTF8,MsgID}; @@ -17,6 +20,8 @@ final class Netmail extends Model implements Packet use SoftDeletes,EncodeUTF8,MsgID; + private Collection $set_path; + private const cast_utf8 = [ 'to', 'from', @@ -30,6 +35,44 @@ final class Netmail extends Model implements Packet protected $dates = ['datetime','sent_at']; + protected $casts = [ + 'msg' => CompressedString::class, + 'msg_src' => CompressedString::class, + ]; + + public function __set($key,$value) + { + switch ($key) { + case 'set_path': + $this->{$key} = $value; + break; + + default: + parent::__set($key,$value); + } + } + + public static function boot() + { + parent::boot(); + + static::created(function($model) { + // Save the Path + $ppoid = NULL; + foreach ($model->set_path as $path) { + $po = DB::select('INSERT INTO netmail_path (netmail_id,address_id,parent_id,datetime,program) VALUES (?,?,?,?,?) RETURNING id',[ + $model->id, + $path['node']->id, + $ppoid, + (string)$path['datetime'], + $path['program'], + ]); + + $ppoid = $po[0]->id; + } + }); + } + /* RELATIONS */ public function fftn() @@ -39,6 +82,12 @@ final class Netmail extends Model implements Packet ->withTrashed(); } + public function path() + { + return $this->belongsToMany(Address::class,'netmail_path') + ->withPivot(['id','parent_id','datetime','program']); + } + public function tftn() { return $this @@ -113,4 +162,16 @@ final class Netmail extends Model implements Packet 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(); + } } \ No newline at end of file diff --git a/database/migrations/2023_06_18_160504_netmailpath.php b/database/migrations/2023_06_18_160504_netmailpath.php new file mode 100644 index 0000000..0302e29 --- /dev/null +++ b/database/migrations/2023_06_18_160504_netmailpath.php @@ -0,0 +1,45 @@ +id(); + + $table->bigInteger('address_id'); + $table->foreign('address_id')->references('id')->on('addresses'); + + $table->unique(['id','netmail_id']); + $table->unique(['netmail_id','address_id','parent_id']); + + $table->bigInteger('parent_id')->nullable(); + $table->foreign(['parent_id','netmail_id'])->references(['id','netmail_id'])->on('netmail_path'); + + $table->bigInteger('netmail_id'); + $table->foreign('netmail_id')->references('id')->on('netmails'); + + $table->dateTime('datetime'); + $table->string('program'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('netmail_path'); + } +}; diff --git a/resources/views/netmail/view.blade.php b/resources/views/netmail/view.blade.php new file mode 100644 index 0000000..fa3d820 --- /dev/null +++ b/resources/views/netmail/view.blade.php @@ -0,0 +1,10 @@ +@extends('layouts.app') +@section('htmlheader_title') + Message View +@endsection + +@section('content') +

Netmail

+ + @include('widgets.message',['msg'=>$o]) +@endsection \ No newline at end of file diff --git a/resources/views/widgets/message.blade.php b/resources/views/widgets/message.blade.php index 6d989cc..c49688b 100644 --- a/resources/views/widgets/message.blade.php +++ b/resources/views/widgets/message.blade.php @@ -1,6 +1,6 @@
- TO: {!! \App\Classes\FTN\Message::tr($msg->to) !!} + TO: {!! \App\Classes\FTN\Message::tr($msg->to) !!}@if ($msg instanceof \App\Models\Netmail)({{ $msg->tftn->ftn }})@endif
DATE: {{ $msg->datetime->format('Y-m-d H:i:s') }} @@ -35,11 +35,13 @@
-
-
- SEENBY:
{!! optimize_path($msg->seenby->pluck('ftn2d'))->join(', ') !!} +@if ($msg instanceof \App\Models\Echomail) +
+
+ SEENBY:
{!! optimize_path($msg->seenby->pluck('ftn2d'))->join(', ') !!} +
-
+@endif
diff --git a/routes/web.php b/routes/web.php index cd745da..f39f079 100644 --- a/routes/web.php +++ b/routes/web.php @@ -8,6 +8,7 @@ use App\Http\Controllers\{HomeController, EchoareaController, EchomailController, FileareaController, + NetmailController, SystemController, UserController, UserSwitchController, @@ -106,6 +107,7 @@ Route::middleware(['auth','can:admin'])->group(function () { Route::match(['get','post'],'setup',[HomeController::class,'setup']); Route::get('echomail/view/{o}',[EchomailController::class,'view']); + Route::get('netmail/view/{o}',[NetmailController::class,'view']); Route::get('user/list',[UserController::class,'home']); Route::match(['get','post'],'user/addedit/{o?}',[UserController::class,'add_edit']) ->where('o','[0-9]+');