Implemented file sending during BINKP and EMSI sessions
This commit is contained in:
@@ -4,16 +4,18 @@ namespace App\Classes\FTN;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use League\Flysystem\UnableToWriteFile;
|
||||
|
||||
use App\Classes\FTN as FTNBase;
|
||||
use App\Models\{Address,File,Filearea};
|
||||
use App\Models\{Address,File,Filearea,Setup};
|
||||
use App\Traits\EncodeUTF8;
|
||||
|
||||
/**
|
||||
* Class TIC
|
||||
* Used create the structure of TIC files
|
||||
*
|
||||
* @package App\Classes
|
||||
*/
|
||||
@@ -50,34 +52,96 @@ class Tic extends FTNBase
|
||||
'pw' => FALSE, // Password
|
||||
];
|
||||
|
||||
private File $file;
|
||||
private File $fo;
|
||||
private Filearea $area;
|
||||
private ?string $areadesc = NULL;
|
||||
private ?string $pw = NULL;
|
||||
private Collection $values;
|
||||
|
||||
private Address $origin; // Should be first address in Path
|
||||
private Address $from; // Should be last address in Path
|
||||
private Address $to; // Should be me
|
||||
|
||||
public function __construct(private string $filename) {
|
||||
public function __construct()
|
||||
{
|
||||
$this->fo = new File;
|
||||
|
||||
$this->fo->kludges = collect();
|
||||
$this->fo->set_path = collect();
|
||||
$this->fo->set_seenby = collect();
|
||||
$this->fo->rogue_path = collect();
|
||||
$this->fo->rogue_seenby = collect();
|
||||
|
||||
$this->values = collect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this TIC file bring us a nodelist
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isNodelist(): bool
|
||||
{
|
||||
return (($this->fo->nodelist_filearea_id === $this->fo->filearea->domain->filearea_id)
|
||||
&& (preg_match(str_replace(['.','?'],['\.','.'],'#^'.$this->fo->filearea->domain->nodelist_filename.'$#i'),$this->fo->file)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a TIC file for an address
|
||||
*
|
||||
* @param Address $ao
|
||||
* @param File $fo
|
||||
* @return string
|
||||
*/
|
||||
public function generate(Address $ao,File $fo): string
|
||||
{
|
||||
$sysaddress = Setup::findOrFail(config('app.id'))->system->match($ao->zone)->first();
|
||||
|
||||
$result = collect();
|
||||
|
||||
// Origin is the first address in our path
|
||||
$result->put('ORIGIN',$fo->path->first()->ftn3d);
|
||||
$result->put('FROM',$sysaddress->ftn3d);
|
||||
$result->put('TO',$ao->ftn3d);
|
||||
$result->put('FILE',$fo->file);
|
||||
$result->put('SIZE',$fo->size);
|
||||
if ($fo->description)
|
||||
$result->put('DESC',$fo->description);
|
||||
$result->put('AREA',$fo->filearea->name);
|
||||
$result->put('AREADESC',$fo->filearea->description);
|
||||
$result->put('PW',$ao->session('ticpass'));
|
||||
$result->put('CRC',sprintf("%X",$fo->crc));
|
||||
|
||||
$out = '';
|
||||
foreach ($result as $key=>$value)
|
||||
$out .= sprintf("%s %s\r\n",$key,$value);
|
||||
|
||||
foreach ($fo->path as $o)
|
||||
$out .= sprintf("PATH %s %s %s\r\n",$o->ftn3d,$o->pivot->datetime,$o->pivot->extra);
|
||||
|
||||
foreach ($fo->seenby as $o)
|
||||
$out .= sprintf("SEENBY %s\r\n",$o->ftn3d);
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a TIC file from an existing filename
|
||||
*
|
||||
* @param string $filename
|
||||
* @return void
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public function load(string $filename): void
|
||||
{
|
||||
Log::info(sprintf('%s:Processing TIC file [%s]',self::LOGKEY,$filename));
|
||||
|
||||
$fo = new File;
|
||||
|
||||
$fo->kludges = collect();
|
||||
$fo->set_path = collect();
|
||||
$fo->set_seenby = collect();
|
||||
$fo->rogue_path = collect();
|
||||
$fo->rogue_seenby = collect();
|
||||
|
||||
list($hex,$name) = explode('-',$filename);
|
||||
$hex = basename($hex);
|
||||
|
||||
if (! file_exists($filename))
|
||||
throw new FileNotFoundException(sprintf('%s:File [%s] doesnt exist',self::LOGKEY,realpath($filename)));
|
||||
|
||||
if (! is_writable($filename))
|
||||
throw new UnableToWriteFile(sprintf('%s:File [%s] is not writable',self::LOGKEY,realpath($filename)));
|
||||
if (! is_readable($filename))
|
||||
throw new UnableToWriteFile(sprintf('%s:File [%s] is not readable',self::LOGKEY,realpath($filename)));
|
||||
|
||||
$f = fopen($filename,'rb');
|
||||
if (! $f) {
|
||||
@@ -112,38 +176,43 @@ class Tic extends FTNBase
|
||||
if (! Storage::disk('local')->exists($x=sprintf('%s/%s-%s',config('app.fido'),$hex,$matches[2])))
|
||||
throw new FileNotFoundException(sprintf('File not found? [%s]',$x));
|
||||
|
||||
$fo->{$k} = $matches[2];
|
||||
$fo->fullname = $x;
|
||||
$this->fo->{$k} = $matches[2];
|
||||
$this->fo->fullname = $x;
|
||||
break;
|
||||
|
||||
case 'areadesc':
|
||||
case 'pw':
|
||||
case 'created':
|
||||
$this->{$k} = $matches[2];
|
||||
$areadesc = $matches[2];
|
||||
break;
|
||||
|
||||
case 'lfile':
|
||||
case 'size':
|
||||
case 'created':
|
||||
// ignored
|
||||
break;
|
||||
|
||||
case 'pw':
|
||||
$pw = $matches[2];
|
||||
|
||||
case 'desc':
|
||||
case 'lfile':
|
||||
case 'magic':
|
||||
case 'replaces':
|
||||
$fo->{$k} = $matches[2];
|
||||
case 'size':
|
||||
$this->fo->{$k} = $matches[2];
|
||||
break;
|
||||
|
||||
case 'fullname':
|
||||
$fo->lfile = $matches[2];
|
||||
$this->fo->lfile = $matches[2];
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
$fo->datetime = Carbon::create($matches[2]);
|
||||
$this->fo->datetime = Carbon::create($matches[2]);
|
||||
break;
|
||||
|
||||
case 'ldesc':
|
||||
$fo->{$k} .= $matches[2];
|
||||
$this->fo->{$k} .= $matches[2];
|
||||
break;
|
||||
|
||||
case 'crc':
|
||||
$fo->{$k} = hexdec($matches[2]);
|
||||
$this->fo->{$k} = hexdec($matches[2]);
|
||||
break;
|
||||
|
||||
case 'path':
|
||||
@@ -152,9 +221,9 @@ class Tic extends FTNBase
|
||||
$ao = Address::findFTN($x[1]);
|
||||
|
||||
if (! $ao) {
|
||||
$fo->rogue_path->push($matches[2]);
|
||||
$this->fo->rogue_path->push($matches[2]);
|
||||
} else {
|
||||
$fo->set_path->push(['address'=>$ao,'datetime'=>Carbon::createFromTimestamp($x[8]),'extra'=>$x[9]]);
|
||||
$this->fo->set_path->push(['address'=>$ao,'datetime'=>Carbon::createFromTimestamp($x[8]),'extra'=>$x[9]]);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -163,36 +232,36 @@ class Tic extends FTNBase
|
||||
$ao = Address::findFTN($matches[2]);
|
||||
|
||||
if (! $ao) {
|
||||
$fo->rogue_seenby->push($matches[2]);
|
||||
$this->fo->rogue_seenby->push($matches[2]);
|
||||
} else {
|
||||
$fo->set_seenby->push($ao->id);
|
||||
$this->fo->set_seenby->push($ao->id);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
$fo->kludges->push($line);
|
||||
$this->fo->kludges->push($line);
|
||||
}
|
||||
}
|
||||
|
||||
fclose($f);
|
||||
|
||||
$f = fopen($x=Storage::disk('local')->path($fo->fullname),'rb');
|
||||
$f = fopen($x=Storage::disk('local')->path($this->fo->fullname),'rb');
|
||||
$stat = fstat($f);
|
||||
fclose($f);
|
||||
|
||||
// Validate Size
|
||||
if ($fo->size !== ($y=$stat['size']))
|
||||
throw new \Exception(sprintf('TIC file size [%d] doesnt match file [%s] (%d)',$fo->size,$fo->fullname,$y));
|
||||
if ($this->fo->size !== ($y=$stat['size']))
|
||||
throw new \Exception(sprintf('TIC file size [%d] doesnt match file [%s] (%d)',$this->fo->size,$this->fo->fullname,$y));
|
||||
|
||||
// Validate CRC
|
||||
if (sprintf('%08x',$fo->crc) !== ($y=hash_file('crc32b',$x)))
|
||||
throw new \Exception(sprintf('TIC file CRC [%08x] doesnt match file [%s] (%s)',$fo->crc,$fo->fullname,$y));
|
||||
if (sprintf('%08x',$this->fo->crc) !== ($y=hash_file('crc32b',$x)))
|
||||
throw new \Exception(sprintf('TIC file CRC [%08x] doesnt match file [%s] (%s)',$this->fo->crc,$this->fo->fullname,$y));
|
||||
|
||||
// Validate Password
|
||||
if ($this->pw !== ($y=$this->from->session('ticpass')))
|
||||
throw new \Exception(sprintf('TIC file PASSWORD [%s] doesnt match system [%s] (%s)',$this->pw,$this->from->ftn,$y));
|
||||
if ($pw !== ($y=$this->from->session('ticpass')))
|
||||
throw new \Exception(sprintf('TIC file PASSWORD [%s] doesnt match system [%s] (%s)',$pw,$this->from->ftn,$y));
|
||||
|
||||
// Validate Sender is linked (and permitted to send)
|
||||
if ($this->from->fileareas->search(function($item) { return $item->id === $this->area->id; }) === FALSE)
|
||||
@@ -200,7 +269,7 @@ class Tic extends FTNBase
|
||||
|
||||
// If the filearea is to be autocreated, create it
|
||||
if (! $this->area->exists) {
|
||||
$this->area->description = $this->areadesc;
|
||||
$this->area->description = $areadesc;
|
||||
$this->area->active = TRUE;
|
||||
$this->area->public = FALSE;
|
||||
$this->area->notes = 'Autocreated';
|
||||
@@ -208,21 +277,13 @@ class Tic extends FTNBase
|
||||
$this->area->save();
|
||||
}
|
||||
|
||||
$fo->filearea_id = $this->area->id;
|
||||
$fo->fftn_id = $this->origin->id;
|
||||
$this->fo->filearea_id = $this->area->id;
|
||||
$this->fo->fftn_id = $this->origin->id;
|
||||
|
||||
// If the file create time is blank, we'll take the files
|
||||
if (! $fo->datetime)
|
||||
$fo->datetime = Carbon::createFromTimestamp($stat['ctime']);
|
||||
if (! $this->fo->datetime)
|
||||
$this->fo->datetime = Carbon::createFromTimestamp($stat['ctime']);
|
||||
|
||||
$fo->save();
|
||||
|
||||
$this->fo = $fo;
|
||||
}
|
||||
|
||||
public function isNodelist(): bool
|
||||
{
|
||||
return (($this->fo->nodelist_filearea_id === $this->fo->filearea->domain->filearea_id)
|
||||
&& (preg_match(str_replace(['.','?'],['\.','.'],'#^'.$this->fo->filearea->domain->nodelist_filename.'$#i'),$this->fo->file)));
|
||||
$this->fo->save();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user