Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
e65e664792 | |||
4f6e1e90c6 |
61
.env.example
61
.env.example
@ -1,25 +1,55 @@
|
|||||||
APP_NAME="Clearing Houz"
|
APP_NAME="Clearing Houz"
|
||||||
|
APP_ENV=production
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
APP_MAINTENANCE_DRIVER=cache
|
APP_DEBUG=false
|
||||||
APP_MAINTENANCE_STORE=memcached
|
APP_URL=http://clrghouz
|
||||||
APP_TIMEZONE=
|
APP_TIMEZONE=
|
||||||
APP_URL=
|
|
||||||
|
|
||||||
AUTH_PASSWORD_RESET_TOKEN_TABLE=password_resets
|
LOG_CHANNEL=stack
|
||||||
|
LOG_LEVEL=info
|
||||||
CACHE_STORE=memcached
|
|
||||||
MEMCACHED_HOST=memcached
|
|
||||||
|
|
||||||
DB_CONNECTION=pgsql
|
DB_CONNECTION=pgsql
|
||||||
DB_HOST=postgres
|
DB_HOST=postgres
|
||||||
|
DB_PORT=5432
|
||||||
DB_DATABASE=clrghouz
|
DB_DATABASE=clrghouz
|
||||||
DB_USERNAME=clrghouz
|
DB_USERNAME=clrghouz
|
||||||
DB_PASSWORD=
|
DB_PASSWORD=
|
||||||
|
#DB_SSLMODE=prefer
|
||||||
|
#DB_SSLROOTCERT=/var/www/html/config/ssl/ca.crt
|
||||||
|
#DB_SSLCERT=/var/www/html/config/ssl/client.crt
|
||||||
|
#DB_SSLKEY=/var/www/html/config/ssl/client.key
|
||||||
|
|
||||||
|
BROADCAST_DRIVER=log
|
||||||
|
MEMCACHED_HOST=memcached
|
||||||
|
CACHE_DRIVER=memcached
|
||||||
QUEUE_CONNECTION=database
|
QUEUE_CONNECTION=database
|
||||||
SESSION_DRIVER=file
|
SESSION_DRIVER=file
|
||||||
SESSION_LIFETIME=120
|
SESSION_LIFETIME=120
|
||||||
|
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_DRIVER=smtp
|
||||||
|
MAIL_HOST=mail.dege.lan
|
||||||
|
MAIL_PORT=25
|
||||||
|
MAIL_USERNAME=
|
||||||
|
MAIL_PASSWORD=
|
||||||
|
MAIL_ENCRYPTION=
|
||||||
|
MAIL_AUTO_EMBED_METHOD=base64
|
||||||
|
|
||||||
|
PUSHER_APP_ID=
|
||||||
|
PUSHER_APP_KEY=
|
||||||
|
PUSHER_APP_SECRET=
|
||||||
|
PUSHER_APP_CLUSTER=mt1
|
||||||
|
|
||||||
|
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||||
|
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||||
|
|
||||||
|
FIDO_DIR=fido
|
||||||
|
FIDO_PACKET_KEEP=
|
||||||
|
FIDO_STRICT=false
|
||||||
|
|
||||||
FILESYSTEM_DISK=s3
|
FILESYSTEM_DISK=s3
|
||||||
AWS_ACCESS_KEY_ID=
|
AWS_ACCESS_KEY_ID=
|
||||||
AWS_SECRET_ACCESS_KEY=
|
AWS_SECRET_ACCESS_KEY=
|
||||||
@ -28,23 +58,6 @@ AWS_ENDPOINT=
|
|||||||
AWS_DEFAULT_REGION=home
|
AWS_DEFAULT_REGION=home
|
||||||
AWS_USE_PATH_STYLE_ENDPOINT=true
|
AWS_USE_PATH_STYLE_ENDPOINT=true
|
||||||
|
|
||||||
LOG_CHANNEL=daily
|
|
||||||
LOG_LEVEL=info
|
|
||||||
LOG_DAILY_DAYS=93
|
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
|
||||||
MAIL_HOST=smtp
|
|
||||||
MAIL_PORT=25
|
|
||||||
MAIL_USERNAME=
|
|
||||||
MAIL_PASSWORD=
|
|
||||||
MAIL_ENCRYPTION=
|
|
||||||
MAIL_AUTO_EMBED_METHOD=base64
|
|
||||||
|
|
||||||
SESSION_DRIVER=file
|
|
||||||
|
|
||||||
# Clrghouz configuration
|
|
||||||
FIDO_DNS_NS=
|
|
||||||
|
|
||||||
MATRIX_SERVER=
|
MATRIX_SERVER=
|
||||||
MATRIX_AS_TOKEN=
|
MATRIX_AS_TOKEN=
|
||||||
MATRIX_HS_TOKEN=
|
MATRIX_HS_TOKEN=
|
||||||
|
@ -74,7 +74,8 @@ jobs:
|
|||||||
( dockerd --host=tcp://0.0.0.0:2375 --tls=false & ) && sleep 3
|
( dockerd --host=tcp://0.0.0.0:2375 --tls=false & ) && sleep 3
|
||||||
## Some debugging info
|
## Some debugging info
|
||||||
# docker info && docker version
|
# docker info && docker version
|
||||||
# env|sort
|
env|sort
|
||||||
|
echo "PRT: ${{ secrets.PKG_WRITE_TOKEN }}"
|
||||||
|
|
||||||
- name: Registry FQDN Setup
|
- name: Registry FQDN Setup
|
||||||
id: registry
|
id: registry
|
||||||
@ -92,10 +93,12 @@ jobs:
|
|||||||
- name: Code Checkout
|
- name: Code Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Record version and Delete Unnecessary files
|
- name: Record version
|
||||||
run: |
|
run: |
|
||||||
|
pwd
|
||||||
|
ls -al
|
||||||
echo ${GITHUB_SHA::8} > VERSION
|
echo ${GITHUB_SHA::8} > VERSION
|
||||||
rm -rf .git* tests/ storage/app/test/
|
cat VERSION
|
||||||
|
|
||||||
- name: Build and Push Docker Image
|
- name: Build and Push Docker Image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models\Casts;
|
namespace App\Casts;
|
||||||
|
|
||||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
class CollectionOrNull implements CastsAttributes
|
class CollectionOrNull implements CastsAttributes
|
||||||
@ -11,13 +10,13 @@ class CollectionOrNull implements CastsAttributes
|
|||||||
/**
|
/**
|
||||||
* Cast the given value.
|
* Cast the given value.
|
||||||
*
|
*
|
||||||
* @param Model $model
|
* @param \Illuminate\Database\Eloquent\Model $model
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @param array $attributes
|
* @param array $attributes
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function get(Model $model,string $key,$value,array $attributes): Collection
|
public function get($model,string $key,$value,array $attributes): Collection
|
||||||
{
|
{
|
||||||
return collect(json_decode($value, true));
|
return collect(json_decode($value, true));
|
||||||
}
|
}
|
||||||
@ -31,7 +30,7 @@ class CollectionOrNull implements CastsAttributes
|
|||||||
* @param array $attributes
|
* @param array $attributes
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function set(Model $model,string $key,$value,array $attributes): ?string
|
public function set($model,string $key,$value,array $attributes): ?string
|
||||||
{
|
{
|
||||||
return ($value->count()) ? json_encode($value) : NULL;
|
return ($value->count()) ? json_encode($value) : NULL;
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models\Casts;
|
namespace App\Casts;
|
||||||
|
|
||||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models\Casts;
|
namespace App\Casts;
|
||||||
|
|
||||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
@ -100,7 +100,7 @@ class HubStats extends Dynamic
|
|||||||
$o->uncollected_echomail ?? 0,
|
$o->uncollected_echomail ?? 0,
|
||||||
$o->uncollected_netmail ?? 0,
|
$o->uncollected_netmail ?? 0,
|
||||||
$o->uncollected_files ?? 0,
|
$o->uncollected_files ?? 0,
|
||||||
$o->system->last_seen?->format('Y-m-d H:i') ?: '-',
|
$o->system->last_session?->format('Y-m-d H:i'),
|
||||||
is_null($o->system->pollmode) ? 'HOLD' : ($o->system->pollmode ? 'CRASH' : 'DAILY'),
|
is_null($o->system->pollmode) ? 'HOLD' : ($o->system->pollmode ? 'CRASH' : 'DAILY'),
|
||||||
$o->system->autohold ? 'YES' : 'NO');
|
$o->system->autohold ? 'YES' : 'NO');
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ class NodelistSegment extends Dynamic
|
|||||||
$result->push('CM');
|
$result->push('CM');
|
||||||
|
|
||||||
if ($ao->system->address) {
|
if ($ao->system->address) {
|
||||||
$result->push(sprintf('INA:%s',our_address($ao->domain)->contains($ao->id) ? our_hostname($ao) : $ao->system->address));
|
$result->push(sprintf('INA:%s',$ao->system->address));
|
||||||
|
|
||||||
if (($x=$ao->system->mailers->pluck('name')->search('BINKP')) !== FALSE)
|
if (($x=$ao->system->mailers->pluck('name')->search('BINKP')) !== FALSE)
|
||||||
$result->push(sprintf('IBN%s',(($y=$ao->system->mailers->get($x)->pivot->port) !== 24554) ? ':'.$y : ''));
|
$result->push(sprintf('IBN%s',(($y=$ao->system->mailers->get($x)->pivot->port) !== 24554) ? ':'.$y : ''));
|
||||||
|
@ -17,7 +17,7 @@ abstract class FTN
|
|||||||
$this->fn,
|
$this->fn,
|
||||||
$this->ff,
|
$this->ff,
|
||||||
$this->fp,
|
$this->fp,
|
||||||
).((isset($this->zone) && $this->zone) ? sprintf('@%s',$this->zone->domain->name) : '');
|
).($this->zone ? sprintf('@%s',$this->zone->domain->name) : '');
|
||||||
|
|
||||||
case 'tftn_t':
|
case 'tftn_t':
|
||||||
return sprintf('%d:%d/%d.%d',
|
return sprintf('%d:%d/%d.%d',
|
||||||
@ -25,7 +25,7 @@ abstract class FTN
|
|||||||
$this->tn,
|
$this->tn,
|
||||||
$this->tf,
|
$this->tf,
|
||||||
$this->tp,
|
$this->tp,
|
||||||
).((isset($this->zone) && $this->zone) ? sprintf('@%s',$this->zone->domain->name) : '');
|
).($this->zone ? sprintf('@%s',$this->zone->domain->name) : '');
|
||||||
|
|
||||||
case 'fftn':
|
case 'fftn':
|
||||||
return Address::findFTN($this->fftn_t);
|
return Address::findFTN($this->fftn_t);
|
||||||
|
@ -89,7 +89,7 @@ class Message extends FTNBase
|
|||||||
public const AREATAG_LEN = 35; //
|
public const AREATAG_LEN = 35; //
|
||||||
|
|
||||||
private array $header; // Message Header
|
private array $header; // Message Header
|
||||||
private Collection $kludges; // TZUTC that needs to be converted to be used by Carbon @see self::kludges
|
private int $tzutc = 0; // TZUTC that needs to be converted to be used by Carbon @see self::kludges
|
||||||
private Echomail|Netmail $mo; // The object storing this packet message
|
private Echomail|Netmail $mo; // The object storing this packet message
|
||||||
private Address $us; // Our address for this message
|
private Address $us; // Our address for this message
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ class Message extends FTNBase
|
|||||||
$o->mo->from = $o->header['user_from'];
|
$o->mo->from = $o->header['user_from'];
|
||||||
$o->mo->subject = $o->header['subject'];
|
$o->mo->subject = $o->header['subject'];
|
||||||
|
|
||||||
$o->mo->datetime = $o->datetime->clone()->utc();
|
$o->mo->datetime = $o->datetime;
|
||||||
$o->mo->tzoffset = $o->datetime->utcOffset();
|
$o->mo->tzoffset = $o->datetime->utcOffset();
|
||||||
$o->mo->flags = $o->header['flags'];
|
$o->mo->flags = $o->header['flags'];
|
||||||
$o->mo->cost = $o->header['cost'];
|
$o->mo->cost = $o->header['cost'];
|
||||||
@ -294,7 +294,6 @@ class Message extends FTNBase
|
|||||||
public function __construct(Zone $zone)
|
public function __construct(Zone $zone)
|
||||||
{
|
{
|
||||||
$this->zone = $zone;
|
$this->zone = $zone;
|
||||||
$this->kludges = collect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __get($key)
|
public function __get($key)
|
||||||
@ -307,7 +306,7 @@ class Message extends FTNBase
|
|||||||
case 'fz': return (int)Arr::get($this->src,'z');
|
case 'fz': return (int)Arr::get($this->src,'z');
|
||||||
case 'fn': return (int)($x=$this->src) ? Arr::get($x,'n') : Arr::get($this->header,'onet');
|
case 'fn': return (int)($x=$this->src) ? Arr::get($x,'n') : Arr::get($this->header,'onet');
|
||||||
case 'ff': return (int)($x=$this->src) ? Arr::get($x,'f') : Arr::get($this->header,'onode');
|
case 'ff': return (int)($x=$this->src) ? Arr::get($x,'f') : Arr::get($this->header,'onode');
|
||||||
case 'fp': return (int)$this->mo->kludges->get('FMPT') ?: Arr::get($this->src,'p',Arr::get($this->header,'opoint',0));
|
case 'fp': return (int)$this->mo->kludges->get('FMPT:') ?: Arr::get($this->src,'p',Arr::get($this->header,'opoint',0));
|
||||||
case 'fd': return Arr::get($this->src,'d');
|
case 'fd': return Arr::get($this->src,'d');
|
||||||
|
|
||||||
case 'fzone':
|
case 'fzone':
|
||||||
@ -324,7 +323,6 @@ class Message extends FTNBase
|
|||||||
return Zone::where('zone_id',$this->fz)
|
return Zone::where('zone_id',$this->fz)
|
||||||
->where('default',TRUE)
|
->where('default',TRUE)
|
||||||
->single();
|
->single();
|
||||||
|
|
||||||
case 'fdomain':
|
case 'fdomain':
|
||||||
// We'll use the zone's domain if this method class was called with a zone
|
// We'll use the zone's domain if this method class was called with a zone
|
||||||
if ($this->zone && (($this->zone->domain->name === Arr::get($this->src,'d')) || ! Arr::get($this->src,'d')))
|
if ($this->zone && (($this->zone->domain->name === Arr::get($this->src,'d')) || ! Arr::get($this->src,'d')))
|
||||||
@ -342,7 +340,7 @@ class Message extends FTNBase
|
|||||||
case 'tz': return (int)Arr::get($this->isEchomail() ? $this->src : $this->dst,'z');
|
case 'tz': return (int)Arr::get($this->isEchomail() ? $this->src : $this->dst,'z');
|
||||||
case 'tn': return (int)Arr::get($this->header,'dnet');
|
case 'tn': return (int)Arr::get($this->header,'dnet');
|
||||||
case 'tf': return (int)Arr::get($this->header,'dnode');
|
case 'tf': return (int)Arr::get($this->header,'dnode');
|
||||||
case 'tp': return (int)$this->mo->kludges->get('TOPT') ?: Arr::get($this->header,'dpoint',0);
|
case 'tp': return (int)$this->mo->kludges->get('TOPT:') ?: Arr::get($this->header,'dpoint',0);
|
||||||
|
|
||||||
case 'tzone':
|
case 'tzone':
|
||||||
// Use the zone if this class was called with it.
|
// Use the zone if this class was called with it.
|
||||||
@ -477,25 +475,11 @@ class Message extends FTNBase
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'tzutc':
|
|
||||||
return $this->kludges->get($key);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new \Exception('Unknown key: '.$key);
|
throw new \Exception('Unknown key: '.$key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __set(string $key,mixed $value): void
|
|
||||||
{
|
|
||||||
switch ($key) {
|
|
||||||
case 'tzutc':
|
|
||||||
if (! is_numeric($value))
|
|
||||||
throw new InvalidPacketException('TZUTC is not numeric '.$value);
|
|
||||||
|
|
||||||
$this->kludges->put($key,$value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export an FTN message, ready for sending.
|
* Export an FTN message, ready for sending.
|
||||||
*
|
*
|
||||||
@ -504,6 +488,8 @@ class Message extends FTNBase
|
|||||||
*/
|
*/
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
|
$s = Setup::findOrFail(config('app.id'));
|
||||||
|
|
||||||
$return = pack(collect(self::HEADER)->pluck(1)->join(''),
|
$return = pack(collect(self::HEADER)->pluck(1)->join(''),
|
||||||
$this->mo->fftn->node_id, // Originating Node
|
$this->mo->fftn->node_id, // Originating Node
|
||||||
$this->mo->tftn->node_id, // Destination Node
|
$this->mo->tftn->node_id, // Destination Node
|
||||||
@ -519,6 +505,9 @@ class Message extends FTNBase
|
|||||||
$return .= $this->mo->subject."\00";
|
$return .= $this->mo->subject."\00";
|
||||||
|
|
||||||
if (($this->mo instanceof Netmail) && $this->mo->isFlagSet(self::FLAG_LOCAL)) {
|
if (($this->mo instanceof Netmail) && $this->mo->isFlagSet(self::FLAG_LOCAL)) {
|
||||||
|
// If there isnt an INTL kludge, we'll add it
|
||||||
|
if (! $this->mo->kludges->has('INTL'))
|
||||||
|
$this->mo->kludges->put('INTL',sprintf('%s %s',$this->mo->tftn->ftn3d,$this->mo->fftn->ftn3d));
|
||||||
|
|
||||||
if ((! $this->mo->kludges->has('FMPT')) && $this->mo->fftn->point_id)
|
if ((! $this->mo->kludges->has('FMPT')) && $this->mo->fftn->point_id)
|
||||||
$this->mo->kludges->put('FMPT',$this->mo->fftn->point_id);
|
$this->mo->kludges->put('FMPT',$this->mo->fftn->point_id);
|
||||||
@ -527,16 +516,12 @@ class Message extends FTNBase
|
|||||||
$this->mo->kludges->put('TOPT',$this->mo->tftn->point_id);
|
$this->mo->kludges->put('TOPT',$this->mo->tftn->point_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->mo->kludges->put($this->mo->isFlagSet(self::FLAG_LOCAL) ? 'PID:' : 'TID:',sprintf('%s %s',Setup::PRODUCT_NAME_SHORT,Setup::version()));
|
$this->mo->kludges->put($this->mo->isFlagSet(self::FLAG_LOCAL) ? 'PID:' : 'TID:',sprintf('%s %s',Setup::PRODUCT_NAME_SHORT,$s->version));
|
||||||
$this->mo->kludges->put('DBID:',$this->mo->id);
|
$this->mo->kludges->put('DBID:',$this->mo->id);
|
||||||
|
|
||||||
if ($this->mo instanceof Echomail)
|
if ($this->mo instanceof Echomail)
|
||||||
$return .= sprintf("AREA:%s\r",strtoupper($this->mo->echoarea->name));
|
$return .= sprintf("AREA:%s\r",strtoupper($this->mo->echoarea->name));
|
||||||
|
|
||||||
// Rebuild the INTL kludge line
|
|
||||||
elseif ($this->mo instanceof Netmail)
|
|
||||||
$this->mo->kludges->put('INTL',sprintf('%s %s',$this->mo->tftn->ftn3d,$this->mo->fftn->ftn3d));
|
|
||||||
|
|
||||||
// Add some kludges
|
// Add some kludges
|
||||||
$return .= sprintf("\01TZUTC: %s\r",str_replace('+','',$this->mo->date->getOffsetString('')));
|
$return .= sprintf("\01TZUTC: %s\r",str_replace('+','',$this->mo->date->getOffsetString('')));
|
||||||
|
|
||||||
@ -559,19 +544,14 @@ class Message extends FTNBase
|
|||||||
$return .= sprintf("\x01Via %s @%s.UTC %s %s\r",
|
$return .= sprintf("\x01Via %s @%s.UTC %s %s\r",
|
||||||
$this->us->ftn3d,
|
$this->us->ftn3d,
|
||||||
Carbon::now()->format('Ymd.His'),
|
Carbon::now()->format('Ymd.His'),
|
||||||
Setup::PRODUCT_NAME_SHORT,Setup::version());
|
Setup::PRODUCT_NAME_SHORT,$s->version);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// FTS-0004.001/FSC-0068.001 The message SEEN-BY lines
|
// FTS-0004.001/FSC-0068.001 The message SEEN-BY lines
|
||||||
// FTS-0004.001/FSC-0068.001 The message PATH lines
|
// FTS-0004.001/FSC-0068.001 The message PATH lines
|
||||||
|
|
||||||
// @todo This unique() function here shouldnt be required, but is while system generated messages are storing path/seenby
|
// @todo This unique() function here shouldnt be required, but is while system generated messages are storing path/seenby
|
||||||
$path = $this
|
$path = $this->mo->path->push($this->us)->unique('ftn')->filter(fn($item)=>($item->point_id === 0));
|
||||||
->mo
|
|
||||||
->path
|
|
||||||
->push($this->us)
|
|
||||||
->unique('ftn')
|
|
||||||
->filter(fn($item)=>is_null($item->point_id) || ($item->point_id === 0));
|
|
||||||
|
|
||||||
// Create our rogue seenby objects
|
// Create our rogue seenby objects
|
||||||
$seenby = $this->mo->seenby;
|
$seenby = $this->mo->seenby;
|
||||||
@ -585,7 +565,7 @@ class Message extends FTNBase
|
|||||||
|
|
||||||
$seenby = $seenby
|
$seenby = $seenby
|
||||||
->push($this->us)
|
->push($this->us)
|
||||||
->filter(fn($item)=>is_null($item->point_id) || ($item->point_id === 0))
|
->filter(fn($item)=>($item->point_id === 0))
|
||||||
->unique('ftn')
|
->unique('ftn')
|
||||||
->sortBy(function($item) { return sprintf('%05d%05d',$item->host_id,$item->node_id);});
|
->sortBy(function($item) { return sprintf('%05d%05d',$item->host_id,$item->node_id);});
|
||||||
|
|
||||||
@ -667,9 +647,7 @@ class Message extends FTNBase
|
|||||||
|
|
||||||
// First find our kludge lines
|
// First find our kludge lines
|
||||||
$ptr_start = 0;
|
$ptr_start = 0;
|
||||||
$ptr_end = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (substr($message,$ptr_start,1) === "\x01") {
|
while (substr($message,$ptr_start,1) === "\x01") {
|
||||||
$ptr_end = strpos($message,"\r",$ptr_start);
|
$ptr_end = strpos($message,"\r",$ptr_start);
|
||||||
|
|
||||||
@ -812,15 +790,6 @@ class Message extends FTNBase
|
|||||||
$o->kludges = [$m[1],$m[2]];
|
$o->kludges = [$m[1],$m[2]];
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::error(sprintf('%s:! Error parsing message, now at offset [0x%02x] (%s)',
|
|
||||||
self::LOGKEY,
|
|
||||||
$ptr_start,
|
|
||||||
$e->getMessage()),['dump'=>hex_dump($message)]);
|
|
||||||
|
|
||||||
throw new InvalidPacketException('Error parsing message');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $o;
|
return $o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -876,17 +845,11 @@ class Message extends FTNBase
|
|||||||
$validator->after(function($validator) {
|
$validator->after(function($validator) {
|
||||||
if ($this->zone->domain->flatten) {
|
if ($this->zone->domain->flatten) {
|
||||||
if (! $this->zone->domain->zones->pluck('zone_id')->contains($this->fz))
|
if (! $this->zone->domain->zones->pluck('zone_id')->contains($this->fz))
|
||||||
$validator->errors()->add('invalid-zone',sprintf('Message from zone [%d] doesnt match any zone in domain for packet zone [%d].',$this->fz,$this->zone->zone_id));
|
$validator->errors()->add('invalid-zone',sprintf('Message zone [%d] doesnt match any zone in domain for packet zone [%d].',$this->fz,$this->zone->zone_id));
|
||||||
|
|
||||||
if (! $this->zone->domain->zones->pluck('zone_id')->contains($this->tz))
|
|
||||||
$validator->errors()->add('invalid-zone',sprintf('Message to zone [%d] doesnt match any zone in domain for packet zone [%d].',$this->fz,$this->zone->zone_id));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if ($this->zone->zone_id !== $this->fz)
|
if ($this->zone->zone_id !== $this->fz)
|
||||||
$validator->errors()->add('invalid-zone',sprintf('Message from zone [%d] doesnt match packet zone [%d].',$this->fz,$this->zone->zone_id));
|
$validator->errors()->add('invalid-zone',sprintf('Message zone [%d] doesnt match packet zone [%d].',$this->fz,$this->zone->zone_id));
|
||||||
|
|
||||||
if ($this->zone->zone_id !== $this->tz)
|
|
||||||
$validator->errors()->add('invalid-zone',sprintf('Message to zone [%d] doesnt match packet zone [%d].',$this->tz,$this->zone->zone_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->fftn)
|
if (! $this->fftn)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace App\Classes\FTN;
|
namespace App\Classes\FTN;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
@ -12,8 +12,8 @@ use Symfony\Component\HttpFoundation\File\File;
|
|||||||
|
|
||||||
use App\Classes\FTN as FTNBase;
|
use App\Classes\FTN as FTNBase;
|
||||||
use App\Exceptions\InvalidPacketException;
|
use App\Exceptions\InvalidPacketException;
|
||||||
use App\Models\{Address,Echomail,Netmail,Software,System,Zone};
|
use App\Models\{Address,Domain,Echomail,Netmail,Software,System,Zone};
|
||||||
use App\Notifications\Netmails\{EchomailBadAddress,NetmailBadAddress};
|
use App\Notifications\Netmails\EchomailBadAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a Fidonet Packet, that contains an array of messages.
|
* Represents a Fidonet Packet, that contains an array of messages.
|
||||||
@ -88,11 +88,11 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
|
|||||||
* @param mixed $f File handler returning packet data
|
* @param mixed $f File handler returning packet data
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int $size
|
* @param int $size
|
||||||
* @param System|null $so - The system that sent us the packet, used to figure out domains if the packet is for a different zone
|
* @param Domain|null $domain
|
||||||
* @return Packet
|
* @return Packet
|
||||||
* @throws InvalidPacketException
|
* @throws InvalidPacketException
|
||||||
*/
|
*/
|
||||||
public static function process(mixed $f,string $name,int $size,System $so=NULL): self
|
public static function process(mixed $f,string $name,int $size,Domain $domain=NULL): self
|
||||||
{
|
{
|
||||||
Log::debug(sprintf('%s:+ Opening Packet [%s] with size [%d]',self::LOGKEY,$name,$size));
|
Log::debug(sprintf('%s:+ Opening Packet [%s] with size [%d]',self::LOGKEY,$name,$size));
|
||||||
|
|
||||||
@ -139,34 +139,25 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
|
|||||||
} else
|
} 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',self::LOGKEY,$o->name,get_class($o)));
|
Log::info(sprintf('%s:- Packet [%s] is a [%s] packet, dated [%s]',self::LOGKEY,$o->name,get_class($o),$o->date));
|
||||||
|
|
||||||
if ($o->fz && ($o->fd || $so)) {
|
// Work out the packet zone
|
||||||
Log::alert(sprintf('%s:! No domain in the packet, work it out from the system [%d] for zone [%d]',self::LOGKEY,$so->name,$o->fz));
|
if ($o->fz && ($o->fd || $domain)) {
|
||||||
|
$o->zone = Zone::select('zones.*')
|
||||||
if (($x=$so->zones->where('zone_id',$o->fz)->unique('domain_id'))->count() === 1) {
|
->join('domains',['domains.id'=>'zones.domain_id'])
|
||||||
$o->zone = $x->pop();
|
->where('zone_id',$o->fz)
|
||||||
|
->where('name',$o->fd ?: $domain->name)
|
||||||
} else {
|
->single();
|
||||||
Log::alert(sprintf('%s:! Node [%s] has two zones with [%d]',self::LOGKEY,$so->name,$o->fz));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If zone is not set, then we need to use a default zone - the messages may not be from this zone.
|
// If zone is not set, then we need to use a default zone - the messages may not be from this zone.
|
||||||
if (empty($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));
|
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));
|
||||||
|
|
||||||
try {
|
|
||||||
$o->zone = Zone::where('zone_id',$o->fz)
|
$o->zone = Zone::where('zone_id',$o->fz)
|
||||||
->where('default',TRUE)
|
->where('default',TRUE)
|
||||||
->singleOrFail();
|
->singleOrFail();
|
||||||
|
|
||||||
} catch (ModelNotFoundException $e) {
|
|
||||||
throw new InvalidPacketException(sprintf('%s:! We couldnt work out the packet zone, and there isnt a default for[%d]',self::LOGKEY,$o->fz));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Log::info(sprintf('%s:- Packet Dated [%s] from [%s] to [%s]',self::LOGKEY,$o->date,$o->fftn_t,$o->tftn_t));
|
|
||||||
|
|
||||||
$message = ''; // Current message we are building
|
$message = ''; // Current message we are building
|
||||||
$msgbuf = '';
|
$msgbuf = '';
|
||||||
@ -182,7 +173,6 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
|
|||||||
|| (($end=strpos($msgbuf,"\x00".self::PACKED_END,$leader)) !== FALSE))
|
|| (($end=strpos($msgbuf,"\x00".self::PACKED_END,$leader)) !== FALSE))
|
||||||
{
|
{
|
||||||
// Parse our message
|
// Parse our message
|
||||||
Log::debug(sprintf('%s:- Message at offset [%d] in [%s]',self::LOGKEY,$read_ptr-strlen($readbuf),$name));
|
|
||||||
$o->parseMessage(substr($msgbuf,0,$end));
|
$o->parseMessage(substr($msgbuf,0,$end));
|
||||||
|
|
||||||
$msgbuf = substr($msgbuf,$end+3);
|
$msgbuf = substr($msgbuf,$end+3);
|
||||||
@ -194,7 +184,7 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we get here
|
// If we get here
|
||||||
throw new InvalidPacketException(sprintf('Cannot determine END of message/packet: %s|%s',get_class($o),hex_dump($message)));
|
throw new InvalidPacketException(sprintf('Cannot determine END of message/packet: %s|%s',get_class($o),hex_dump($message)));;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($msgbuf)
|
if ($msgbuf)
|
||||||
@ -371,7 +361,7 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
|
|||||||
|
|
||||||
$this->content .= "\00\00";
|
$this->content .= "\00\00";
|
||||||
|
|
||||||
$this->messages = $msgs->map(fn($item)=>$item->only(['id','datetime']));
|
$this->messages = $msgs->map(fn($item)=>$item->only(['id','date']));
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -394,10 +384,10 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
|
|||||||
|
|
||||||
// If the messages is not for the right zone, we'll ignore it
|
// If the messages is not for the right zone, we'll ignore it
|
||||||
if ($msg->errors->has('invalid-zone')) {
|
if ($msg->errors->has('invalid-zone')) {
|
||||||
Log::alert(sprintf('%s:! Message [%s] is from|to an invalid zone [%s|%s], packet is from [%s] - ignoring it',self::LOGKEY,$msg->msgid,$msg->get_fftn,$msg->get_tftn,$this->fz));
|
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->kludges->get('RESCANNED'))
|
if (! $msg->kludges->get('RESCANNED'))
|
||||||
Notification::route('netmail',$this->fftn)->notify(($msg instanceof Echomail) ? new EchomailBadAddress($msg) : new NetmailBadAddress($msg));
|
Notification::route('netmail',$this->fftn)->notify(new EchomailBadAddress($msg));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -406,7 +396,7 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
|
|||||||
if ($msg->errors->has('from') && $this->fftn && $this->fftn->zone_id) {
|
if ($msg->errors->has('from') && $this->fftn && $this->fftn->zone_id) {
|
||||||
Log::debug(sprintf('%s:^ From address [%s] doesnt exist, it needs to be created',self::LOGKEY,$msg->set->get('set_fftn')));
|
Log::debug(sprintf('%s:^ From address [%s] doesnt exist, it needs to be created',self::LOGKEY,$msg->set->get('set_fftn')));
|
||||||
|
|
||||||
$ao = Address::findFTN($msg->set->get('set_fftn'),TRUE,TRUE);
|
$ao = Address::findFTN($msg->set->get('set_fftn'),TRUE);
|
||||||
|
|
||||||
if ($ao?->exists && ($ao->zone?->domain_id !== $this->fftn->zone->domain_id)) {
|
if ($ao?->exists && ($ao->zone?->domain_id !== $this->fftn->zone->domain_id)) {
|
||||||
Log::alert(sprintf('%s:! From address [%s] domain [%d] doesnt match packet domain [%d]?',self::LOGKEY,$msg->set->get('set_fftn'),$ao->zone?->domain_id,$this->fftn->zone->domain_id));
|
Log::alert(sprintf('%s:! From address [%s] domain [%d] doesnt match packet domain [%d]?',self::LOGKEY,$msg->set->get('set_fftn'),$ao->zone?->domain_id,$this->fftn->zone->domain_id));
|
||||||
@ -417,20 +407,17 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
|
|||||||
if (! $ao) {
|
if (! $ao) {
|
||||||
$so = System::createUnknownSystem();
|
$so = System::createUnknownSystem();
|
||||||
$ao = Address::createFTN($msg->set->get('set_fftn'),$so);
|
$ao = Address::createFTN($msg->set->get('set_fftn'),$so);
|
||||||
|
|
||||||
Log::alert(sprintf('%s:- From FTN [%s] is not defined, created new entry for (%d)',self::LOGKEY,$msg->set->get('set_fftn'),$ao->id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$msg->fftn_id = $ao->id;
|
$msg->fftn_id = $ao->id;
|
||||||
$msg->errors->forget('from');
|
Log::alert(sprintf('%s:- From FTN [%s] is not defined, created new entry for (%d)',self::LOGKEY,$msg->set->get('set_fftn'),$ao->id));
|
||||||
$msg->errors->forget('fftn_id');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the $msg->tftn doesnt exist, we'll need to create it
|
// If the $msg->tftn doesnt exist, we'll need to create it
|
||||||
if ($msg->errors->has('to') && $this->tftn && $this->tftn->zone_id) {
|
if ($msg->errors->has('to') && $this->tftn && $this->tftn->zone_id) {
|
||||||
Log::debug(sprintf('%s:^ To address [%s] doesnt exist, it needs to be created',self::LOGKEY,$msg->set->get('set_tftn')));
|
Log::debug(sprintf('%s:^ To address [%s] doesnt exist, it needs to be created',self::LOGKEY,$msg->set->get('set_tftn')));
|
||||||
|
|
||||||
$ao = Address::findFTN($msg->set->get('set_tftn'),TRUE,TRUE);
|
$ao = Address::findFTN($msg->set->get('set_tftn'),TRUE);
|
||||||
|
|
||||||
if ($ao?->exists && ($ao->zone?->domain_id !== $this->tftn->zone->domain_id)) {
|
if ($ao?->exists && ($ao->zone?->domain_id !== $this->tftn->zone->domain_id)) {
|
||||||
Log::alert(sprintf('%s:! To address [%s] domain [%d] doesnt match packet domain [%d]?',self::LOGKEY,$msg->set->get('set_tftn'),$ao->zone?->domain_id,$this->fftn->zone->domain_id));
|
Log::alert(sprintf('%s:! To address [%s] domain [%d] doesnt match packet domain [%d]?',self::LOGKEY,$msg->set->get('set_tftn'),$ao->zone?->domain_id,$this->fftn->zone->domain_id));
|
||||||
@ -441,13 +428,10 @@ abstract class Packet extends FTNBase implements \Iterator, \Countable
|
|||||||
if (! $ao) {
|
if (! $ao) {
|
||||||
$so = System::createUnknownSystem();
|
$so = System::createUnknownSystem();
|
||||||
$ao = Address::createFTN($msg->set->get('set_fftn'),$so);
|
$ao = Address::createFTN($msg->set->get('set_fftn'),$so);
|
||||||
|
|
||||||
Log::alert(sprintf('%s:- To FTN [%s] is not defined, created new entry for (%d)',self::LOGKEY,$msg->set->get('set_tftn'),$ao->id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$msg->tftn_id = $ao->id;
|
$msg->tftn_id = $ao->id;
|
||||||
$msg->errors->forget('to');
|
Log::alert(sprintf('%s:- To FTN [%s] is not defined, created new entry for (%d)',self::LOGKEY,$msg->set->get('set_tftn'),$ao->id));
|
||||||
$msg->errors->forget('tftn_id');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is no fftn, then its from a system that we dont know about
|
// If there is no fftn, then its from a system that we dont know about
|
||||||
|
@ -65,7 +65,7 @@ final class FSC39 extends Packet
|
|||||||
*/
|
*/
|
||||||
protected function header(Collection $msgs): string
|
protected function header(Collection $msgs): string
|
||||||
{
|
{
|
||||||
$oldest = $this->messages->sortBy('date')->last();
|
$oldest = $this->messages->sortBy('datetime')->last();
|
||||||
|
|
||||||
return pack(collect(self::HEADER)->pluck(1)->join(''),
|
return pack(collect(self::HEADER)->pluck(1)->join(''),
|
||||||
$this->fftn_p->node_id, // Orig Node
|
$this->fftn_p->node_id, // Orig Node
|
||||||
|
@ -55,10 +55,6 @@ final class FSC48 extends Packet
|
|||||||
case 'capability':
|
case 'capability':
|
||||||
return sprintf('%016b',Arr::get($this->header,'capword'));
|
return sprintf('%016b',Arr::get($this->header,'capword'));
|
||||||
|
|
||||||
case 'fn':
|
|
||||||
// If the packet is from a point, then onet will be 0xffff
|
|
||||||
return ($x=Arr::get($this->header,'onet')) === 0xffff ? Arr::get($this->header,'auxnet') : $x;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return parent::__get($key);
|
return parent::__get($key);
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,9 @@ use Illuminate\Support\Facades\Notification;
|
|||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
use App\Classes\FTN\Process;
|
use App\Classes\FTN\Process;
|
||||||
use App\Classes\FTN\Process\Netmail\Robot\Unknown;
|
|
||||||
use App\Models\{Echomail,Netmail};
|
use App\Models\{Echomail,Netmail};
|
||||||
use App\Notifications\Netmails\FixCantHandle;
|
use App\Notifications\Netmails\Areafix as AreafixNotification;
|
||||||
use App\Notifications\Netmails\Areafix\{CommandsProcessed,InvalidPassword,NotConfiguredHere};
|
use App\Notifications\Netmails\Areafix\NotConfiguredHere as AreafixNotConfiguredHereNotification;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process messages to Ping
|
* Process messages to Ping
|
||||||
@ -20,102 +19,18 @@ final class Areafix extends Process
|
|||||||
{
|
{
|
||||||
private const LOGKEY = 'RP-';
|
private const LOGKEY = 'RP-';
|
||||||
|
|
||||||
public const areafix_commands = 'App\\Classes\\FTN\\Process\\Netmail\\Robot\\Areafix\\';
|
|
||||||
|
|
||||||
public static function handle(Echomail|Netmail $mo): bool
|
public static function handle(Echomail|Netmail $mo): bool
|
||||||
{
|
{
|
||||||
if (((strtolower($mo->to) !== 'areafix') && (strtolower($mo->to) !== 'filefix')) || (! ($mo instanceof Netmail)))
|
if (strtolower($mo->to) !== 'areafix')
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
Log::info(sprintf('%s:- Processing *FIX [%s] message from (%s) [%s]',self::LOGKEY,$mo->to,$mo->from,$mo->fftn->ftn));
|
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 this is not a node we manage, then respond with a sorry can help you
|
||||||
if (! $mo->fftn->system->sessions->count()) {
|
if ($mo->fftn->system->sessions->count())
|
||||||
Notification::route('netmail',$mo->fftn)->notify(new NotConfiguredHere($mo));
|
Notification::route('netmail',$mo->fftn)->notify(new AreafixNotification($mo));
|
||||||
|
else
|
||||||
return TRUE;
|
Notification::route('netmail',$mo->fftn)->notify(new AreafixNotConfiguredHereNotification($mo));
|
||||||
}
|
|
||||||
|
|
||||||
// If this nodes password is not correct
|
|
||||||
if ($mo->fftn->pass_fix !== strtoupper($mo->subject)) {
|
|
||||||
Notification::route('netmail',$mo->fftn)->notify(new InvalidPassword($mo));
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((strtolower($mo->to) === 'areafix'))
|
|
||||||
return self::areafix($mo);
|
|
||||||
|
|
||||||
if ((strtolower($mo->to) === 'filefix'))
|
|
||||||
return self::filefix($mo);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function areafix(Netmail $mo): bool
|
|
||||||
{
|
|
||||||
$result = collect();
|
|
||||||
$result->push('--> BEGIN <--');
|
|
||||||
|
|
||||||
foreach ($mo->body_lines as $command) {
|
|
||||||
// Skip empty lines
|
|
||||||
if (! $command)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$command = explode(' ',strtoupper(trim($command)));
|
|
||||||
|
|
||||||
// If command starts with '...' or '---', its a tear/tag line, and we have reached the end
|
|
||||||
if (str_starts_with($command[0],'...') || str_starts_with($command[0],'---')) {
|
|
||||||
Log::debug(sprintf('%s:= We got a tearline/tagline, end of processing',self::LOGKEY));
|
|
||||||
|
|
||||||
$result->push('--> END OF PROCESSING <--');
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
// If command doesnt start with %, its an area
|
|
||||||
} elseif (! str_starts_with($command[0],'%')) {
|
|
||||||
Log::info(sprintf('%s:= Assuming command [%s] is an AREA command',self::LOGKEY,$command[0]));
|
|
||||||
|
|
||||||
array_unshift($command,'%AREA');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some commands are reserved words
|
|
||||||
switch ($x=strtolower(substr($command[0],1))) {
|
|
||||||
case 'list':
|
|
||||||
$class = self::areafix_commands.'AreaList';
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Parse the message body and pluck out the commands on each line
|
|
||||||
$class = self::areafix_commands.ucfirst($x);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! class_exists($class)) {
|
|
||||||
$result->push(sprintf('%-25s <-- **COMMAND UNKNOWN**',join(' ',$command)));
|
|
||||||
Log::info(sprintf('%s:! Command UNKNOWN [%s] ',self::LOGKEY,join('|',$command)),['class'=>$class]);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop the command from the array, the rest are arguments
|
|
||||||
array_shift($command);
|
|
||||||
|
|
||||||
// Refresh our echoareas
|
|
||||||
$mo->fftn->load('echoareas');
|
|
||||||
|
|
||||||
$o = new $class($mo,$command);
|
|
||||||
$result->push($o->process());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reply with a confirmation of what commands were processed
|
|
||||||
Notification::route('netmail',$mo->fftn)->notify(new CommandsProcessed($mo,$result));
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function filefix(Netmail $mo): bool
|
|
||||||
{
|
|
||||||
Notification::route('netmail',$mo->fftn)->notify(new FixCantHandle($mo));
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1,143 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes\FTN\Process\Netmail\Robot\Areafix;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
use App\Jobs\AreafixRescan;
|
|
||||||
|
|
||||||
// Echoarea Processing Command
|
|
||||||
class Area extends Base
|
|
||||||
{
|
|
||||||
private const LOGKEY = 'AFA';
|
|
||||||
|
|
||||||
private const command = '%AREA';
|
|
||||||
|
|
||||||
public static function help(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
self::command.' [-|+]<ECHOAREA> [R|D=<DAYS>]',
|
|
||||||
' Use the area command to subscribe (+) or unsubscribe (-) to an ECHOAREA',
|
|
||||||
' Arguments:',
|
|
||||||
' - ECHOAREA (required) name of area to subscribe or unsubscribe',
|
|
||||||
' - D=DAYS (optional) number of days to resend mail from this area that you',
|
|
||||||
' havent already received (useful if you are resubscribing to an area and',
|
|
||||||
' have received mail in the past)',
|
|
||||||
' - R=DAYS (optional) number of days to resend mail from this area (even if',
|
|
||||||
' it was sent to you previously)',
|
|
||||||
' Notes:',
|
|
||||||
' * "+" is optional, and is implied if "-" is not used',
|
|
||||||
' * "R" and "D" options only apply to subscribing',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function process(): string
|
|
||||||
{
|
|
||||||
$command = self::command.' '.join(' ',$this->arguments);
|
|
||||||
|
|
||||||
// If command starts with '-', its to unsubscribe
|
|
||||||
if (str_starts_with($this->arguments[0],'-')) {
|
|
||||||
$sub = FALSE;
|
|
||||||
$area = substr($this->arguments[0],1);
|
|
||||||
|
|
||||||
} elseif (str_starts_with($this->arguments[0],'+')) {
|
|
||||||
$sub = TRUE;
|
|
||||||
$area = substr($this->arguments[0],1);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$sub = TRUE;
|
|
||||||
$area = $this->arguments[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- Processing [%s] for [%s]',self::LOGKEY,$sub ? 'ADD' : 'REMOVE',$area));
|
|
||||||
|
|
||||||
// Drop the area from the arguments, the rest are options
|
|
||||||
array_shift($this->arguments);
|
|
||||||
|
|
||||||
// Area exists
|
|
||||||
if ($ea=$this->mo->fftn->domain->echoareas->where('name',$area)->pop()) {
|
|
||||||
// If already subscribed
|
|
||||||
if ($nea=$this->mo->fftn->echoareas->where('name',$area)->pop()) {
|
|
||||||
// requesting to subscribe "You already are since..., arguments ignored
|
|
||||||
if ($sub) {
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] ALREADY subscribed to [%s] since [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area,$nea->pivot->subscribed->format('Y-m-d H:i')));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- ALREADY subscribed since %s',$command,$nea->pivot->subscribed->format('Y-m-d H:i'));
|
|
||||||
|
|
||||||
// requesting to unsubscribe
|
|
||||||
} else {
|
|
||||||
$this->mo->fftn->echoareas()->detach($ea->id);
|
|
||||||
|
|
||||||
// Remove sub, clear queue
|
|
||||||
$x = DB::table('echomail_seenby')
|
|
||||||
->where('address_id',$this->mo->fftn->id)
|
|
||||||
->join('echomails',['echomails.id'=>'echomail_seenby.echomail_id'])
|
|
||||||
->where('echoarea_id',$nea->id)
|
|
||||||
->whereNotNull('export_at')
|
|
||||||
->whereNull('sent_at')
|
|
||||||
->orderBy('echomails.datetime')
|
|
||||||
->skip($this->mo->fftn->system->pkt_msgs)
|
|
||||||
->delete();
|
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] UNSUBSCRIBED from [%s] clearing [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area,$x));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- UNSUBSCRIBED, CLEARED [%d] MSGS from queue',$command,$x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not subscribed
|
|
||||||
} else {
|
|
||||||
// requesting to subscribe, subsubsribe and rescan if arguments
|
|
||||||
if ($sub) {
|
|
||||||
$this->mo->fftn->echoareas()->attach([$ea->id=>['subscribed'=>Carbon::now()]]);
|
|
||||||
|
|
||||||
// If we have arguments, they are to rescan
|
|
||||||
if (count($this->arguments) === 1) {
|
|
||||||
$m = [];
|
|
||||||
if (preg_match('/^([DR])=([0-9]+)$/',$this->arguments[0],$m)) {
|
|
||||||
switch ($m[1]) {
|
|
||||||
// Scan
|
|
||||||
case 'D':
|
|
||||||
AreafixRescan::dispatch($this->mo->fftn,$ea,$m[2])
|
|
||||||
->onQueue('mail');
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- SUBSCRIBED, RESCAN [%d] DAYS queued',$command,$m[2]);
|
|
||||||
|
|
||||||
// Scan
|
|
||||||
case 'R':
|
|
||||||
AreafixRescan::dispatch($this->mo->fftn,$ea,$m[2],TRUE)
|
|
||||||
->onQueue('mail');
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- SUBSCRIBED, FORCE RESCAN [%d] DAYS queued',$command,$m[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- SUBSCRIBED, INVALID OPTIONS',$command);
|
|
||||||
|
|
||||||
} elseif (count($this->arguments) > 1) {
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] subscribed to [%s], extra commands [%s] ignored',self::LOGKEY,$this->mo->fftn->ftn,$area,join('|',$this->arguments)));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- SUBSCRIBED, OPTIONS IGNORED',$command);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] subscribed to [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- SUBSCRIBED',$command);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not subscribed, "you arent subscribed, arguments ignored"
|
|
||||||
} else {
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] is NOT subscribed to [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$area));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- NOT subscribed, NO ACTION taken',$command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] area UNKNOWN [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$area));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- AREA UNKNOWN, NO ACTION TAKEN',$command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes\FTN\Process\Netmail\Robot\Areafix;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Facades\Notification;
|
|
||||||
|
|
||||||
use App\Notifications\Netmails\Areafix\AreaList as AreaListNotification;
|
|
||||||
|
|
||||||
// LIST - List echoareas in a domain
|
|
||||||
class AreaList extends Base
|
|
||||||
{
|
|
||||||
private const LOGKEY = 'AFS';
|
|
||||||
private const command = '%LIST';
|
|
||||||
|
|
||||||
public static function help(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
self::command,
|
|
||||||
' List the available echoareas in this network',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function process(): string
|
|
||||||
{
|
|
||||||
Log::debug(sprintf('%s:- Areafix [%s] for [%s] for [%s]',self::LOGKEY,self::command,$this->mo->fftn->ftn,join('|',$this->arguments)));
|
|
||||||
|
|
||||||
if (count($this->arguments) > 1)
|
|
||||||
return sprintf('%-25s <-- INVALID COMMAND',self::command);
|
|
||||||
|
|
||||||
else {
|
|
||||||
Notification::route('netmail',$this->mo->fftn)
|
|
||||||
->notify(new AreaListNotification($this->mo));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- COMMAND PROCESSED',self::command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes\FTN\Process\Netmail\Robot\Areafix;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
use App\Models\Netmail;
|
|
||||||
|
|
||||||
// Our base areafix commands class
|
|
||||||
abstract class Base
|
|
||||||
{
|
|
||||||
private const LOGKEY = 'AB-';
|
|
||||||
|
|
||||||
protected Netmail $mo;
|
|
||||||
protected array $arguments;
|
|
||||||
|
|
||||||
public function __construct(Netmail $mo,array $arguments) {
|
|
||||||
Log::debug(sprintf('%s:- Areafix [%s] command with arguments [%s] for [%s]',self::LOGKEY,get_class($this),implode('|',$arguments),$mo->fftn->ftn));
|
|
||||||
|
|
||||||
$this->mo = $mo;
|
|
||||||
$this->arguments = $arguments;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract public static function help(): array;
|
|
||||||
abstract public function process(): string;
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes\FTN\Process\Netmail\Robot\Areafix;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Facades\Notification;
|
|
||||||
|
|
||||||
use App\Classes\FTN\Process\Netmail\Areafix;
|
|
||||||
use App\Notifications\Netmails\Areafix\Help as HelpNotification;
|
|
||||||
|
|
||||||
// A Help Index Command
|
|
||||||
class Help extends Base
|
|
||||||
{
|
|
||||||
private const LOGKEY = 'AFH';
|
|
||||||
private const areafix_classes = 'app/Classes/FTN/Process/Netmail/Robot/Areafix';
|
|
||||||
private const command = '%HELP';
|
|
||||||
|
|
||||||
public static function help(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
self::command,
|
|
||||||
' This message!',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function process(): string
|
|
||||||
{
|
|
||||||
Log::debug(sprintf('%s:- Processing [%s] for [%s]',self::LOGKEY,self::command,$this->mo->fftn->ftn));
|
|
||||||
|
|
||||||
$result = collect();
|
|
||||||
|
|
||||||
foreach (preg_grep('/^([^.])/',scandir(self::areafix_classes)) as $file) {
|
|
||||||
if (($file === 'Base.php') || (! str_ends_with(strtolower($file),'.php')))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$class = Areafix::areafix_commands.preg_replace('/\.php$/','',$file);
|
|
||||||
if ($result->count())
|
|
||||||
$result->push('');
|
|
||||||
|
|
||||||
$result = $result
|
|
||||||
->merge($class::help());
|
|
||||||
}
|
|
||||||
|
|
||||||
Notification::route('netmail',$this->mo->fftn)->notify(new HelpNotification($this->mo,$result));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- COMMAND PROCESSED',self::command);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes\FTN\Process\Netmail\Robot\Areafix;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
use App\Jobs\AreafixRescan;
|
|
||||||
|
|
||||||
// RESCAN - Resend echomail
|
|
||||||
class Rescan extends Base
|
|
||||||
{
|
|
||||||
private const LOGKEY = 'AFR';
|
|
||||||
private const command = '%RESCAN';
|
|
||||||
|
|
||||||
public static function help(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
self::command.' [-|+]<ECHOAREA> [<DAYS>]',
|
|
||||||
' Use the rescan command to resend mail from an echoarea.',
|
|
||||||
' This is will resend mail again, even if you have received it in the past.',
|
|
||||||
' Arguments:',
|
|
||||||
' - ECHOAREA (required) name of area to subscribe or unsubscribe',
|
|
||||||
' - DAYS (optional) number of days to resend mail from this area that you',
|
|
||||||
' If DAYS is omitted, the default is 30',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function process(): string
|
|
||||||
{
|
|
||||||
Log::debug(sprintf('%s:- Areafix [%s] for [%s] for [%s]',self::LOGKEY,self::command,$this->mo->fftn->ftn,join('|',$this->arguments)));
|
|
||||||
|
|
||||||
$command = self::command.' '.join(' ',$this->arguments);
|
|
||||||
|
|
||||||
if (! is_numeric($this->arguments[1]))
|
|
||||||
return sprintf('%-25s <-- INVALID, DAYS [%s] NOT NUMERIC',$command,$this->arguments[1]);
|
|
||||||
|
|
||||||
// Area exists
|
|
||||||
if ($ea=$this->mo->fftn->domain->echoareas->where('name',$this->arguments[0])->pop()) {
|
|
||||||
// If already subscribed
|
|
||||||
if ($this->mo->fftn->echoareas->pluck('name')->contains($this->arguments[0])) {
|
|
||||||
AreafixRescan::dispatch($this->mo->fftn,$ea,$this->arguments[1],TRUE)
|
|
||||||
->onQueue('mail');
|
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] RESCAN [%s] DAYS [%d]',self::LOGKEY,$this->mo->fftn->ftn,$this->arguments[0],$this->arguments[1]));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- RESCAN [%d] DAYS queued',$command,$this->arguments[1]);
|
|
||||||
|
|
||||||
// If not subscribed
|
|
||||||
} else {
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] is NOT subscribed to [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$this->arguments[0]));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- NOT subscribed, NO ACTION taken',$command);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] area UNKNOWN [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$this->arguments[0]));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- AREA UNKNOWN, NO ACTION TAKEN',$command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes\FTN\Process\Netmail\Robot\Areafix;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
use App\Jobs\AreafixRescan;
|
|
||||||
|
|
||||||
// SCAN - Send unsent echomail
|
|
||||||
class Scan extends Base
|
|
||||||
{
|
|
||||||
private const LOGKEY = 'AFS';
|
|
||||||
private const command = '%SCAN';
|
|
||||||
|
|
||||||
public static function help(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
self::command.' [-|+]<ECHOAREA> [<DAYS>]',
|
|
||||||
' Use the scan command to resend mail that you havent received yet from an',
|
|
||||||
' echoarea. This is useful if you are rejoining an echoarea, and only want',
|
|
||||||
' to get mail that you dont already have.',
|
|
||||||
' Arguments:',
|
|
||||||
' - ECHOAREA (required) name of area to subscribe or unsubscribe',
|
|
||||||
' - DAYS (optional) number of days to resend mail from this area that you',
|
|
||||||
' If DAYS is omitted, the default is 30',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function process(): string
|
|
||||||
{
|
|
||||||
Log::debug(sprintf('%s:- Areafix [%s] for [%s] for [%s]',self::LOGKEY,self::command,$this->mo->fftn->ftn,join('|',$this->arguments)));
|
|
||||||
|
|
||||||
$command = self::command.' '.join(' ',$this->arguments);
|
|
||||||
|
|
||||||
if (! is_numeric($this->arguments[1]))
|
|
||||||
return sprintf('%-25s <-- INVALID, DAYS [%s] NOT NUMERIC',$command,$this->arguments[1]);
|
|
||||||
|
|
||||||
// Area exists
|
|
||||||
if ($ea=$this->mo->fftn->domain->echoareas->where('name',$this->arguments[0])->pop()) {
|
|
||||||
// If already subscribed
|
|
||||||
if ($this->mo->fftn->echoareas->pluck('name')->contains($this->arguments[0])) {
|
|
||||||
AreafixRescan::dispatch($this->mo->fftn,$ea,$this->arguments[1])
|
|
||||||
->onQueue('mail');
|
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] SCAN [%s] DAYS [%d]',self::LOGKEY,$this->mo->fftn->ftn,$this->arguments[0],$this->arguments[1]));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- SCAN [%d] DAYS queued',$command,$this->arguments[1]);
|
|
||||||
|
|
||||||
// If not subscribed
|
|
||||||
} else {
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] is NOT subscribed to [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$this->arguments[0]));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- NOT subscribed, NO ACTION taken',$command);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] area UNKNOWN [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$this->arguments[0]));
|
|
||||||
|
|
||||||
return sprintf('%-25s <-- AREA UNKNOWN, NO ACTION TAKEN',$command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -83,11 +83,6 @@ class File extends FileBase implements \Iterator
|
|||||||
|
|
||||||
/* METHODS */
|
/* METHODS */
|
||||||
|
|
||||||
public function isArchive(): bool
|
|
||||||
{
|
|
||||||
return $this->isArchive;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the file is a mail packet
|
* Determine if the file is a mail packet
|
||||||
*
|
*
|
||||||
|
@ -11,7 +11,7 @@ use Illuminate\Support\Collection;
|
|||||||
* When sending, we can queue up a list of items, and mark one active (the one being sent) at a time.
|
* When sending, we can queue up a list of items, and mark one active (the one being sent) at a time.
|
||||||
*
|
*
|
||||||
* + Netmail/Echomail/TIC
|
* + Netmail/Echomail/TIC
|
||||||
* + name is the hex ID of the youngest item in the mail bundle
|
* + name is dynamically calculated, based on timew() of the youngest item in the mail bundle
|
||||||
* + size is dynamically calculated based on the size of the bundle
|
* + size is dynamically calculated based on the size of the bundle
|
||||||
* + mtime is dynamically calculated, based on the age of the youngest item
|
* + mtime is dynamically calculated, based on the age of the youngest item
|
||||||
* + sendas (nameas) is name + [.pkt|.tic]
|
* + sendas (nameas) is name + [.pkt|.tic]
|
||||||
|
@ -86,9 +86,11 @@ final class File extends Send
|
|||||||
$this->size = $this->f->size;
|
$this->size = $this->f->size;
|
||||||
|
|
||||||
// If sending file is a File::class, then our file is s3
|
// If sending file is a File::class, then our file is s3
|
||||||
$this->fd = ($this->nameas && $this->f instanceof FileModel)
|
if ($this->nameas && $this->f instanceof FileModel) {
|
||||||
? Storage::readStream($this->f->rel_name)
|
$this->fd = Storage::readStream($this->f->rel_name);
|
||||||
: fopen($this->full_name,'rb');
|
|
||||||
|
} else {
|
||||||
|
$this->fd = fopen($this->full_name,'rb');
|
||||||
|
|
||||||
if (! $this->fd) {
|
if (! $this->fd) {
|
||||||
Log::error(sprintf('%s:! Unable to open file [%s] for reading',self::LOGKEY,$this->full_name));
|
Log::error(sprintf('%s:! Unable to open file [%s] for reading',self::LOGKEY,$this->full_name));
|
||||||
@ -97,6 +99,7 @@ final class File extends Send
|
|||||||
}
|
}
|
||||||
|
|
||||||
Log::info(sprintf('%s:= File [%s] opened with size [%d]',self::LOGKEY,$this->full_name,$this->size));
|
Log::info(sprintf('%s:= File [%s] opened with size [%d]',self::LOGKEY,$this->full_name,$this->size));
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -108,6 +111,6 @@ final class File extends Send
|
|||||||
|
|
||||||
public function seek(int $pos): bool
|
public function seek(int $pos): bool
|
||||||
{
|
{
|
||||||
return (fseek($this->fd,$pos,SEEK_SET) === 0);
|
return (fseek($this->f,$pos,SEEK_SET) === 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,6 @@ namespace App\Classes\File;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
|
||||||
use Illuminate\Support\Arr;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
@ -37,13 +36,13 @@ final class Mail extends Send
|
|||||||
return $this->f->messages->pluck('id');
|
return $this->f->messages->pluck('id');
|
||||||
|
|
||||||
case 'name':
|
case 'name':
|
||||||
return sprintf('%08x',$this->youngest_id());
|
return sprintf('%08x',timew($this->youngest()));
|
||||||
|
|
||||||
case 'nameas':
|
case 'nameas':
|
||||||
return sprintf('%s.pkt',$this->name);
|
return sprintf('%s.pkt',$this->name);
|
||||||
|
|
||||||
case 'mtime':
|
case 'mtime':
|
||||||
return $this->youngest_date()->timestamp;
|
return $this->youngest()->timestamp;
|
||||||
|
|
||||||
case 'type':
|
case 'type':
|
||||||
return ($this->ftype&0xff00)>>8;
|
return ($this->ftype&0xff00)>>8;
|
||||||
@ -115,18 +114,8 @@ final class Mail extends Send
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function youngest(): array
|
private function youngest(): Carbon
|
||||||
{
|
{
|
||||||
return $this->f->messages->sortBy(fn($item)=>Arr::get($item,'datetime'))->first();
|
return $this->f->messages->pluck('date')->sort()->last();
|
||||||
}
|
|
||||||
|
|
||||||
private function youngest_id(): int
|
|
||||||
{
|
|
||||||
return Arr::get($this->youngest(),'id',0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function youngest_date(): Carbon
|
|
||||||
{
|
|
||||||
return Arr::get($this->youngest(),'datetime',Carbon::now());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -128,9 +128,9 @@ class Receive extends Base
|
|||||||
// If packet is greater than a size, lets queue it
|
// If packet is greater than a size, lets queue it
|
||||||
if ($this->queue || ($this->receiving->size > config('fido.queue_size',0))) {
|
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));
|
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->rel_name,$this->ao->system,FALSE,$rcvd_time);
|
PacketProcess::dispatch($this->receiving->rel_name,$this->ao->zone->domain,FALSE,$rcvd_time);
|
||||||
} else
|
} else
|
||||||
PacketProcess::dispatchSync($this->receiving->rel_name,$this->ao->system,TRUE,$rcvd_time);
|
PacketProcess::dispatchSync($this->receiving->rel_name,$this->ao->zone->domain,TRUE,$rcvd_time);
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::error(sprintf('%s:! Got error dispatching packet [%s] (%d:%s-%s).',self::LOGKEY,$this->receiving->rel_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()));
|
||||||
|
@ -125,9 +125,6 @@ class Send extends Base
|
|||||||
if ($successful) {
|
if ($successful) {
|
||||||
$end = time()-$this->start;
|
$end = time()-$this->start;
|
||||||
Log::info(sprintf('%s:- Closing [%s], sent in [%d] with [%s] items',self::LOGKEY,$this->sending->nameas,$end,$this->sending->dbids->count()));
|
Log::info(sprintf('%s:- Closing [%s], sent in [%d] with [%s] items',self::LOGKEY,$this->sending->nameas,$end,$this->sending->dbids->count()));
|
||||||
|
|
||||||
} else {
|
|
||||||
Log::alert(sprintf('%s:- Closing [%s], file NOT SENT successfully',self::LOGKEY,$this->sending->nameas));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->sending->close($successful,$node);
|
$this->sending->close($successful,$node);
|
||||||
@ -204,7 +201,7 @@ class Send extends Base
|
|||||||
|
|
||||||
// Files
|
// Files
|
||||||
if (($x=$ao->filesWaiting())->count()) {
|
if (($x=$ao->filesWaiting())->count()) {
|
||||||
Log::info(sprintf('%s:- [%d] Files(s) added for sending to [%s]',self::LOGKEY,$x->count(),$ao->ftn));
|
Log::debug(sprintf('%s:- [%d] Files(s) added for sending to [%s]',self::LOGKEY,$x->count(),$ao->ftn));
|
||||||
|
|
||||||
// Add Files
|
// Add Files
|
||||||
foreach ($x as $fo) {
|
foreach ($x as $fo) {
|
||||||
@ -227,12 +224,12 @@ class Send extends Base
|
|||||||
*/
|
*/
|
||||||
public function open(string $compress=''): bool
|
public function open(string $compress=''): bool
|
||||||
{
|
{
|
||||||
Log::debug(sprintf('%s:+ File Open to send',self::LOGKEY));
|
Log::debug(sprintf('%s:+ Opening file to send',self::LOGKEY));
|
||||||
|
|
||||||
if ((($this->index=$this->list->search(function($item) { return $item->complete === FALSE; })) !== FALSE)
|
if ((($this->index=$this->list->search(function($item) { return $item->complete === FALSE; })) !== FALSE)
|
||||||
&& $this->sending->open())
|
&& $this->sending->open())
|
||||||
{
|
{
|
||||||
Log::info(sprintf('%s:- Content Send item [#%d] (%s) with size [%d]',self::LOGKEY,$this->index,$this->sending->nameas,$this->sending->size));
|
Log::info(sprintf('%s:- Sending item [%d] (%s)',self::LOGKEY,$this->index,$this->sending->nameas));
|
||||||
|
|
||||||
$this->pos = 0;
|
$this->pos = 0;
|
||||||
$this->start = time();
|
$this->start = time();
|
||||||
@ -245,10 +242,7 @@ class Send extends Base
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log::error(sprintf('%s:- No files to open',self::LOGKEY));
|
throw new Exception('No files to open');
|
||||||
$this->index = NULL;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +303,7 @@ class Send extends Base
|
|||||||
|
|
||||||
$this->pos += strlen($data);
|
$this->pos += strlen($data);
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- Content Read [%d] bytes, pos now [%d]',self::LOGKEY,strlen($data),$this->pos));
|
Log::debug(sprintf('%s:- Read [%d] bytes, file pos now [%d]',self::LOGKEY,strlen($data),$this->pos));
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
@ -329,7 +323,7 @@ class Send extends Base
|
|||||||
if ($this->sending->seek($pos)) {
|
if ($this->sending->seek($pos)) {
|
||||||
$this->pos = $pos;
|
$this->pos = $pos;
|
||||||
|
|
||||||
Log::debug(sprintf('%s:= Content Seek to [%d]',self::LOGKEY,$this->pos));
|
Log::debug(sprintf('%s:= Seeked to [%d]',self::LOGKEY,$this->pos));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ final class Dynamic extends Send
|
|||||||
return $this->sent->timestamp;
|
return $this->sent->timestamp;
|
||||||
|
|
||||||
case 'size':
|
case 'size':
|
||||||
return $this->{$key};
|
return strlen($this->buffer);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -104,7 +104,6 @@ final class Dynamic extends Send
|
|||||||
public function open(string $compress=''): bool
|
public function open(string $compress=''): bool
|
||||||
{
|
{
|
||||||
$this->buffer = (string)$this->item;
|
$this->buffer = (string)$this->item;
|
||||||
$this->size = strlen($this->buffer);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ class Node
|
|||||||
private Collection $ftns_authed; // The FTNs we have validated
|
private Collection $ftns_authed; // The FTNs we have validated
|
||||||
private Collection $ftns_other; // Other FTN addresses presented
|
private Collection $ftns_other; // Other FTN addresses presented
|
||||||
private bool $authed; // Have we authenticated the remote.
|
private bool $authed; // Have we authenticated the remote.
|
||||||
private Address $originate; // When we originate a call, this is who we are after
|
|
||||||
|
|
||||||
private int $options; // This nodes capabilities/options
|
private int $options; // This nodes capabilities/options
|
||||||
|
|
||||||
@ -85,10 +84,6 @@ class Node
|
|||||||
|
|
||||||
// The nodes password
|
// The nodes password
|
||||||
case 'password':
|
case 'password':
|
||||||
// If we are originating a session, we'll use that password.
|
|
||||||
if (isset($this->originate))
|
|
||||||
return $this->originate->pass_session;
|
|
||||||
|
|
||||||
// If we have already authed, we'll use that password.
|
// If we have already authed, we'll use that password.
|
||||||
if ($this->ftns_authed->count())
|
if ($this->ftns_authed->count())
|
||||||
return $this->ftns_authed->first()->pass_session;
|
return $this->ftns_authed->first()->pass_session;
|
||||||
@ -199,8 +194,6 @@ class Node
|
|||||||
throw new Exception('Already authed');
|
throw new Exception('Already authed');
|
||||||
|
|
||||||
foreach ($this->ftns as $o) {
|
foreach ($this->ftns as $o) {
|
||||||
Log::debug(sprintf('%s:- Attempting to authenticate [%s] with [%s]',self::LOGKEY,$o->ftn,$o->pass_session));
|
|
||||||
|
|
||||||
if (! $sespass=$o->pass_session)
|
if (! $sespass=$o->pass_session)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -276,8 +269,7 @@ class Node
|
|||||||
*/
|
*/
|
||||||
public function originate(Address $o): void
|
public function originate(Address $o): void
|
||||||
{
|
{
|
||||||
$this->originate = $o;
|
$this->ftns_authed->push($o);
|
||||||
$this->ftns_authed = $o->system->match($o->zone,Address::NODE_ALL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -291,11 +283,19 @@ class Node
|
|||||||
if ($this->authed)
|
if ($this->authed)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- Making sure we called [%s] from [%s]',self::LOGKEY,$this->originate->ftn,$this->ftns->pluck('ftn')->join(',')));
|
if ($this->ftns_authed->count() !== 1 || ! $this->ftns->count())
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
$this->authed = $this->ftns->pluck('ftn')->contains($this->originate->ftn);
|
$ftn = $this->ftns_authed->first()->ftn;
|
||||||
|
|
||||||
return $this->authed;
|
return $this->ftns->search(function($item) use ($ftn) {
|
||||||
|
if ($item->ftn === $ftn) {
|
||||||
|
$item->system->last_session = Carbon::now();
|
||||||
|
$item->system->save();
|
||||||
|
$this->authed = TRUE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}) !== FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function optionClear(int $key): void
|
public function optionClear(int $key): void
|
||||||
|
@ -332,13 +332,13 @@ class Page
|
|||||||
$subtext = substr($this->text,$current_pos,$space_pos);
|
$subtext = substr($this->text,$current_pos,$space_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the rest of the string will fit on the current line
|
// If the reset of the string will fit on the current line
|
||||||
} elseif ($text_length-$current_pos < static::MSG_WIDTH-$this->x-$buffer) {
|
} elseif ($text_length-$current_pos < static::MSG_WIDTH-$buffer) {
|
||||||
$subtext = substr($this->text,$current_pos);
|
$subtext = substr($this->text,$current_pos);
|
||||||
|
|
||||||
// Get the next lines worth of chars, breaking on a space
|
// Get the next lines worth of chars, breaking on a space
|
||||||
} else {
|
} else {
|
||||||
$subtext = $this->text_substr(substr($this->text,$current_pos),static::MSG_WIDTH-$this->x-$buffer);
|
$subtext = $this->text_substr(substr($this->text,$current_pos),static::MSG_WIDTH-$buffer);
|
||||||
|
|
||||||
// Include the text up to the last space
|
// Include the text up to the last space
|
||||||
if (substr($this->text,$current_pos+strlen($subtext),1) !== ' ')
|
if (substr($this->text,$current_pos+strlen($subtext),1) !== ' ')
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace App\Classes;
|
namespace App\Classes;
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Config;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
use App\Classes\File\{Receive,Send};
|
use App\Classes\File\{Receive,Send};
|
||||||
@ -108,7 +107,7 @@ abstract class Protocol
|
|||||||
public const TCP_SPEED = 115200;
|
public const TCP_SPEED = 115200;
|
||||||
|
|
||||||
protected SocketClient $client; /* Our socket details */
|
protected SocketClient $client; /* Our socket details */
|
||||||
protected Setup $setup; /* Our setup */
|
protected ?Setup $setup; /* Our setup */
|
||||||
protected Node $node; /* The node we are communicating with */
|
protected Node $node; /* The node we are communicating with */
|
||||||
/** The list of files we are sending */
|
/** The list of files we are sending */
|
||||||
protected Send $send;
|
protected Send $send;
|
||||||
@ -135,9 +134,12 @@ abstract class Protocol
|
|||||||
|
|
||||||
abstract protected function protocol_session(bool $force_queue=FALSE): int;
|
abstract protected function protocol_session(bool $force_queue=FALSE): int;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct(Setup $o=NULL)
|
||||||
{
|
{
|
||||||
$this->setup = Config::get('setup',Setup::findOrFail(config('app.id')));
|
if ($o && ! $o->system->akas->count())
|
||||||
|
throw new \Exception('We dont have any ACTIVE FTN addresses assigned');
|
||||||
|
|
||||||
|
$this->setup = $o;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,7 +259,7 @@ abstract class Protocol
|
|||||||
throw new SocketException(SocketException::CANT_ACCEPT,'Could not fork process');
|
throw new SocketException(SocketException::CANT_ACCEPT,'Could not fork process');
|
||||||
|
|
||||||
if ($pid)
|
if ($pid)
|
||||||
Log::info(sprintf('%s:+ New connection from [%s], thread [%d] created',self::LOGKEY,$client->address_remote,$pid));
|
Log::info(sprintf('%s:+ New connection, thread [%d] created',self::LOGKEY,$pid));
|
||||||
|
|
||||||
// Parent return ready for next connection
|
// Parent return ready for next connection
|
||||||
return $pid;
|
return $pid;
|
||||||
@ -316,7 +318,7 @@ abstract class Protocol
|
|||||||
Log::debug(sprintf('%s:- Presenting limited AKAs [%s]',self::LOGKEY,$addresses->pluck('ftn')->join(',')));
|
Log::debug(sprintf('%s:- Presenting limited AKAs [%s]',self::LOGKEY,$addresses->pluck('ftn')->join(',')));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$addresses = our_address();
|
$addresses = $this->setup->system->akas;
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- Presenting ALL our AKAs [%s]',self::LOGKEY,$addresses->pluck('ftn')->join(',')));
|
Log::debug(sprintf('%s:- Presenting ALL our AKAs [%s]',self::LOGKEY,$addresses->pluck('ftn')->join(',')));
|
||||||
}
|
}
|
||||||
@ -429,8 +431,8 @@ abstract class Protocol
|
|||||||
|
|
||||||
if ($so && $so->exists) {
|
if ($so && $so->exists) {
|
||||||
foreach ($this->node->aka_other as $aka)
|
foreach ($this->node->aka_other as $aka)
|
||||||
// @todo For disabled zones, we shouldnt refuse to record the address
|
if (! Address::findFTN($aka)) {
|
||||||
if ((! Address::findFTN($aka)) && ($oo=Address::createFTN($aka,$so))) {
|
$oo = Address::createFTN($aka,$so);
|
||||||
$oo->validated = TRUE;
|
$oo->validated = TRUE;
|
||||||
$oo->save();
|
$oo->save();
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ use App\Classes\Protocol as BaseProtocol;
|
|||||||
use App\Classes\Sock\Exception\SocketException;
|
use App\Classes\Sock\Exception\SocketException;
|
||||||
use App\Classes\Sock\SocketClient;
|
use App\Classes\Sock\SocketClient;
|
||||||
use App\Exceptions\{FileGrewException,InvalidFTNException};
|
use App\Exceptions\{FileGrewException,InvalidFTNException};
|
||||||
use App\Models\{Address,Mailer,Setup};
|
use App\Models\{Address,Mailer};
|
||||||
|
|
||||||
final class Binkp extends BaseProtocol
|
final class Binkp extends BaseProtocol
|
||||||
{
|
{
|
||||||
@ -177,8 +177,8 @@ final class Binkp extends BaseProtocol
|
|||||||
|
|
||||||
$this->msgs(self::BPM_BSY,'RETRY 0600: Down for maintenance, back soon...');
|
$this->msgs(self::BPM_BSY,'RETRY 0600: Down for maintenance, back soon...');
|
||||||
|
|
||||||
// @note Sometimes the remote drops the connection when we send the busy
|
while ($this->tx_left || $this->mqueue->count())
|
||||||
while (($this->tx_left || $this->mqueue->count()) && $this->binkp_send()) {}
|
$this->binkp_send();
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -195,7 +195,7 @@ final class Binkp extends BaseProtocol
|
|||||||
$this->msgs(self::BPM_NUL,sprintf('NDL %d,TCP,BINKP',$this->client->speed));
|
$this->msgs(self::BPM_NUL,sprintf('NDL %d,TCP,BINKP',$this->client->speed));
|
||||||
$this->msgs(self::BPM_NUL,sprintf('TIME %s',Carbon::now()->toRfc2822String()));
|
$this->msgs(self::BPM_NUL,sprintf('TIME %s',Carbon::now()->toRfc2822String()));
|
||||||
$this->msgs(self::BPM_NUL,
|
$this->msgs(self::BPM_NUL,
|
||||||
sprintf('VER %s/%s %s/%s',Setup::PRODUCT_NAME_SHORT,Setup::version(),self::PROT,self::VERSION));
|
sprintf('VER %s-%s %s/%s',config('app.name'),$this->setup->version,self::PROT,self::VERSION));
|
||||||
|
|
||||||
if ($this->originate) {
|
if ($this->originate) {
|
||||||
$opt = $this->capGet(self::F_NOREL,self::O_WANT) ? ' NR' : '';
|
$opt = $this->capGet(self::F_NOREL,self::O_WANT) ? ' NR' : '';
|
||||||
@ -393,13 +393,11 @@ final class Binkp extends BaseProtocol
|
|||||||
|
|
||||||
if ($this->capGet(self::F_CRYPT,self::O_YES)) {
|
if ($this->capGet(self::F_CRYPT,self::O_YES)) {
|
||||||
Log::debug(sprintf('%s:%% Decrypting data from remote.',self::LOGKEY));
|
Log::debug(sprintf('%s:%% Decrypting data from remote.',self::LOGKEY));
|
||||||
$this->rx_buf .= ($x=$this->crypt_in->decrypt($rx_buf));
|
$this->rx_buf .= $this->crypt_in->decrypt($rx_buf);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$this->rx_buf .= ($x=$rx_buf);
|
$this->rx_buf .= $rx_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- We read [%d] chars from remote',self::LOGKEY,strlen($x)),['rx_buf'=>hex_dump($x)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- Read buffer has [%d] chars to process.',self::LOGKEY,strlen($this->rx_buf)));
|
Log::debug(sprintf('%s:- Read buffer has [%d] chars to process.',self::LOGKEY,strlen($this->rx_buf)));
|
||||||
@ -436,7 +434,7 @@ final class Binkp extends BaseProtocol
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (static::DEBUG)
|
if (static::DEBUG)
|
||||||
Log::debug(sprintf('%s:- rx_buf size [%d]',self::LOGKEY,strlen($this->rx_buf)));
|
Log::debug(sprintf('%s: - binkp_recv BUFFER [%d]',self::LOGKEY,strlen($this->rx_buf)));
|
||||||
|
|
||||||
$msg = ord(substr($this->rx_buf,0,1));
|
$msg = ord(substr($this->rx_buf,0,1));
|
||||||
|
|
||||||
@ -489,11 +487,6 @@ final class Binkp extends BaseProtocol
|
|||||||
$rc = $this->M_get($data);
|
$rc = $this->M_get($data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case self::BPM_SKIP:
|
|
||||||
Log::debug(sprintf('%s:- SKIP:Remote requested to skip file [%s]',self::LOGKEY,$data));
|
|
||||||
$rc = $this->M_skip($data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case self::BPM_GOTSKIP:
|
case self::BPM_GOTSKIP:
|
||||||
Log::debug(sprintf('%s:- GOT:Remote received, or already has a file [%s]',self::LOGKEY,$data));
|
Log::debug(sprintf('%s:- GOT:Remote received, or already has a file [%s]',self::LOGKEY,$data));
|
||||||
$rc = $this->M_gotskip($data);
|
$rc = $this->M_gotskip($data);
|
||||||
@ -663,7 +656,7 @@ final class Binkp extends BaseProtocol
|
|||||||
$offs = (int)$this->strsep($str,' ');
|
$offs = (int)$this->strsep($str,' ');
|
||||||
$flags = $this->strsep($str,' ');
|
$flags = $this->strsep($str,' ');
|
||||||
|
|
||||||
if ($name && is_numeric($size) && $time) {
|
if ($name && $size && $time) {
|
||||||
return [
|
return [
|
||||||
'file'=>['name'=>$name,'size'=>$size,'mtime'=>$time],
|
'file'=>['name'=>$name,'size'=>$size,'mtime'=>$time],
|
||||||
'offs'=>$offs,
|
'offs'=>$offs,
|
||||||
@ -718,7 +711,7 @@ final class Binkp extends BaseProtocol
|
|||||||
|
|
||||||
// If we only present limited AKAs dont validate password against akas outside of the domains we present
|
// If we only present limited AKAs dont validate password against akas outside of the domains we present
|
||||||
} elseif (is_null(our_address($o))) {
|
} elseif (is_null(our_address($o))) {
|
||||||
Log::debug(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(',')));
|
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(',')));
|
||||||
|
|
||||||
$this->node->ftn_other = $rem_aka;
|
$this->node->ftn_other = $rem_aka;
|
||||||
continue;
|
continue;
|
||||||
@ -733,7 +726,6 @@ final class Binkp extends BaseProtocol
|
|||||||
Log::info(sprintf('%s:- Got AKA [%s]',self::LOGKEY,$rem_aka));
|
Log::info(sprintf('%s:- Got AKA [%s]',self::LOGKEY,$rem_aka));
|
||||||
|
|
||||||
// We'll update this address status
|
// We'll update this address status
|
||||||
// @todo this shouldnt be here, since we havent authenticated the node
|
|
||||||
$o->validated = TRUE;
|
$o->validated = TRUE;
|
||||||
$o->role &= ~(Address::NODE_HOLD|Address::NODE_DOWN);
|
$o->role &= ~(Address::NODE_HOLD|Address::NODE_DOWN);
|
||||||
$o->save();
|
$o->save();
|
||||||
@ -894,13 +886,16 @@ final class Binkp extends BaseProtocol
|
|||||||
//if ($this->recv->fd)
|
//if ($this->recv->fd)
|
||||||
// $this->recv->close();
|
// $this->recv->close();
|
||||||
|
|
||||||
// If we cannot understand the file, we'll send back a SKIP
|
|
||||||
if (! ($file=$this->file_parse($buf))) {
|
if (! ($file=$this->file_parse($buf))) {
|
||||||
Log::error(sprintf('%s:! UNPARSABLE file info [%s]',self::LOGKEY,$buf));
|
Log::error(sprintf('%s:! UNPARSABLE file info [%s]',self::LOGKEY,$buf));
|
||||||
$this->msgs(self::BPM_ERR,sprintf('M_FILE: unparsable file info: "%s", what are you on?',$buf));
|
$this->msgs(self::BPM_ERR,sprintf('M_FILE: unparsable file info: "%s", what are you on?',$buf));
|
||||||
$this->msgs(self::BPM_SKIP,$buf);
|
|
||||||
|
|
||||||
return TRUE;
|
if ($this->sessionGet(self::SE_SENDFILE))
|
||||||
|
$this->send->close(FALSE,$this->node);
|
||||||
|
|
||||||
|
$this->rc = self::S_FAILURE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In NR mode, when we got -1 for the file offsite, the reply to our get will confirm our requested offset.
|
// In NR mode, when we got -1 for the file offsite, the reply to our get will confirm our requested offset.
|
||||||
@ -918,18 +913,6 @@ final class Binkp extends BaseProtocol
|
|||||||
|
|
||||||
$this->recv->new($file['file'],$this->node->address,$this->force_queue);
|
$this->recv->new($file['file'],$this->node->address,$this->force_queue);
|
||||||
|
|
||||||
// If the file is zero byte size, we'll skip it
|
|
||||||
if ($this->recv->recvsize === 0) {
|
|
||||||
Log::alert(sprintf('%s:! SKIPPING zero byte file info [%s]',self::LOGKEY,$this->recv->nameas));
|
|
||||||
|
|
||||||
$this->msgs(self::BPM_SKIP,$this->recv->name_size_time);
|
|
||||||
|
|
||||||
// Close the file, since we are skipping it.
|
|
||||||
$this->recv->close();
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch ($this->recv->open($file['offs']<0,$file['flags'])) {
|
switch ($this->recv->open($file['offs']<0,$file['flags'])) {
|
||||||
case self::FOP_ERROR:
|
case self::FOP_ERROR:
|
||||||
@ -1023,46 +1006,7 @@ final class Binkp extends BaseProtocol
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* M_SKIP commands
|
* M_GOT/M_SKIP commands
|
||||||
*
|
|
||||||
* @param string $buf
|
|
||||||
* @return bool
|
|
||||||
* @throws \Exception
|
|
||||||
* @todo We need to not add more files this session if a node skips a file
|
|
||||||
*/
|
|
||||||
private function M_skip(string $buf): bool
|
|
||||||
{
|
|
||||||
Log::alert(sprintf('%s:+ Remote request to skip the file for now [%s]',self::LOGKEY,$buf));
|
|
||||||
|
|
||||||
if ($file = $this->file_parse($buf)) {
|
|
||||||
if ($this->send->nameas
|
|
||||||
&& ! strncasecmp(Arr::get($file,'file.name'),$this->send->nameas,self::MAX_PATH)
|
|
||||||
&& $this->send->mtime === Arr::get($file,'file.mtime')
|
|
||||||
&& $this->send->size === Arr::get($file,'file.size'))
|
|
||||||
{
|
|
||||||
if ((! $this->sessionGet(self::SE_SENDFILE)) && (! $this->sessionGet(self::SE_WAITGOT))) {
|
|
||||||
Log::error(sprintf('%s:! M_skip for unknown file [%s]',self::LOGKEY,$buf));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log::info(sprintf('%s:= Packet/File [%s], type [%d] skipped.',self::LOGKEY,$this->send->nameas,$this->send->type));
|
|
||||||
$this->sessionClear(self::SE_WAITGOT|self::SE_SENDFILE);
|
|
||||||
|
|
||||||
$this->send->close(FALSE,$this->node);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log::error(sprintf('%s:! M_skip not for our file? [%s]',self::LOGKEY,$buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log::error(sprintf('%s:! UNPARSABLE file info [%s]',self::LOGKEY,$buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* M_GOTSKIP command
|
|
||||||
*
|
*
|
||||||
* @param string $buf
|
* @param string $buf
|
||||||
* @return bool
|
* @return bool
|
||||||
@ -1286,13 +1230,9 @@ final class Binkp extends BaseProtocol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->optionGet(self::O_PWD)) {
|
if ($this->optionGet(self::O_PWD))
|
||||||
Log::info(sprintf('%s:- SECURE',self::LOGKEY));
|
Log::info(sprintf('%s:- SECURE',self::LOGKEY));
|
||||||
|
|
||||||
// @todo Since we have connected, if the node was marked down/hold reset that
|
|
||||||
// Notification::route('netmail',$ao->system->aka_unknown()->first()->withoutRelations())->notify(new NodeMarkedDownNetmail($ao->withoutRelations()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->binkp_hsdone();
|
return $this->binkp_hsdone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1388,9 +1328,6 @@ final class Binkp extends BaseProtocol
|
|||||||
if ($this->node->aka_authed) {
|
if ($this->node->aka_authed) {
|
||||||
$this->msgs(self::BPM_OK,sprintf('%ssecure',$have_pwd ? '' : 'non-'));
|
$this->msgs(self::BPM_OK,sprintf('%ssecure',$have_pwd ? '' : 'non-'));
|
||||||
|
|
||||||
// @todo Since we have connected, if the node was marked down/hold reset that
|
|
||||||
// Notification::route('netmail',$ao->system->aka_unknown()->first()->withoutRelations())->notify(new NodeMarkedDownNetmail($ao->withoutRelations()));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$this->msgs(self::OK,'non-secure');
|
$this->msgs(self::OK,'non-secure');
|
||||||
}
|
}
|
||||||
@ -1573,7 +1510,12 @@ final class Binkp extends BaseProtocol
|
|||||||
Log::info(sprintf('%s:- We have authed these AKAs [%s]',self::LOGKEY,$node->aka_remote_authed->pluck('ftn')->join(',')));
|
Log::info(sprintf('%s:- We have authed these AKAs [%s]',self::LOGKEY,$node->aka_remote_authed->pluck('ftn')->join(',')));
|
||||||
|
|
||||||
foreach ($node->aka_remote_authed as $ao) {
|
foreach ($node->aka_remote_authed as $ao) {
|
||||||
Log::info(sprintf('%s:- Checking for any new mail and files to [%s]',self::LOGKEY,$ao->ftn));
|
Log::debug(sprintf('%s:- Checking for any new mail and files to [%s]',self::LOGKEY,$ao->ftn));
|
||||||
|
|
||||||
|
if (! $ao->validated) {
|
||||||
|
Log::alert(sprintf('%s:! Address [%s] is not validated, so we wont bundle mail for it',self::LOGKEY,$ao->ftn));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$this->send->mail($ao);
|
$this->send->mail($ao);
|
||||||
$this->send->files($ao);
|
$this->send->files($ao);
|
||||||
@ -1590,11 +1532,11 @@ final class Binkp extends BaseProtocol
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::info(sprintf('%s:- We have [%d] items to send to [%s]',self::LOGKEY,$this->send->togo_count,$ao->ftn));
|
Log::info(sprintf('%s:- We have [%d] items to send to [%s]',self::LOGKEY,$this->send->togo_count,$ao->system->name));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// @todo We should only send netmail if unauthenticated - netmail that is direct to this node (no routing)
|
// @todo We should only send netmail if unauthenticated - netmail that is direct to this node (no routing)
|
||||||
Log::alert(sprintf('%s:- Not AUTHed so not looking for mail, but we know these akas [%s]',self::LOGKEY,$node->aka_remote->pluck('ftn')->join(',')));
|
Log::debug(sprintf('%s:- Not AUTHed so not looking for mail, but we know these akas [%s]',self::LOGKEY,$node->aka_remote->pluck('ftn')->join(',')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ final class DNS extends BaseProtocol
|
|||||||
$this->client = $client;
|
$this->client = $client;
|
||||||
$this->protocol_session();
|
$this->protocol_session();
|
||||||
|
|
||||||
Log::debug(sprintf('%s:= onConnect - Connection closed [%s]',self::LOGKEY,$client->address_remote));
|
Log::info(sprintf('%s:= onConnect - Connection closed [%s]',self::LOGKEY,$client->address_remote));
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ final class DNS extends BaseProtocol
|
|||||||
case self::DNS_TYPE_AAAA:
|
case self::DNS_TYPE_AAAA:
|
||||||
case self::DNS_TYPE_SRV:
|
case self::DNS_TYPE_SRV:
|
||||||
case self::DNS_TYPE_TXT:
|
case self::DNS_TYPE_TXT:
|
||||||
Log::debug(sprintf('%s:= Looking for record [%s] for [%s]',self::LOGKEY,$this->query->type,$this->query->domain));
|
Log::info(sprintf('%s:= Looking for record [%s] for [%s]',self::LOGKEY,$this->query->type,$this->query->domain));
|
||||||
|
|
||||||
$labels = clone($this->query->labels);
|
$labels = clone($this->query->labels);
|
||||||
$mailer = '';
|
$mailer = '';
|
||||||
@ -232,15 +232,14 @@ final class DNS extends BaseProtocol
|
|||||||
// Check we have the right record
|
// Check we have the right record
|
||||||
if ((! $ao) || (($rootdn !== self::TLD) && ((! $ao->zone->domain->dnsdomain) || ($ao->zone->domain->dnsdomain !== $rootdn)))) {
|
if ((! $ao) || (($rootdn !== self::TLD) && ((! $ao->zone->domain->dnsdomain) || ($ao->zone->domain->dnsdomain !== $rootdn)))) {
|
||||||
Log::alert(sprintf('%s:= No DNS record for [%d:%d/%d.%d@%s]',self::LOGKEY,$z,$n,$f,$p,$d));
|
Log::alert(sprintf('%s:= No DNS record for [%d:%d/%d.%d@%s]',self::LOGKEY,$z,$n,$f,$p,$d));
|
||||||
|
|
||||||
return $this->nameerr();
|
return $this->nameerr();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($this->query->type) {
|
switch ($this->query->type) {
|
||||||
case self::DNS_TYPE_SRV:
|
case self::DNS_TYPE_SRV:
|
||||||
if (($ao->system->address) && ($xx=$ao->system->mailers->where('id',$mailer->id)->pop())) {
|
|
||||||
Log::info(sprintf('%s:= Returning [%s] for DNS query [%s]',self::LOGKEY,$ao->system->address,$ao->ftn));
|
Log::info(sprintf('%s:= Returning [%s] for DNS query [%s]',self::LOGKEY,$ao->system->address,$ao->ftn));
|
||||||
|
|
||||||
|
if (($ao->system->address) && ($xx=$ao->system->mailers->where('id',$mailer->id)->pop())) {
|
||||||
return $this->reply(
|
return $this->reply(
|
||||||
self::DNS_NOERROR,
|
self::DNS_NOERROR,
|
||||||
[serialize([
|
[serialize([
|
||||||
@ -251,8 +250,6 @@ final class DNS extends BaseProtocol
|
|||||||
]) => self::DNS_TYPE_SRV]);
|
]) => self::DNS_TYPE_SRV]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log::alert(sprintf('%s:! No/incomplete hostname/port details for [%d] for DNS query [%s]',self::LOGKEY,$ao->system->id,$ao->ftn));
|
|
||||||
|
|
||||||
return $this->nodata();
|
return $this->nodata();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +261,7 @@ final class DNS extends BaseProtocol
|
|||||||
[serialize($ao->system->name) => self::DNS_TYPE_TXT]);
|
[serialize($ao->system->name) => self::DNS_TYPE_TXT]);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Log::info(sprintf('%s:= Returning [%s] for DNS query [%s]',self::LOGKEY,$ao->system->address ?: 'NO ADDRESS',$ao->ftn));
|
Log::info(sprintf('%s:= Returning [%s] for DNS query [%s]',self::LOGKEY,$ao->system->address,$ao->ftn));
|
||||||
|
|
||||||
return (! $ao->system->address)
|
return (! $ao->system->address)
|
||||||
? $this->nodata()
|
? $this->nodata()
|
||||||
|
@ -207,8 +207,8 @@ final class EMSI extends BaseProtocol implements CRCInterface,ZmodemInterface
|
|||||||
// Mailer Details
|
// Mailer Details
|
||||||
$makedata .= sprintf('{%s}{%s}{%s}{%s}',
|
$makedata .= sprintf('{%s}{%s}{%s}{%s}',
|
||||||
Setup::product_id(),
|
Setup::product_id(),
|
||||||
Setup::PRODUCT_NAME_SHORT,
|
config('app.name'),
|
||||||
Setup::version(),
|
$this->setup->version,
|
||||||
'#000000' // Serial Numbers
|
'#000000' // Serial Numbers
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1061,9 +1061,6 @@ final class EMSI extends BaseProtocol implements CRCInterface,ZmodemInterface
|
|||||||
return (self::S_REDIAL|self::S_ADDTRY);
|
return (self::S_REDIAL|self::S_ADDTRY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo Since we have connected, if the node was marked down/hold reset that
|
|
||||||
// Notification::route('netmail',$ao->system->aka_unknown()->first()->withoutRelations())->notify(new NodeMarkedDownNetmail($ao->withoutRelations()));
|
|
||||||
|
|
||||||
// @todo Lock Node AKAs
|
// @todo Lock Node AKAs
|
||||||
|
|
||||||
Log::info(sprintf('%s:- We have [%lu%s] mail, [%lu%s] files',self::LOGKEY,$this->send->mail_size,'b',$this->send->files_size,'b'));
|
Log::info(sprintf('%s:- We have [%lu%s] mail, [%lu%s] files',self::LOGKEY,$this->send->mail_size,'b',$this->send->files_size,'b'));
|
||||||
@ -1237,6 +1234,11 @@ final class EMSI extends BaseProtocol implements CRCInterface,ZmodemInterface
|
|||||||
// Add our mail to the queue if we have authenticated
|
// Add our mail to the queue if we have authenticated
|
||||||
if ($this->node->aka_authed)
|
if ($this->node->aka_authed)
|
||||||
foreach ($this->node->aka_remote_authed as $ao) {
|
foreach ($this->node->aka_remote_authed as $ao) {
|
||||||
|
if (! $ao->validated) {
|
||||||
|
Log::alert(sprintf('%s:! Address [%s] is not validated, so we wont bundle mail for it',self::LOGKEY,$ao->ftn));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Send mail
|
// Send mail
|
||||||
while ($this->send->mail($ao)) {
|
while ($this->send->mail($ao)) {
|
||||||
$z = new Zmodem;
|
$z = new Zmodem;
|
||||||
|
@ -48,7 +48,7 @@ final class SocketClient {
|
|||||||
/** @var string Data in the RX buffer */
|
/** @var string Data in the RX buffer */
|
||||||
private string $rx_buf = '';
|
private string $rx_buf = '';
|
||||||
|
|
||||||
public function __construct (\Socket $connection,bool $originate=FALSE) {
|
public function __construct (\Socket $connection) {
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
|
|
||||||
if ($this->type === SOCK_STREAM) {
|
if ($this->type === SOCK_STREAM) {
|
||||||
@ -56,58 +56,12 @@ final class SocketClient {
|
|||||||
socket_getpeername($connection,$this->address_remote,$this->port_remote);
|
socket_getpeername($connection,$this->address_remote,$this->port_remote);
|
||||||
|
|
||||||
// If HAPROXY is used, work get the clients address
|
// If HAPROXY is used, work get the clients address
|
||||||
if ((! $originate) && config('fido.haproxy')) {
|
if (config('fido.haproxy')) {
|
||||||
Log::debug(sprintf('%s:+ HAPROXY connection host [%s] on port [%d] (%s)',self::LOGKEY,$this->address_remote,$this->port_remote,$this->type));
|
Log::debug(sprintf('%s:+ HAPROXY connection host [%s] on port [%d] (%s)',self::LOGKEY,$this->address_remote,$this->port_remote,$this->type));
|
||||||
|
|
||||||
if (($x=$this->read(5,6)) === 'PROXY ')
|
if ($this->read(5,12) !== "\x0d\x0a\x0d\x0a\x00\x0d\x0aQUIT\x0a")
|
||||||
$vers = 1;
|
|
||||||
|
|
||||||
elseif (($x === "\x0d\x0a\x0d\x0a\x00\x0d") && ($this->read('5,6') === "\x0aQUIT\x0a"))
|
|
||||||
$vers = 2;
|
|
||||||
|
|
||||||
else
|
|
||||||
throw new HAproxyException('Failed to initialise HAPROXY connection');
|
throw new HAproxyException('Failed to initialise HAPROXY connection');
|
||||||
|
|
||||||
switch ($vers) {
|
|
||||||
case 1:
|
|
||||||
// Protocol/Address Family
|
|
||||||
switch ($x=$this->read(5,5)) {
|
|
||||||
case 'TCP4 ':
|
|
||||||
$p = 4;
|
|
||||||
break;
|
|
||||||
case 'TCP6 ':
|
|
||||||
$p = 6;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new HAproxyException(sprintf('HAPROXY protocol [%d] is not handled',$x));
|
|
||||||
}
|
|
||||||
|
|
||||||
$read = $this->read(5,104-11);
|
|
||||||
|
|
||||||
// IPv4
|
|
||||||
if (($p === 4) || ($p === 6)) {
|
|
||||||
$parse = collect(sscanf($read,'%s %s %s %s'));
|
|
||||||
|
|
||||||
$src = Arr::get($parse,0);
|
|
||||||
$dst = Arr::get($parse,1);
|
|
||||||
$src_port = (int)Arr::get($parse,2);
|
|
||||||
$dst_port = (int)Arr::get($parse,3);
|
|
||||||
$len = $parse->map(fn($item)=>strlen($item))->sum()+3;
|
|
||||||
|
|
||||||
// The last 2 chars should be "\r\n"
|
|
||||||
if (($x=substr($read,$len)) !== "\r\n")
|
|
||||||
throw new HAproxyException(sprintf('HAPROXY parsing failed for version [%d] [%s] (%s)',$p,$read,hex_dump($x)));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new HAproxyException(sprintf('HAPROXY version [%d] is not handled [%s]',$p,$read));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->port_remote = $src_port;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
// Version/Command
|
// Version/Command
|
||||||
$vc = $this->read_ch(5);
|
$vc = $this->read_ch(5);
|
||||||
|
|
||||||
@ -129,6 +83,7 @@ final class SocketClient {
|
|||||||
|
|
||||||
// Protocol/Address Family
|
// Protocol/Address Family
|
||||||
$pa = $this->read_ch(5);
|
$pa = $this->read_ch(5);
|
||||||
|
$p = NULL;
|
||||||
|
|
||||||
switch ($x=($pa>>4)&0x7) {
|
switch ($x=($pa>>4)&0x7) {
|
||||||
case 1: // AF_INET
|
case 1: // AF_INET
|
||||||
@ -139,7 +94,8 @@ final class SocketClient {
|
|||||||
$p = 6;
|
$p = 6;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new HAproxyException(sprintf('HAPROXY protocol [%d] is not handled',$x));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($x=($pa&0x7)) {
|
switch ($x=($pa&0x7)) {
|
||||||
@ -166,28 +122,21 @@ final class SocketClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$src_port = unpack('n',$this->read(5,2));
|
$src_port = unpack('n',$this->read(5,2));
|
||||||
$dst_port = Arr::get(unpack('n',$this->read(5,2)),1);
|
$dst_port = unpack('n',$this->read(5,2));
|
||||||
|
|
||||||
$this->port_remote = Arr::get($src_port,1);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new HAproxyException('Failed to initialise HAPROXY connection');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->address_remote = $src;
|
$this->address_remote = $src;
|
||||||
|
$this->port_remote = Arr::get($src_port,1);
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- HAPROXY src [%s:%d] dst [%s:%d]',
|
Log::info(sprintf('%s:! HAPROXY src [%s:%d] dst [%s:%d]',
|
||||||
self::LOGKEY,
|
self::LOGKEY,
|
||||||
$this->address_remote,
|
$this->address_remote,
|
||||||
$this->port_remote,
|
$this->port_remote,
|
||||||
$dst,
|
$dst,
|
||||||
$dst_port,
|
Arr::get($dst_port,1),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::debug(sprintf('%s:+ Connection host [%s] on port [%d] (%s)',self::LOGKEY,$this->address_remote,$this->port_remote,$this->type));
|
Log::info(sprintf('%s:+ Connection host [%s] on port [%d] (%s)',self::LOGKEY,$this->address_remote,$this->port_remote,$this->type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,14 +184,13 @@ final class SocketClient {
|
|||||||
* @param string $address
|
* @param string $address
|
||||||
* @param int $port
|
* @param int $port
|
||||||
* @return static
|
* @return static
|
||||||
* @throws SocketException|HAproxyException
|
* @throws SocketException
|
||||||
*/
|
*/
|
||||||
public static function create(string $address,int $port): self
|
public static function create(string $address,int $port): self
|
||||||
{
|
{
|
||||||
Log::info(sprintf('%s:+ Creating connection to [%s:%d]',self::LOGKEY,$address,$port));
|
Log::info(sprintf('%s:+ Creating connection to [%s:%d]',self::LOGKEY,$address,$port));
|
||||||
|
|
||||||
$type = collect(config('fido.ip'))
|
$sort = collect(['AAAA','A']);
|
||||||
->filter(fn($item)=>$item['enabled']);
|
|
||||||
|
|
||||||
if (filter_var($address,FILTER_VALIDATE_IP))
|
if (filter_var($address,FILTER_VALIDATE_IP))
|
||||||
$resolved = collect([[
|
$resolved = collect([[
|
||||||
@ -251,15 +199,14 @@ final class SocketClient {
|
|||||||
]]);
|
]]);
|
||||||
else
|
else
|
||||||
// We only look at AAAA/A records
|
// We only look at AAAA/A records
|
||||||
$resolved = collect(dns_get_record($address,$type->map(fn($item)=>$item['type'])->sum()))
|
$resolved = collect(dns_get_record($address,DNS_AAAA|DNS_A))
|
||||||
->filter(fn($item)=>$type->has(Arr::get($item,'type')))
|
->filter(function($item) use ($sort) { return $sort->search(Arr::get($item,'type')) !== FALSE; })
|
||||||
->sort(fn($a,$b)=>$type->get(Arr::get($a,'type'))['order'] < $type->get(Arr::get($b,'type'))['order']);
|
->sort(function($item) use ($sort) { return $sort->search(Arr::get($item,'type')); });
|
||||||
|
|
||||||
if (! $resolved->count())
|
if (! $resolved->count())
|
||||||
throw new SocketException(SocketException::CANT_CONNECT,sprintf('%s doesnt resolved to an IPv4/IPv6 address',$address));
|
throw new SocketException(SocketException::CANT_CONNECT,sprintf('%s doesnt resolved to an IPv4/IPv6 address',$address));
|
||||||
|
|
||||||
$result = FALSE;
|
$result = FALSE;
|
||||||
$socket = NULL;
|
|
||||||
|
|
||||||
foreach ($resolved as $address) {
|
foreach ($resolved as $address) {
|
||||||
try {
|
try {
|
||||||
@ -289,7 +236,7 @@ final class SocketClient {
|
|||||||
if ($result === FALSE)
|
if ($result === FALSE)
|
||||||
throw new SocketException(SocketException::CANT_CONNECT,socket_strerror(socket_last_error($socket)));
|
throw new SocketException(SocketException::CANT_CONNECT,socket_strerror(socket_last_error($socket)));
|
||||||
|
|
||||||
return new self($socket,TRUE);
|
return new self($socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -405,7 +352,7 @@ final class SocketClient {
|
|||||||
Log::error(sprintf('%s:! Closing socket [%s]',self::LOGKEY,$e->getMessage()));
|
Log::error(sprintf('%s:! Closing socket [%s]',self::LOGKEY,$e->getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::debug(sprintf('%s:= Connection closed with [%s]',self::LOGKEY,$this->address_remote));
|
Log::info(sprintf('%s:= Connection closed with [%s]',self::LOGKEY,$this->address_remote));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
|
|
||||||
use App\Jobs\AddressClearQueue as Job;
|
|
||||||
use App\Models\Address;
|
|
||||||
|
|
||||||
class AddressClearQueue extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'address:clear:queue'
|
|
||||||
.' {ftn : FTN}';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Clear up anything queued for an FTN';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle(): int
|
|
||||||
{
|
|
||||||
$ao = Address::findFTN($this->argument('ftn'),TRUE,TRUE);
|
|
||||||
|
|
||||||
if (! $ao) {
|
|
||||||
$this->error('FTN not found: '.$this->argument('ftn'));
|
|
||||||
|
|
||||||
return self::FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Job::dispatchSync($ao);
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands\Areafix;
|
namespace App\Console\Commands\Areafix;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
use App\Jobs\AreafixRescan;
|
use App\Models\{Address,Echoarea,Echomail};
|
||||||
use App\Models\{Address,Echoarea};
|
|
||||||
|
|
||||||
class Rescan extends Command
|
class Rescan extends Command
|
||||||
{
|
{
|
||||||
@ -14,13 +14,7 @@ class Rescan extends Command
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'areafix:rescan'
|
protected $signature = 'areafix:rescan {ftn} {area} {days?}';
|
||||||
.' {ftn : FTN Address}'
|
|
||||||
.' {area : Echoarea Tag}'
|
|
||||||
.' {days? : Limit to messages authored days ago}'
|
|
||||||
.' {--j|queue : Queue the Job}'
|
|
||||||
.' {--Q|queuename=default : Queue on queue}'
|
|
||||||
.' {--R|export : Re-export previously sent messages}';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
@ -49,12 +43,50 @@ class Rescan extends Command
|
|||||||
if (! $this->argument('area'))
|
if (! $this->argument('area'))
|
||||||
throw new \Exception('Areaname is required');
|
throw new \Exception('Areaname is required');
|
||||||
|
|
||||||
$eo = Echoarea::where('name',$this->argument('area'))->sole();
|
$eao = Echoarea::where('name',$this->argument('area'))->singleOrFail();
|
||||||
|
if ($eao->domain_id !== $ao->zone->domain_id)
|
||||||
|
throw new \Exception(sprintf('Echo area [%s] is not in domain [%s] for FTN [%s]',$eao->name,$ao->zone->domain->name,$ao->ftn));
|
||||||
|
|
||||||
if ($this->option('queue'))
|
// Check that the user is subscribed
|
||||||
AreafixRescan::dispatch($ao,$eo,$this->argument('days'))->onQueue($this->option('queuename'));
|
if (! $ao->echoareas->contains($eao->id))
|
||||||
else
|
throw new \Exception(sprintf('FTN [%s] is not subscribed to [%s]',$ao->ftn,$eao->name));
|
||||||
AreafixRescan::dispatchSync($ao,$eo,$this->argument('days'));
|
|
||||||
|
// Check that an FTN can read the area
|
||||||
|
if (! $eao->can_read($ao->security))
|
||||||
|
throw new \Exception(sprintf('FTN [%s] doesnt have permission to receive [%s]',$ao->ftn,$eao->name));
|
||||||
|
|
||||||
|
foreach (Echomail::select('id')
|
||||||
|
->where('echoarea_id',$eao->id)
|
||||||
|
->when($this->argument('days'),function($query) {
|
||||||
|
return $query->where('created_at','>=',Carbon::now()->subDays($this->argument('days'))->startOfDay());
|
||||||
|
})
|
||||||
|
->orderBy('datetime')
|
||||||
|
->cursor() as $eo) {
|
||||||
|
|
||||||
|
// Echomail hasnt been exported before
|
||||||
|
if (! $eo->seenby->count()) {
|
||||||
|
$eo->seenby()->attach($ao->id,['export_at'=>Carbon::now()]);
|
||||||
|
$this->info(sprintf('Exported [%d] to [%s]',$eo->id,$ao->ftn3d));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$export = $eo->seenby->where('id',$ao->id)->pop();
|
||||||
|
|
||||||
|
// Echomail is pending export
|
||||||
|
if ($export && $export->pivot->export_at && is_null($export->pivot->sent_at) && is_null($export->pivot->sent_pkt)) {
|
||||||
|
$this->warn(sprintf('Not exporting [%d] already queued for [%s]',$eo->id,$ao->ftn3d));
|
||||||
|
|
||||||
|
// Echomail has been exported
|
||||||
|
} elseif ($export) {
|
||||||
|
$eo->seenby()->updateExistingPivot($ao,['export_at'=>Carbon::now(),'sent_at'=>NULL,'sent_pkt'=>NULL]);
|
||||||
|
$this->info(sprintf('Re-exported [%d] to [%s]',$eo->id,$ao->ftn3d));
|
||||||
|
|
||||||
|
// Echomail has not been exported
|
||||||
|
} else {
|
||||||
|
$eo->seenby()->attach($ao,['export_at'=>Carbon::now(),'sent_at'=>NULL,'sent_pkt'=>NULL]);
|
||||||
|
$this->info(sprintf('Exported [%d] to [%s]',$eo->id,$ao->ftn3d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return self::SUCCESS;
|
return self::SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class CommBinkpReceive extends Command
|
|||||||
$o = Setup::findOrFail(config('app.id'));
|
$o = Setup::findOrFail(config('app.id'));
|
||||||
|
|
||||||
$server = new SocketServer($o->binkp_port,$o->binkp_bind);
|
$server = new SocketServer($o->binkp_port,$o->binkp_bind);
|
||||||
$server->handler = [new Binkp,'onConnect'];
|
$server->handler = [new Binkp($o),'onConnect'];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$server->listen();
|
$server->listen();
|
||||||
|
@ -16,9 +16,7 @@ class CommBinkpSend extends Command
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'comm:binkp:send'
|
protected $signature = 'comm:binkp:send {ftn : FTN to Send to}';
|
||||||
.'{--N|now : Dont queue}'
|
|
||||||
.'{ftn : FTN to Send to}';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
@ -34,7 +32,7 @@ class CommBinkpSend extends Command
|
|||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$ao = Address::findFTN($this->argument('ftn'));
|
$ao = Address::findFTN($this->argument('ftn'));
|
||||||
if (! $ao)
|
if (! $ao)
|
||||||
@ -44,11 +42,6 @@ class CommBinkpSend extends Command
|
|||||||
|
|
||||||
$mo = Mailer::where('name',self::ID)->singleOrFail();
|
$mo = Mailer::where('name',self::ID)->singleOrFail();
|
||||||
|
|
||||||
if ($this->option('now'))
|
|
||||||
Job::dispatchSync($ao,$mo);
|
|
||||||
else
|
|
||||||
Job::dispatch($ao,$mo);
|
Job::dispatch($ao,$mo);
|
||||||
|
|
||||||
return self::SUCCESS;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class CommEMSIReceive extends Command
|
|||||||
$o = Setup::findOrFail(config('app.id'));
|
$o = Setup::findOrFail(config('app.id'));
|
||||||
|
|
||||||
$server = new SocketServer($o->emsi_port,$o->emsi_bind);
|
$server = new SocketServer($o->emsi_port,$o->emsi_bind);
|
||||||
$server->handler = [new EMSI,'onConnect'];
|
$server->handler = [new EMSI($o),'onConnect'];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$server->listen();
|
$server->listen();
|
||||||
|
@ -16,9 +16,7 @@ class CommEMSISend extends Command
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'comm:emsi:send'
|
protected $signature = 'comm:emsi:send {ftn : FTN to Send to}';
|
||||||
.'{--N|now : Dont queue}'
|
|
||||||
.'{ftn : FTN to Send to}';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
@ -34,7 +32,7 @@ class CommEMSISend extends Command
|
|||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$ao = Address::findFTN($this->argument('ftn'));
|
$ao = Address::findFTN($this->argument('ftn'));
|
||||||
if (! $ao)
|
if (! $ao)
|
||||||
@ -44,11 +42,6 @@ class CommEMSISend extends Command
|
|||||||
|
|
||||||
$mo = Mailer::where('name',self::ID)->singleOrFail();
|
$mo = Mailer::where('name',self::ID)->singleOrFail();
|
||||||
|
|
||||||
if ($this->option('now'))
|
|
||||||
Job::dispatchSync($ao,$mo);
|
|
||||||
else
|
|
||||||
Job::dispatch($ao,$mo);
|
Job::dispatch($ao,$mo);
|
||||||
|
|
||||||
return self::SUCCESS;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,11 +49,6 @@ class PacketDump extends Command
|
|||||||
throw new \Exception('Unknown type: '.$this->argument('type'));
|
throw new \Exception('Unknown type: '.$this->argument('type'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($pkt)) {
|
|
||||||
$this->info(sprintf('No packet for [%s] of type [%s]',$this->argument('ftn'),$this->argument('type')));
|
|
||||||
return self::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! $this->argument('file')) {
|
if (! $this->argument('file')) {
|
||||||
$this->info('Item Name:'.$pkt->name);
|
$this->info('Item Name:'.$pkt->name);
|
||||||
$this->info('Item Type:'.get_class($pkt));
|
$this->info('Item Type:'.get_class($pkt));
|
||||||
|
@ -49,8 +49,8 @@ class MailList extends Command
|
|||||||
return [
|
return [
|
||||||
'id'=>$item->id,
|
'id'=>$item->id,
|
||||||
'msgid'=>$item->msgid,
|
'msgid'=>$item->msgid,
|
||||||
'from'=>sprintf('%s (%s)',$item->from,$item->fftn->ftn3d),
|
'from'=>$item->from,
|
||||||
'to'=>sprintf('%s (%s)',$item->to,$item->tftn->ftn3d),
|
'to'=>$item->to,
|
||||||
'subject'=>$item->subject,
|
'subject'=>$item->subject,
|
||||||
];
|
];
|
||||||
}));
|
}));
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use App\Models\Address;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
|
|
||||||
use App\Jobs\NodesNew as Job;
|
|
||||||
use App\Models\Domain;
|
|
||||||
|
|
||||||
class NodesNew extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'nodes:new'
|
|
||||||
.' {domain : Domain}'
|
|
||||||
.' {--date= : From a specific date (default 1 since last Saturday)}'
|
|
||||||
.' {--netmail= : Send a Netmail to FTN}';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'List new nodes since last Saturday (or a specific date)';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle(): int
|
|
||||||
{
|
|
||||||
$do = Domain::where('name',$this->argument('domain'))->singleOrFail();
|
|
||||||
$ao = NULL;
|
|
||||||
|
|
||||||
if ($this->option('netmail')) {
|
|
||||||
$ao = Address::findFTN($this->option('netmail'));
|
|
||||||
|
|
||||||
if (! $ao) {
|
|
||||||
$this->error('Address not found: '.$this->option('netmail'));
|
|
||||||
return self::FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Job::dispatchSync($do,$this->option('date') ? Carbon::parse($this->option('date')) : Carbon::parse('last saturday'),$ao);
|
|
||||||
}
|
|
||||||
}
|
|
@ -50,7 +50,7 @@ class PacketInfo extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($f as $packet) {
|
foreach ($f as $packet) {
|
||||||
$pkt = Packet::process($packet,$x=$f->itemName(),$f->itemSize(),$a?->system);
|
$pkt = Packet::process($packet,$x=$f->itemName(),$f->itemSize(),$a?->zone->domain);
|
||||||
|
|
||||||
$this->alert(sprintf('File Name: %s',$x));
|
$this->alert(sprintf('File Name: %s',$x));
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ class PacketInfo extends Command
|
|||||||
echo "\n";
|
echo "\n";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->warn(sprintf('- Date : %s (%s)',$msg->date,$msg->date->tz->toOffsetName()));
|
$this->warn(sprintf('- Date : %s (%s)',$msg->datetime,$msg->datetime->tz->toOffsetName()));
|
||||||
$this->warn(sprintf(' - Errors : %s',$msg->errors->count() ? 'YES' : 'No'));
|
$this->warn(sprintf(' - Errors : %s',$msg->errors->count() ? 'YES' : 'No'));
|
||||||
$this->warn(sprintf(' - Flags : %s',$msg->flags()->keys()->join(', ')));
|
$this->warn(sprintf(' - Flags : %s',$msg->flags()->keys()->join(', ')));
|
||||||
$this->warn(sprintf(' - Cost : %d',$msg->cost));
|
$this->warn(sprintf(' - Cost : %d',$msg->cost));
|
||||||
@ -97,7 +97,7 @@ class PacketInfo extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($pkt->errors as $msg) {
|
foreach ($pkt->errors as $msg) {
|
||||||
$this->error(sprintf('- Date: %s',$msg->datetime));
|
$this->error(sprintf('- Date: %s',$msg->date));
|
||||||
$this->error(sprintf(' - FLAGS: %s',$msg->flags()->filter()->keys()->join(', ')));
|
$this->error(sprintf(' - FLAGS: %s',$msg->flags()->filter()->keys()->join(', ')));
|
||||||
$this->error(sprintf(' - From: %s (%s)',$msg->from,$msg->fftn));
|
$this->error(sprintf(' - From: %s (%s)',$msg->from,$msg->fftn));
|
||||||
$this->error(sprintf(' - To: %s (%s)',$msg->to,$msg->tftn));
|
$this->error(sprintf(' - To: %s (%s)',$msg->to,$msg->tftn));
|
||||||
|
@ -78,7 +78,7 @@ class PacketProcess extends Command
|
|||||||
return self::FAILURE;
|
return self::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Job::dispatchSync($rel_name,$ao->system,$this->option('dontqueue'));
|
Job::dispatchSync($rel_name,$ao->zone->domain,$this->option('dontqueue'));
|
||||||
|
|
||||||
return self::SUCCESS;
|
return self::SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\Config;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
use App\Classes\Protocol\{Binkp,DNS,EMSI};
|
use App\Classes\Protocol\{Binkp,DNS,EMSI};
|
||||||
use App\Classes\Sock\Exception\SocketException;
|
use App\Classes\Sock\Exception\SocketException;
|
||||||
use App\Classes\Sock\SocketServer;
|
use App\Classes\Sock\SocketServer;
|
||||||
|
use App\Models\Setup;
|
||||||
|
|
||||||
class ServerStart extends Command
|
class ServerStart extends Command
|
||||||
{
|
{
|
||||||
@ -37,11 +37,7 @@ class ServerStart extends Command
|
|||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
Log::info(sprintf('%s:+ Server Starting (%d)',self::LOGKEY,getmypid()));
|
Log::info(sprintf('%s:+ Server Starting (%d)',self::LOGKEY,getmypid()));
|
||||||
|
$o = Setup::findOrFail(config('app.id'));
|
||||||
if (! our_address()->count())
|
|
||||||
throw new \Exception('We dont have any ACTIVE FTN addresses assigned');
|
|
||||||
|
|
||||||
$o = Config::get('setup');
|
|
||||||
|
|
||||||
$start = collect();
|
$start = collect();
|
||||||
|
|
||||||
@ -50,7 +46,7 @@ class ServerStart extends Command
|
|||||||
'address'=>$o->binkp_bind,
|
'address'=>$o->binkp_bind,
|
||||||
'port'=>$o->binkp_port,
|
'port'=>$o->binkp_port,
|
||||||
'proto'=>SOCK_STREAM,
|
'proto'=>SOCK_STREAM,
|
||||||
'class'=>new Binkp,
|
'class'=>new Binkp($o),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($o->emsi_active)
|
if ($o->emsi_active)
|
||||||
@ -58,7 +54,7 @@ class ServerStart extends Command
|
|||||||
'address'=>$o->emsi_bind,
|
'address'=>$o->emsi_bind,
|
||||||
'port'=>$o->emsi_port,
|
'port'=>$o->emsi_port,
|
||||||
'proto'=>SOCK_STREAM,
|
'proto'=>SOCK_STREAM,
|
||||||
'class'=>new EMSI,
|
'class'=>new EMSI($o),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($o->dns_active)
|
if ($o->dns_active)
|
||||||
@ -66,7 +62,7 @@ class ServerStart extends Command
|
|||||||
'address'=>$o->dns_bind,
|
'address'=>$o->dns_bind,
|
||||||
'port'=>$o->dns_port,
|
'port'=>$o->dns_port,
|
||||||
'proto'=>SOCK_DGRAM,
|
'proto'=>SOCK_DGRAM,
|
||||||
'class'=>new DNS,
|
'class'=>new DNS(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$children = collect();
|
$children = collect();
|
||||||
|
46
app/Console/Kernel.php
Normal file
46
app/Console/Kernel.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console;
|
||||||
|
|
||||||
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
|
||||||
|
use App\Jobs\{AddressIdleDomain,MailSend,SystemHeartbeat};
|
||||||
|
|
||||||
|
class Kernel extends ConsoleKernel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The Artisan commands provided by your application.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $commands = [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the application's command schedule.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function schedule(Schedule $schedule)
|
||||||
|
{
|
||||||
|
$schedule->job(new MailSend(TRUE))->everyMinute()->withoutOverlapping();
|
||||||
|
$schedule->job(new MailSend(FALSE))->twiceDaily(1,13);
|
||||||
|
$schedule->job(new SystemHeartbeat)->hourly();
|
||||||
|
$schedule->job(new AddressIdleDomain)->weeklyOn(0,'01:00');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the commands for the application.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function commands()
|
||||||
|
{
|
||||||
|
$this->load(__DIR__.'/Commands');
|
||||||
|
|
||||||
|
require base_path('routes/console.php');
|
||||||
|
}
|
||||||
|
}
|
@ -42,13 +42,13 @@ abstract class Base
|
|||||||
|
|
||||||
case 'room':
|
case 'room':
|
||||||
$room_alias = Http::withToken(config('matrix.as_token'))
|
$room_alias = Http::withToken(config('matrix.as_token'))
|
||||||
->get(sprintf('%s/_matrix/client/v3/rooms/%s/state/m.room.canonical_alias',config('matrix.server'),$this->room_id));
|
->get(sprintf('https://%s/_matrix/client/v3/rooms/%s/state/m.room.canonical_alias',config('matrix.server'),$this->room_id));
|
||||||
|
|
||||||
return $room_alias->json('alias',$this->room_id);
|
return $room_alias->json('alias',$this->room_id);
|
||||||
|
|
||||||
case 'topic':
|
case 'topic':
|
||||||
$subject = Http::withToken(config('matrix.as_token'))
|
$subject = Http::withToken(config('matrix.as_token'))
|
||||||
->get(sprintf('%s/_matrix/client/v3/rooms/%s/state/m.room.topic',config('matrix.server'),$this->room_id));
|
->get(sprintf('https://%s/_matrix/client/v3/rooms/%s/state/m.room.topic',config('matrix.server'),$this->room_id));
|
||||||
|
|
||||||
return $subject->json('topic','Message from Matrix');
|
return $subject->json('topic','Message from Matrix');
|
||||||
|
|
||||||
|
40
app/Exceptions/Handler.php
Normal file
40
app/Exceptions/Handler.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class Handler extends ExceptionHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A list of the exception types that are not reported.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $dontReport = [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of the inputs that are never flashed for validation exceptions.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $dontFlash = [
|
||||||
|
'password',
|
||||||
|
'password_confirmation',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the exception handling callbacks for the application.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
$this->reportable(function (Throwable $e) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,213 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Helpers;
|
|
||||||
|
|
||||||
use Illuminate\Support\Arr;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Useful tools (js/css) used when rendering pages
|
|
||||||
*/
|
|
||||||
class PageAssets
|
|
||||||
{
|
|
||||||
// Types that we can handle
|
|
||||||
private const array types = [
|
|
||||||
'css',
|
|
||||||
'js',
|
|
||||||
];
|
|
||||||
|
|
||||||
public const array assets = [
|
|
||||||
'datatables' => [
|
|
||||||
'base' => [
|
|
||||||
'css' => [
|
|
||||||
'//cdn.datatables.net/2.1.2/css/dataTables.bootstrap4.css',
|
|
||||||
//'//cdn.datatables.net/2.1.2/css/dataTables.dataTables.min.css',
|
|
||||||
],
|
|
||||||
'js' => [
|
|
||||||
'//cdn.datatables.net/2.1.2/js/dataTables.min.js',
|
|
||||||
'//cdn.datatables.net/2.1.2/js/dataTables.bootstrap4.min.js',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'buttons' => [
|
|
||||||
'css' => [
|
|
||||||
'//cdn.datatables.net/buttons/3.1.0/css/buttons.bootstrap4.min.css',
|
|
||||||
//'//cdn.datatables.net/buttons/3.1.0/css/buttons.dataTables.min.css',
|
|
||||||
],
|
|
||||||
'js' => [
|
|
||||||
'//cdn.datatables.net/buttons/3.1.0/js/dataTables.buttons.min.js',
|
|
||||||
//'//cdn.datatables.net/buttons/3.1.0/js/buttons.dataTables.min.js',
|
|
||||||
'//cdn.datatables.net/buttons/3.1.0/js/buttons.bootstrap4.min.js',
|
|
||||||
'//cdnjs.cloudflare.com/ajax/libs/jszip/3.2.0/jszip.min.js',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'conditionalpaging' => [
|
|
||||||
'js' => [
|
|
||||||
'//cdn.datatables.net/plug-ins/2.0.5/features/conditionalPaging/dataTables.conditionalPaging.min.js',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'fixedheader' => [
|
|
||||||
'css' => [
|
|
||||||
'//cdn.datatables.net/fixedheader/4.0.1/css/fixedHeader.bootstrap4.min.css',
|
|
||||||
//'//cdn.datatables.net/fixedheader/4.0.1/css/fixedHeader.dataTables.min.css',
|
|
||||||
],
|
|
||||||
'js' => [
|
|
||||||
'//cdn.datatables.net/fixedheader/4.0.1/js/dataTables.fixedHeader.min.js',
|
|
||||||
//'//cdn.datatables.net/fixedheader/4.0.1/js/fixedHeader.dataTables.min.js',
|
|
||||||
'//cdn.datatables.net/fixedheader/4.0.1/js/fixedHeader.bootstrap4.min.js',
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'responsive' => [
|
|
||||||
'css' => [
|
|
||||||
'//cdn.datatables.net/responsive/3.0.2/css/responsive.bootstrap4.min.css',
|
|
||||||
//'//cdn.datatables.net/responsive/3.0.2/css/responsive.dataTables.min.css',
|
|
||||||
],
|
|
||||||
'js' => [
|
|
||||||
'//cdn.datatables.net/responsive/3.0.2/js/dataTables.responsive.min.js',
|
|
||||||
//'//cdn.datatables.net/responsive/3.0.2/js/responsive.bootstrap.min.js',
|
|
||||||
'//cdn.datatables.net/responsive/3.0.2/js/responsive.bootstrap4.min.js',
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'rowgroup' => [
|
|
||||||
'css' => [
|
|
||||||
'//cdn.datatables.net/rowgroup/1.5.0/css/rowGroup.bootstrap4.min.css',
|
|
||||||
//'//cdn.datatables.net/rowgroup/1.5.0/css/rowGroup.dataTables.min.css',
|
|
||||||
],
|
|
||||||
'js' => [
|
|
||||||
'//cdn.datatables.net/rowgroup/1.5.0/js/dataTables.rowGroup.min.js',
|
|
||||||
//'//cdn.datatables.net/rowgroup/1.5.0/js/rowGroup.dataTables.min.js',
|
|
||||||
'//cdn.datatables.net/rowgroup/1.5.0/js/rowGroup.bootstrap4.min.js',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'searchpanes' => [
|
|
||||||
'css' => [
|
|
||||||
'//cdn.datatables.net/searchpanes/2.3.1/css/searchPanes.bootstrap4.min.css',
|
|
||||||
//'//cdn.datatables.net/searchpanes/2.3.1/css/searchPanes.dataTables.min.css',
|
|
||||||
],
|
|
||||||
'js' => [
|
|
||||||
'//cdn.datatables.net/searchpanes/2.3.1/js/dataTables.searchPanes.min.js',
|
|
||||||
//'//cdn.datatables.net/searchpanes/2.3.1/js/searchPanes.dataTables.min.js',
|
|
||||||
'//cdn.datatables.net/searchpanes/2.3.1/js/searchPanes.bootstrap4.min.js',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'searchpanes-left' => [
|
|
||||||
'css' => [
|
|
||||||
'/plugin/dataTables/leftSearchPanes.css',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'select' => [
|
|
||||||
'css' => [
|
|
||||||
'//cdn.datatables.net/select/2.0.3/css/select.bootstrap4.min.css',
|
|
||||||
//'//cdn.datatables.net/select/2.0.3/css/select.dataTables.min.css',
|
|
||||||
],
|
|
||||||
'js' => [
|
|
||||||
'//cdn.datatables.net/select/2.0.3/js/dataTables.select.min.js',
|
|
||||||
//'//cdn.datatables.net/select/2.0.3/js/select.dataTables.min.js',
|
|
||||||
'//cdn.datatables.net/select/2.0.3/js/select.bootstrap4.min.js',
|
|
||||||
]
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'select2' => [
|
|
||||||
'base' => [
|
|
||||||
'css' => [
|
|
||||||
'//cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css',
|
|
||||||
],
|
|
||||||
'js' => [
|
|
||||||
'//cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'autofocus' => [
|
|
||||||
'js' => [
|
|
||||||
'/plugin/select2/fix-autofocus.js',
|
|
||||||
],
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'simplemde' => [
|
|
||||||
'base' => [
|
|
||||||
'css' => [
|
|
||||||
'//cdn.jsdelivr.net/simplemde/latest/simplemde.min.css',
|
|
||||||
],
|
|
||||||
'js' => [
|
|
||||||
'//cdn.jsdelivr.net/simplemde/latest/simplemde.min.js',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
// Items to manage
|
|
||||||
public static Collection $items;
|
|
||||||
|
|
||||||
// Add an item to the list
|
|
||||||
public static function add(string $type,Collection|array|string $asset): void
|
|
||||||
{
|
|
||||||
if (! in_array($type,self::types))
|
|
||||||
throw new \Exception('Invalid type: '.$type);
|
|
||||||
|
|
||||||
if (! isset(self::$items))
|
|
||||||
self::init();
|
|
||||||
|
|
||||||
if (is_string($asset))
|
|
||||||
self::$items
|
|
||||||
->get($type)
|
|
||||||
->push($asset)
|
|
||||||
->unique();
|
|
||||||
else
|
|
||||||
self::$items->put($type,
|
|
||||||
self::$items
|
|
||||||
->get($type)
|
|
||||||
->merge($asset->values())
|
|
||||||
->unique());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a predefined asset
|
|
||||||
public static function asset(string $id): void
|
|
||||||
{
|
|
||||||
if (! isset(self::$items))
|
|
||||||
self::init();
|
|
||||||
|
|
||||||
if (str_contains($id,',')) {
|
|
||||||
[$item,$arguments] = explode(',',$id,2);
|
|
||||||
$arguments = collect(explode('|',$arguments));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$item = $id;
|
|
||||||
$arguments = collect();
|
|
||||||
}
|
|
||||||
|
|
||||||
$arguments = $arguments->prepend('base');
|
|
||||||
$asset = collect(Arr::get(self::assets,$item))->only($arguments);
|
|
||||||
|
|
||||||
foreach (self::types as $type)
|
|
||||||
if ($x=$asset->pluck($type)->filter()->flatten())
|
|
||||||
self::add($type,$x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render the CSS items
|
|
||||||
public static function css(): string
|
|
||||||
{
|
|
||||||
return isset(self::$items)
|
|
||||||
? self::$items
|
|
||||||
->get('css')
|
|
||||||
->map(fn($item)=>sprintf('<link rel="stylesheet" href="%s">',$item))
|
|
||||||
->join('')
|
|
||||||
: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function init(): void
|
|
||||||
{
|
|
||||||
self::$items = collect([
|
|
||||||
'js' => collect(),
|
|
||||||
'css' => collect(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render the JS items
|
|
||||||
public static function js(): string
|
|
||||||
{
|
|
||||||
return isset(self::$items)
|
|
||||||
? self::$items
|
|
||||||
->get('js')
|
|
||||||
->map(fn($item)=>sprintf('<script type="text/javascript" src="%s"></script>',$item))
|
|
||||||
->join('')
|
|
||||||
: '';
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Providers\RouteServiceProvider;
|
||||||
use Illuminate\Foundation\Auth\ConfirmsPasswords;
|
use Illuminate\Foundation\Auth\ConfirmsPasswords;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
class ConfirmPasswordController extends Controller
|
class ConfirmPasswordController extends Controller
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -25,7 +26,7 @@ class ConfirmPasswordController extends Controller
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = '/';
|
protected $redirectTo = RouteServiceProvider::HOME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new controller instance.
|
* Create a new controller instance.
|
||||||
|
@ -2,12 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Password;
|
use Illuminate\Support\Facades\Password;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
|
|
||||||
class ForgotPasswordController extends Controller
|
class ForgotPasswordController extends Controller
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
|||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Providers\RouteServiceProvider;
|
||||||
|
|
||||||
class LoginController extends Controller
|
class LoginController extends Controller
|
||||||
{
|
{
|
||||||
@ -29,7 +30,7 @@ class LoginController extends Controller
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = '/';
|
protected $redirectTo = RouteServiceProvider::HOME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new controller instance.
|
* Create a new controller instance.
|
||||||
@ -38,8 +39,8 @@ class LoginController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->middleware('guest')->except('logout');
|
$this->middleware('guest')
|
||||||
$this->middleware('auth')->only('logout');
|
->except('logout');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login(Request $request)
|
public function login(Request $request)
|
||||||
@ -55,7 +56,6 @@ class LoginController extends Controller
|
|||||||
return $this->sendFailedLoginResponse($request);
|
return $this->sendFailedLoginResponse($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record our last logged in time
|
|
||||||
protected function authenticated(Request $request, $user)
|
protected function authenticated(Request $request, $user)
|
||||||
{
|
{
|
||||||
$user->last_on = Carbon::now();
|
$user->last_on = Carbon::now();
|
||||||
|
@ -7,6 +7,7 @@ use Illuminate\Support\Facades\Hash;
|
|||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Providers\RouteServiceProvider;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
|
||||||
class RegisterController extends Controller
|
class RegisterController extends Controller
|
||||||
@ -29,7 +30,7 @@ class RegisterController extends Controller
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = '/';
|
protected $redirectTo = RouteServiceProvider::HOME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new controller instance.
|
* Create a new controller instance.
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Providers\RouteServiceProvider;
|
||||||
|
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||||
|
|
||||||
class ResetPasswordController extends Controller
|
class ResetPasswordController extends Controller
|
||||||
{
|
{
|
||||||
@ -26,5 +26,15 @@ class ResetPasswordController extends Controller
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = '/';
|
protected $redirectTo = RouteServiceProvider::HOME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new controller instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('guest');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
use Illuminate\Foundation\Auth\VerifiesEmails;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Providers\RouteServiceProvider;
|
||||||
|
use Illuminate\Foundation\Auth\VerifiesEmails;
|
||||||
|
|
||||||
class VerificationController extends Controller
|
class VerificationController extends Controller
|
||||||
{
|
{
|
||||||
@ -26,7 +26,7 @@ class VerificationController extends Controller
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = '/';
|
protected $redirectTo = RouteServiceProvider::HOME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new controller instance.
|
* Create a new controller instance.
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
|
|
||||||
abstract class Controller extends \Illuminate\Routing\Controller
|
class Controller extends BaseController
|
||||||
{
|
{
|
||||||
use AuthorizesRequests,ValidatesRequests;
|
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||||
}
|
}
|
@ -18,7 +18,7 @@ class EchoareaController extends Controller
|
|||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'domain_id' => 'required|exists:domains,id',
|
'domain_id' => 'required|exists:domains,id',
|
||||||
'name' => 'required|min:4|max:35|regex:/^[a-zA-Z0-9\-_~.]{4,}$/|unique:echoareas,name,'.($o->exists ? $o->id : 0),
|
'name' => 'required|min:4|max:35|regex:/^[a-zA-Z0-9\-_~]{4,}$/|unique:echoareas,name,'.($o->exists ? $o->id : 0),
|
||||||
'description' => 'required',
|
'description' => 'required',
|
||||||
'active' => 'required|boolean',
|
'active' => 'required|boolean',
|
||||||
'show' => 'required|boolean',
|
'show' => 'required|boolean',
|
||||||
|
@ -10,7 +10,7 @@ use Illuminate\Support\Facades\DB;
|
|||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
|
||||||
use App\Classes\File;
|
use App\Classes\File;
|
||||||
use App\Classes\FTN\{Message,Packet};
|
use App\Classes\FTN\Packet;
|
||||||
use App\Http\Requests\SetupRequest;
|
use App\Http\Requests\SetupRequest;
|
||||||
use App\Models\File as FileModel;
|
use App\Models\File as FileModel;
|
||||||
use App\Models\{Address,Echomail,Netmail,Setup,System};
|
use App\Models\{Address,Echomail,Netmail,Setup,System};
|
||||||
@ -169,7 +169,7 @@ class HomeController extends Controller
|
|||||||
->orWhere('replyid','like','%'.$request->query('term').'%')
|
->orWhere('replyid','like','%'.$request->query('term').'%')
|
||||||
->get() as $o)
|
->get() as $o)
|
||||||
{
|
{
|
||||||
$result->push(['id'=>$o->id,'name'=>sprintf('%s (%s)',Message::tr($o->from),$o->fftn->ftn3d),'value'=>url('echomail/view',[$o->id]),'category'=>'Echomail']);
|
$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
|
// Look for Netmail
|
||||||
|
@ -36,7 +36,7 @@ class SystemController extends Controller
|
|||||||
|
|
||||||
// Sometimes items
|
// Sometimes items
|
||||||
foreach (['sysop','hold','notes','zt_id','heartbeat'] as $key)
|
foreach (['sysop','hold','notes','zt_id','heartbeat'] as $key)
|
||||||
if ($request->has($key))
|
if ($request->validated($key))
|
||||||
$o->{$key} = $request->validated($key);
|
$o->{$key} = $request->validated($key);
|
||||||
|
|
||||||
switch ($request->validated('pollmode')) {
|
switch ($request->validated('pollmode')) {
|
||||||
@ -66,17 +66,7 @@ class SystemController extends Controller
|
|||||||
->with('saved',TRUE);
|
->with('saved',TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
$o->loadMissing([
|
$o->load(['addresses.zone.domain','addresses.nodes_hub','addresses.system','sessions.domain','sessions.systems']);
|
||||||
'zcs',
|
|
||||||
// For 'ftn' to work
|
|
||||||
'addresses.zone:id,zone_id,domain_id,active',
|
|
||||||
'addresses.zone.domain:id,name,active',
|
|
||||||
// For 'role'
|
|
||||||
'addresses.system:id,address',
|
|
||||||
// For system addedit
|
|
||||||
'sessions.domain:id,name,active',
|
|
||||||
'sessions.systems:id',
|
|
||||||
]);
|
|
||||||
|
|
||||||
return view('system.addedit')
|
return view('system.addedit')
|
||||||
->with('action',$o->exists ? 'update_nn' : 'create')
|
->with('action',$o->exists ? 'update_nn' : 'create')
|
||||||
@ -498,17 +488,11 @@ class SystemController extends Controller
|
|||||||
public function api_autohold_toggle(Request $request,string $state): array
|
public function api_autohold_toggle(Request $request,string $state): array
|
||||||
{
|
{
|
||||||
$o = System::findOrFail($request->id);
|
$o = System::findOrFail($request->id);
|
||||||
|
$o->autohold = $state === 'off' ? FALSE : TRUE;
|
||||||
if ($request->user()->can('update_nn',$o)) {
|
|
||||||
$o->autohold = !($state === 'off');
|
|
||||||
$o->save();
|
$o->save();
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- Autohold set to [%s]',self::LOGKEY,$o->autohold ? 'ON' : 'OFF'));
|
Log::debug(sprintf('%s:- Autohold set to [%s]',self::LOGKEY,$o->autohold ? 'ON' : 'OFF'));
|
||||||
|
|
||||||
} else {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['autohold'=>$o->autohold];
|
return ['autohold'=>$o->autohold];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,12 +605,31 @@ class SystemController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function register(SystemRegisterRequest $request)
|
public function register(SystemRegisterRequest $request)
|
||||||
{
|
{
|
||||||
|
// Step 1, show the user a form to select an existing defined system
|
||||||
|
if ($request->isMethod('GET'))
|
||||||
|
return view('user.system.register');
|
||||||
|
|
||||||
if ($request->action === 'register' && $request->name && is_numeric($request->name))
|
if ($request->action === 'register' && $request->name && is_numeric($request->name))
|
||||||
return view('user.system.widget.register_confirm')
|
return view('user.system.widget.register_confirm')
|
||||||
->with('o',System::findOrFail($request->name));
|
->with('o',System::findOrFail($request->name));
|
||||||
|
|
||||||
$o = System::findOrNew(is_numeric($request->system_id) ? $request->system_id : NULL);
|
$o = System::findOrNew(is_numeric($request->system_id) ? $request->system_id : NULL);
|
||||||
|
|
||||||
|
// If the system exists, and we are 'register', we'll start the address claim process
|
||||||
|
if ($o->exists && $request->action === 'Link') {
|
||||||
|
$validate = Setup::findOrFail(config('app.id'))->system->inMyZones($o->addresses);
|
||||||
|
|
||||||
|
// If we have addresses, we'll trigger the routed netmail
|
||||||
|
if ($validate->count()) {
|
||||||
|
Notification::route('netmail',$x=$validate->first())->notify(new AddressLink(Auth::user()));
|
||||||
|
AddressPoll::dispatch($x)->delay(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('user.system.widget.register_send')
|
||||||
|
->with('validate',$validate)
|
||||||
|
->with('o',$o);
|
||||||
|
}
|
||||||
|
|
||||||
// If the system doesnt exist, we'll create it
|
// If the system doesnt exist, we'll create it
|
||||||
if (! $o->exist) {
|
if (! $o->exist) {
|
||||||
$o->sysop = Auth::user()->name;
|
$o->sysop = Auth::user()->name;
|
||||||
|
83
app/Http/Kernel.php
Normal file
83
app/Http/Kernel.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||||
|
|
||||||
|
class Kernel extends HttpKernel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The application's global HTTP middleware stack.
|
||||||
|
*
|
||||||
|
* These middleware are run during every request to your application.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $middleware = [
|
||||||
|
\App\Http\Middleware\CheckForMaintenanceMode::class,
|
||||||
|
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||||
|
\App\Http\Middleware\TrimStrings::class,
|
||||||
|
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||||
|
\App\Http\Middleware\TrustProxies::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application's route middleware groups.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $middlewareGroups = [
|
||||||
|
'web' => [
|
||||||
|
\App\Http\Middleware\EncryptCookies::class,
|
||||||
|
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||||
|
\Illuminate\Session\Middleware\StartSession::class,
|
||||||
|
// \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||||
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
|
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
\App\Http\Middleware\AddUserToView::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
'api' => [
|
||||||
|
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||||
|
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
||||||
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application's route middleware.
|
||||||
|
*
|
||||||
|
* These middleware may be assigned to groups or used individually.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $routeMiddleware = [
|
||||||
|
'activeuser' => \App\Http\Middleware\ActiveUser::class,
|
||||||
|
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||||
|
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||||
|
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||||
|
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||||
|
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||||
|
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||||
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
|
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The priority-sorted list of middleware.
|
||||||
|
*
|
||||||
|
* This forces the listed middleware to always be in the given order.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $middlewarePriority = [
|
||||||
|
\Illuminate\Session\Middleware\StartSession::class,
|
||||||
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
|
\App\Http\Middleware\Authenticate::class,
|
||||||
|
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||||
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
\Illuminate\Auth\Middleware\Authorize::class,
|
||||||
|
];
|
||||||
|
}
|
@ -5,7 +5,6 @@ namespace App\Http\Middleware;
|
|||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Facades\Config;
|
|
||||||
|
|
||||||
use App\Models\Setup;
|
use App\Models\Setup;
|
||||||
|
|
||||||
@ -46,10 +45,8 @@ class AddUserToView
|
|||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
Config::set('setup',$x=Setup::find(config('app.id'))->load('system'));
|
|
||||||
|
|
||||||
$this->factory->share('user',$this->user);
|
$this->factory->share('user',$this->user);
|
||||||
$this->factory->share('setup',$x);
|
$this->factory->share('setup',Setup::find(config('app.id')));
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
21
app/Http/Middleware/Authenticate.php
Normal file
21
app/Http/Middleware/Authenticate.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
||||||
|
|
||||||
|
class Authenticate extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the path the user should be redirected to when they are not authenticated.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function redirectTo($request)
|
||||||
|
{
|
||||||
|
if (! $request->expectsJson()) {
|
||||||
|
return route('login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
app/Http/Middleware/CheckForMaintenanceMode.php
Normal file
17
app/Http/Middleware/CheckForMaintenanceMode.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
|
||||||
|
|
||||||
|
class CheckForMaintenanceMode extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The URIs that should be reachable while maintenance mode is enabled.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
17
app/Http/Middleware/EncryptCookies.php
Normal file
17
app/Http/Middleware/EncryptCookies.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
|
||||||
|
|
||||||
|
class EncryptCookies extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The names of the cookies that should not be encrypted.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
28
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
28
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
use App\Providers\RouteServiceProvider;
|
||||||
|
|
||||||
|
class RedirectIfAuthenticated
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @param string|null $guard
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle(Request $request,\Closure $next,?string $guard=NULL)
|
||||||
|
{
|
||||||
|
if (Auth::guard($guard)->check()) {
|
||||||
|
return redirect(RouteServiceProvider::HOME);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
18
app/Http/Middleware/TrimStrings.php
Normal file
18
app/Http/Middleware/TrimStrings.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
|
||||||
|
|
||||||
|
class TrimStrings extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The names of the attributes that should not be trimmed.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
'password',
|
||||||
|
'password_confirmation',
|
||||||
|
];
|
||||||
|
}
|
28
app/Http/Middleware/TrustProxies.php
Normal file
28
app/Http/Middleware/TrustProxies.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||||
|
|
||||||
|
class TrustProxies extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The trusted proxies for this application.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $proxies;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers that should be used to detect proxies.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $headers =
|
||||||
|
Request::HEADER_X_FORWARDED_FOR |
|
||||||
|
Request::HEADER_X_FORWARDED_HOST |
|
||||||
|
Request::HEADER_X_FORWARDED_PORT |
|
||||||
|
Request::HEADER_X_FORWARDED_PROTO |
|
||||||
|
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||||
|
}
|
24
app/Http/Middleware/VerifyCsrfToken.php
Normal file
24
app/Http/Middleware/VerifyCsrfToken.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
|
||||||
|
|
||||||
|
class VerifyCsrfToken extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $addHttpCookie = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URIs that should be excluded from CSRF verification.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
@ -36,7 +36,7 @@ class AddressMerge extends FormRequest
|
|||||||
$src = Address::withTrashed()->findOrFail($request->src);
|
$src = Address::withTrashed()->findOrFail($request->src);
|
||||||
|
|
||||||
if ((! $dst->active) && ($dst->system_id !== $src->system_id) && ($src->system->name !== System::default))
|
if ((! $dst->active) && ($dst->system_id !== $src->system_id) && ($src->system->name !== System::default))
|
||||||
$fail('Destination must be active, or be from the same system');
|
$fail('Destination must be active, or be from the system system');
|
||||||
},
|
},
|
||||||
function ($attribute,$value,$fail) use ($request) {
|
function ($attribute,$value,$fail) use ($request) {
|
||||||
$dst = Address::withTrashed()->findOrFail($value);
|
$dst = Address::withTrashed()->findOrFail($value);
|
||||||
|
@ -23,21 +23,14 @@ class SystemRegisterRequest extends FormRequest
|
|||||||
|
|
||||||
// @todo Also disallow claiming this hosts system
|
// @todo Also disallow claiming this hosts system
|
||||||
|
|
||||||
return Gate::allows(
|
return Gate::allows($this->route('o')->users->count() ? 'update_nn' : 'register',$this->route('o'));
|
||||||
$this->route('o')->users->count()
|
|
||||||
? 'update_nn'
|
|
||||||
: 'register',
|
|
||||||
$this->route('o')
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function messages(): array
|
public function messages(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'heartbeat' => 'Sorry, only an admin can set this below 12',
|
|
||||||
'hold' => 'Must be Yes or No',
|
'hold' => 'Must be Yes or No',
|
||||||
'pollmode' => 'Must be Hold, Normal or Crash',
|
'pollmode' => 'Must be Hold, Normal or Crash',
|
||||||
'pkt_msgs' => 'Sorry, only an admin can increase this above 100',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,26 +69,8 @@ class SystemRegisterRequest extends FormRequest
|
|||||||
'active' => 'required|boolean',
|
'active' => 'required|boolean',
|
||||||
'hold' => 'sometimes|boolean',
|
'hold' => 'sometimes|boolean',
|
||||||
'pollmode' => 'required|integer|min:0|max:2',
|
'pollmode' => 'required|integer|min:0|max:2',
|
||||||
'heartbeat' => [
|
'heartbeat' => 'nullable|integer|min:0|max:48',
|
||||||
'nullable',
|
'pkt_msgs' => 'nullable|integer|min:5',
|
||||||
'integer',
|
|
||||||
function ($attribute,$value,$fail) {
|
|
||||||
if (($value < 12) && (! Gate::allows('admin')))
|
|
||||||
$fail(true);
|
|
||||||
},
|
|
||||||
'min:0',
|
|
||||||
'max:48'
|
|
||||||
],
|
|
||||||
'pkt_msgs' => [
|
|
||||||
'nullable',
|
|
||||||
'integer',
|
|
||||||
function ($attribute,$value,$fail) {
|
|
||||||
if (($value > 100) && (! Gate::allows('admin')))
|
|
||||||
$fail(true);
|
|
||||||
},
|
|
||||||
'min:5',
|
|
||||||
'max:65535',
|
|
||||||
],
|
|
||||||
] : []));
|
] : []));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,67 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
|
||||||
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,Domain,System};
|
|
||||||
use App\Notifications\Echomails\AbsentNodes;
|
|
||||||
use App\Notifications\Emails\NodeMarkedDown as NodeMarkedDownEmail;
|
|
||||||
use App\Notifications\Netmails\NodeMarkedDown as NodeMarkedDownNetmail;
|
|
||||||
use App\Notifications\Emails\NodeMarkedHold as NodeMarkedHoldEmail;
|
|
||||||
use App\Notifications\Netmails\NodeMarkedHold as NodeMarkedHoldNetmail;
|
|
||||||
use App\Notifications\Emails\NodeDelisted as NodeDelistedEmail;
|
|
||||||
use App\Notifications\Netmails\NodeDelisted as NodeDelistedNetmail;
|
|
||||||
|
|
||||||
class AddressClearQueue implements ShouldQueue
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
||||||
|
|
||||||
private const LOGKEY = 'JAC';
|
|
||||||
|
|
||||||
private Address $ao; // System address
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new job instance.
|
|
||||||
*/
|
|
||||||
public function __construct(Address $ao)
|
|
||||||
{
|
|
||||||
$this->ao = $ao->withoutRelations();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the job.
|
|
||||||
*/
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
// Remove echomail not collected from echomail_seenby
|
|
||||||
DB::table('echomail_seenby')
|
|
||||||
->where('address_id',$this->ao->id)
|
|
||||||
->whereNotNull('export_at')
|
|
||||||
->whereNull('sent_at')
|
|
||||||
->delete();
|
|
||||||
|
|
||||||
// Remove FLAG_INTRANSIT from netmail that hasnt been delivered
|
|
||||||
DB::table('netmails')
|
|
||||||
->where('tftn_id',$this->ao->id)
|
|
||||||
->whereRaw(sprintf('(flags & %d) > 0',Message::FLAG_INTRANSIT))
|
|
||||||
->update(['flags'=>DB::raw(sprintf('(flags & ~%d)',Message::FLAG_INTRANSIT))]);
|
|
||||||
|
|
||||||
// Remove files not collected
|
|
||||||
DB::table('file_seenby')
|
|
||||||
->where('address_id',$this->ao->id)
|
|
||||||
->whereNotNull('export_at')
|
|
||||||
->whereNull('sent_at')
|
|
||||||
->delete();
|
|
||||||
}
|
|
||||||
}
|
|
@ -37,8 +37,8 @@ class AddressIdle implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function __construct(Domain $do,Address $ao=NULL)
|
public function __construct(Domain $do,Address $ao=NULL)
|
||||||
{
|
{
|
||||||
$this->do = $do->withoutRelations();
|
$this->do = $do;
|
||||||
$this->ao = $ao?->withoutRelations();
|
$this->ao = $ao;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,24 +49,35 @@ class AddressIdle implements ShouldQueue
|
|||||||
$result = collect();
|
$result = collect();
|
||||||
|
|
||||||
// Delist DOWN nodes
|
// Delist DOWN nodes
|
||||||
if (config('fido.idle.delist')) {
|
|
||||||
$age = Carbon::now()->subDays(config('fido.idle.delist'));
|
|
||||||
|
|
||||||
foreach ($this->old($this->do,config('fido.idle.delist'),Address::NODE_DOWN,$this->ao) as $ao) {
|
foreach ($this->old($this->do,config('fido.idle.delist'),Address::NODE_DOWN,$this->ao) as $ao) {
|
||||||
Log::debug(sprintf('%s:- Evaluating DOWN node [%s], not seen for at least [%d] days, last update [%d] days',self::LOGKEY,$ao->ftn,$ao->system->last_seen?->diffInDays(),$ao->updated_at->diffInDays()));
|
|
||||||
|
|
||||||
// Only delist system that has been marked down
|
// Only delist system that has been marked down
|
||||||
// Only delist them if its been 14 days since they were marked DOWN
|
// Only mark delist them if its been 7 days since they were marked DOWN
|
||||||
if ((! $ao->is_down) || ($ao->updated_at->greaterThan(Carbon::now()->subWeeks(2))))
|
if ((! $ao->is_down) || ($ao->updated_at->isPast(Carbon::now()->subWeek())))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Validate that the last seen was infact that long ago
|
Log::info(sprintf('%s:- Delisting [%s], not seen for [%d] days',self::LOGKEY,$ao->ftn,config('fido.idle.delist')));
|
||||||
if ($ao->system->last_seen && $ao->system->last_seen->greaterThan($age))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Log::info(sprintf('%s:- Delisting [%s], not seen for at least [%d] days',self::LOGKEY,$ao->ftn,$ao->system->last_seen?->diffInDays()));
|
|
||||||
$contact = FALSE;
|
$contact = FALSE;
|
||||||
|
|
||||||
|
// Remove echomail not collected from echomail_seenby
|
||||||
|
DB::table('echomail_seenby')
|
||||||
|
->where('address_id',$ao->id)
|
||||||
|
->whereNotNull('export_at')
|
||||||
|
->whereNull('sent_at')
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
// Remove FLAG_INTRANSIT from netmail that hasnt been delivered
|
||||||
|
DB::table('netmails')
|
||||||
|
->where('tftn_id',$ao->id)
|
||||||
|
->whereRaw(sprintf('(flags & %d) > 0',Message::FLAG_INTRANSIT))
|
||||||
|
->update(['flags'=>DB::raw(sprintf('(flags & ~%d)',Message::FLAG_INTRANSIT))]);
|
||||||
|
|
||||||
|
// Remove files not collected
|
||||||
|
DB::table('file_seenby')
|
||||||
|
->where('address_id',$ao->id)
|
||||||
|
->whereNotNull('export_at')
|
||||||
|
->whereNull('sent_at')
|
||||||
|
->delete();
|
||||||
|
|
||||||
// Remove subscribed echoareas
|
// Remove subscribed echoareas
|
||||||
$ao->echoareas()->detach();
|
$ao->echoareas()->detach();
|
||||||
|
|
||||||
@ -77,9 +88,6 @@ class AddressIdle implements ShouldQueue
|
|||||||
$ao->validated = FALSE;
|
$ao->validated = FALSE;
|
||||||
$ao->save();
|
$ao->save();
|
||||||
|
|
||||||
// Clear the queue
|
|
||||||
AddressClearQueue::dispatchSync($ao);
|
|
||||||
|
|
||||||
// Email Alert
|
// Email Alert
|
||||||
if ($ao->system->users->count()) {
|
if ($ao->system->users->count()) {
|
||||||
Notification::send($ao->system->users,new NodeDelistedEmail($ao->withoutRelations()));
|
Notification::send($ao->system->users,new NodeDelistedEmail($ao->withoutRelations()));
|
||||||
@ -87,33 +95,18 @@ class AddressIdle implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Netmail Alert (to othernet network address)
|
// Netmail Alert (to othernet network address)
|
||||||
if ($ao->system->aka_unknown()->count()) {
|
if ($ao->system->uncommon()->count()) {
|
||||||
Notification::route('netmail',$ao->system->aka_unknown()->first()->withoutRelations())->notify(new NodeDelistedNetmail($ao->withoutRelations()));
|
Notification::route('netmail',$ao->system->uncommon()->first()->withoutRelations())->notify(new NodeDelistedNetmail($ao->withoutRelations()));
|
||||||
$contact = TRUE;
|
$contact = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$ao->contacted = $contact;
|
$ao->contacted = (! $contact);
|
||||||
$result->push($ao);
|
$result->push($ao);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Mark nodes DOWN
|
// Mark nodes DOWN
|
||||||
if (config('fido.idle.down')) {
|
|
||||||
$age = Carbon::now()->subDays(config('fido.idle.down'));
|
|
||||||
|
|
||||||
foreach ($this->old($this->do,config('fido.idle.down'),Address::NODE_HOLD,$this->ao) as $ao) {
|
foreach ($this->old($this->do,config('fido.idle.down'),Address::NODE_HOLD,$this->ao) as $ao) {
|
||||||
Log::debug(sprintf('%s:- Evaluating HOLD node [%s], not seen for at least [%d] days, last update [%d] days',self::LOGKEY,$ao->ftn,$ao->system->last_seen?->diffInDays(),$ao->updated_at->diffInDays()));
|
Log::info(sprintf('%s:- Marking [%s] as DOWN, not seen for [%d] days',self::LOGKEY,$ao->ftn,config('fido.idle.down')));
|
||||||
|
|
||||||
// Only mark down system that has been marked down
|
|
||||||
// Only mark down them if its been 14 days since they were marked HOLD
|
|
||||||
if ((! $ao->is_hold) || ($ao->updated_at->greaterThan(Carbon::now()->subWeeks(2))))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Validate that the last seen was infact that long ago
|
|
||||||
if ($ao->system->last_seen && $ao->system->last_seen->greaterThan($age))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Log::info(sprintf('%s:- Marking [%s] as DOWN, not seen for at least [%d] days',self::LOGKEY,$ao->ftn,$ao->system->last_seen?->diffInDays()));
|
|
||||||
$contact = FALSE;
|
$contact = FALSE;
|
||||||
|
|
||||||
// Email Alert
|
// Email Alert
|
||||||
@ -123,8 +116,8 @@ class AddressIdle implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Netmail Alert (to othernet network address)
|
// Netmail Alert (to othernet network address)
|
||||||
if ($ao->system->aka_unknown()->count()) {
|
if ($ao->system->uncommon()->count()) {
|
||||||
Notification::route('netmail',$ao->system->aka_unknown()->first()->withoutRelations())->notify(new NodeMarkedDownNetmail($ao->withoutRelations()));
|
Notification::route('netmail',$ao->system->uncommon()->first()->withoutRelations())->notify(new NodeMarkedDownNetmail($ao->withoutRelations()));
|
||||||
$contact = TRUE;
|
$contact = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,19 +126,12 @@ class AddressIdle implements ShouldQueue
|
|||||||
$ao->role |= Address::NODE_DOWN;
|
$ao->role |= Address::NODE_DOWN;
|
||||||
$ao->save();
|
$ao->save();
|
||||||
|
|
||||||
$ao->contacted = $contact;
|
$ao->contacted = (! $contact);
|
||||||
$result->push($ao);
|
$result->push($ao);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// @todo Make sure we only process addresses that we are responsible for, eg: 1/999 shouldnt have been processed even though 3/999 as eligible (and they are were connected to the same system)
|
|
||||||
// Mark nodes as HOLD
|
// Mark nodes as HOLD
|
||||||
if (config('fido.idle.hold')) {
|
foreach ($this->old($this->do,config('fido.idle.hold'),0,$this->ao) as $ao) {
|
||||||
$age = Carbon::now()->subDays(config('fido.idle.hold'));
|
|
||||||
|
|
||||||
foreach ($this->old($this->do,config('fido.idle.hold'),Address::NODE_ALL,$this->ao) as $ao) {
|
|
||||||
Log::debug(sprintf('%s:- Evaluating IDLE node [%s], not seen for at least [%d] days',self::LOGKEY,$ao->ftn,$ao->system->last_seen?->diffInDays()));
|
|
||||||
|
|
||||||
// Ignore any systems that are a Discoverd System
|
// Ignore any systems that are a Discoverd System
|
||||||
if ($ao->system->name === System::default) {
|
if ($ao->system->name === System::default) {
|
||||||
Log::alert(sprintf('%s:! Ignoring HOLD for discovered System [%s]',self::LOGKEY,$ao->ftn));
|
Log::alert(sprintf('%s:! Ignoring HOLD for discovered System [%s]',self::LOGKEY,$ao->ftn));
|
||||||
@ -156,13 +142,9 @@ class AddressIdle implements ShouldQueue
|
|||||||
if ($ao->role & (Address::NODE_DOWN|Address::NODE_HOLD))
|
if ($ao->role & (Address::NODE_DOWN|Address::NODE_HOLD))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Validate that the last seen was infact that long ago
|
|
||||||
if ($ao->system->last_seen && $ao->system->last_seen->greaterThan($age))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$contact = FALSE;
|
$contact = FALSE;
|
||||||
|
|
||||||
Log::info(sprintf('%s:- Marking [%s] as HOLD, not seen for at least [%d] days',self::LOGKEY,$ao->ftn,$ao->system->last_seen?->diffInDays()));
|
Log::info(sprintf('%s:- Marking [%s] as HOLD, not seen for [%d] days',self::LOGKEY,$ao->ftn,config('fido.idle.hold')));
|
||||||
|
|
||||||
// Email Alert
|
// Email Alert
|
||||||
if ($ao->system->users->count()) {
|
if ($ao->system->users->count()) {
|
||||||
@ -171,8 +153,8 @@ class AddressIdle implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Netmail Alert (to othernet network address)
|
// Netmail Alert (to othernet network address)
|
||||||
if ($ao->system->aka_unknown()->count()) {
|
if ($ao->system->uncommon()->count()) {
|
||||||
Notification::route('netmail',$ao->system->aka_unknown()->first()->withoutRelations())->notify(new NodeMarkedHoldNetmail($ao->withoutRelations()));
|
Notification::route('netmail',$ao->system->uncommon()->first()->withoutRelations())->notify(new NodeMarkedHoldNetmail($ao->withoutRelations()));
|
||||||
$contact = TRUE;
|
$contact = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,36 +162,55 @@ class AddressIdle implements ShouldQueue
|
|||||||
$ao->role |= Address::NODE_HOLD;
|
$ao->role |= Address::NODE_HOLD;
|
||||||
$ao->save();
|
$ao->save();
|
||||||
|
|
||||||
$ao->contacted = $contact;
|
$ao->contacted = (! $contact);
|
||||||
$result->push($ao);
|
$result->push($ao);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($result->count())
|
if ($result->count())
|
||||||
Notification::route('echomail',$this->do->nodestatus_echoarea)->notify(new AbsentNodes($result));
|
Notification::route('echomail',$this->do->nodestatusarea)->notify(new AbsentNodes($result));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function old(Domain $do,int $days,int $flags=0,Address $ao=NULL): Collection
|
private function old(Domain $do,int $days,int $flags=0,Address $ao=NULL): Collection
|
||||||
{
|
{
|
||||||
// Ignore dates that are zero
|
|
||||||
if (! $days)
|
|
||||||
return collect();
|
|
||||||
|
|
||||||
$age = Carbon::now()->subDays($days)->endOfDay();
|
$age = Carbon::now()->subDays($days)->endOfDay();
|
||||||
$ours = our_address($do)->pluck('ftn');
|
|
||||||
|
|
||||||
return Address::FTN()
|
return Address::select([
|
||||||
->ActiveFTN()
|
'a.id',
|
||||||
->addSelect(['addresses.updated_at'])
|
'a.system_id',
|
||||||
->where(fn($query)=>$query->where('point_id',0)->orWhereNull('point_id'))
|
'a.zone_id',
|
||||||
->whereIn('addresses.id',our_nodes($do)->pluck('id'))
|
'addresses.region_id',
|
||||||
|
'a.host_id',
|
||||||
|
'a.node_id',
|
||||||
|
'a.point_id',
|
||||||
|
'addresses.active',
|
||||||
|
'addresses.hub_id',
|
||||||
|
'addresses.role',
|
||||||
|
'addresses.updated_at',
|
||||||
|
DB::raw('sum(a.uncollected_echomail) as uncollected_echomail'),
|
||||||
|
DB::raw('sum(a.uncollected_netmail) as uncollected_netmail'),
|
||||||
|
DB::raw('sum(a.uncollected_files) as uncollected_files')
|
||||||
|
])
|
||||||
|
->from(
|
||||||
|
Address::UncollectedEchomailTotal()
|
||||||
|
->union(Address::UncollectedNetmailTotal())
|
||||||
|
->union(Address::UncollectedFilesTotal()),'a')
|
||||||
|
->where('systems.active',TRUE)
|
||||||
|
->where('addresses.active',TRUE)
|
||||||
|
->where('zones.active',TRUE)
|
||||||
|
->where('domains.active',TRUE)
|
||||||
|
->whereNotIn('a.id',our_address()->pluck('id'))
|
||||||
->when($ao,fn($query)=>$query->where('addresses.id',$ao->id))
|
->when($ao,fn($query)=>$query->where('addresses.id',$ao->id))
|
||||||
->where(fn($q)=>$q->where('last_session','<',$age)->orWhereNull('last_session'))
|
->where('last_session','<',$age)
|
||||||
->whereRaw(sprintf('((role IS NULL) OR (role=0) OR ((role & %d) > 0))',$flags))
|
->where('domains.id',$do->id)
|
||||||
->whereRaw(sprintf('((role IS NULL) OR ((role & %d) = 0))',Address::NODE_KEEP))
|
->whereRaw(sprintf('((role IS NULL) OR ((role & %d) > 0))',$flags))
|
||||||
->join('systems',['systems.id'=>'addresses.system_id'])
|
->join('addresses',['addresses.id'=>'a.id'])
|
||||||
//->with(['system','zone.domain'])
|
->join('systems',['systems.id'=>'a.system_id'])
|
||||||
->get()
|
->join('zones',['zones.id'=>'addresses.zone_id'])
|
||||||
->filter(fn($item)=>$ours->contains($item->parent()?->ftn));
|
->join('domains',['domains.id'=>'zones.domain_id'])
|
||||||
|
->ftnOrder()
|
||||||
|
->groupBy('a.system_id','a.id','a.zone_id','addresses.region_id','a.host_id','a.node_id','a.point_id','addresses.hub_id','addresses.role','addresses.active','addresses.updated_at')
|
||||||
|
->with(['system','zone.domain'])
|
||||||
|
->dontCache()
|
||||||
|
->get();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,6 +14,13 @@ class AddressIdleDomain implements ShouldQueue
|
|||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the job.
|
* Execute the job.
|
||||||
*/
|
*/
|
||||||
|
@ -27,7 +27,7 @@ class AddressPoll implements ShouldQueue, ShouldBeUnique
|
|||||||
|
|
||||||
private const LOGKEY = 'JAP';
|
private const LOGKEY = 'JAP';
|
||||||
|
|
||||||
public int $tries = 10;
|
public int $tries = 5;
|
||||||
public int $maxExceptions = 1;
|
public int $maxExceptions = 1;
|
||||||
public bool $failOnTimeout = TRUE;
|
public bool $failOnTimeout = TRUE;
|
||||||
|
|
||||||
@ -38,8 +38,8 @@ class AddressPoll implements ShouldQueue, ShouldBeUnique
|
|||||||
|
|
||||||
public function __construct(Address $ao,Mailer $mo=NULL)
|
public function __construct(Address $ao,Mailer $mo=NULL)
|
||||||
{
|
{
|
||||||
$this->ao = $ao->withoutRelations();
|
$this->ao = $ao;
|
||||||
$this->mo = $mo?->withoutRelations();
|
$this->mo = $mo;
|
||||||
|
|
||||||
$this->onQueue(self::QUEUE);
|
$this->onQueue(self::QUEUE);
|
||||||
}
|
}
|
||||||
@ -93,13 +93,13 @@ class AddressPoll implements ShouldQueue, ShouldBeUnique
|
|||||||
|
|
||||||
switch ($o->name) {
|
switch ($o->name) {
|
||||||
case 'BINKP':
|
case 'BINKP':
|
||||||
$s = new Binkp;
|
$s = new Binkp(Setup::findOrFail(config('app.id')));
|
||||||
$mo = Mailer::where('name','BINKP')->singleOrFail();
|
$mo = Mailer::where('name','BINKP')->singleOrFail();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'EMSI':
|
case 'EMSI':
|
||||||
$s = new EMSI;
|
$s = new EMSI(Setup::findOrFail(config('app.id')));
|
||||||
$mo = Mailer::where('name','EMSI')->singleOrFail();
|
$mo = Mailer::where('name','EMSI')->singleOrFail();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1,169 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use Illuminate\Queue\Middleware\Skip;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Facades\Notification;
|
|
||||||
|
|
||||||
use App\Models\{Address,Echoarea,Echomail};
|
|
||||||
use App\Notifications\Netmails\Areafix\Scan;
|
|
||||||
|
|
||||||
class AreafixRescan implements ShouldQueue
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
||||||
|
|
||||||
private const LOGKEY = 'JAR';
|
|
||||||
|
|
||||||
private Address $ao; // System address
|
|
||||||
private Echoarea $eao; // Domain we are processing
|
|
||||||
private int $days;
|
|
||||||
private bool $rescan;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new job instance.
|
|
||||||
*/
|
|
||||||
public function __construct(Address $ao,Echoarea $eao,int $days=30,bool $rescan=FALSE)
|
|
||||||
{
|
|
||||||
$this->ao = $ao->withoutRelations();
|
|
||||||
$this->eao = $eao->withoutRelations();
|
|
||||||
$this->days = $days;
|
|
||||||
$this->rescan = $rescan;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __get(string $key): mixed
|
|
||||||
{
|
|
||||||
switch ($key) {
|
|
||||||
case 'jobname':
|
|
||||||
return sprintf('%s %s (%d)',$this->ao->ftn,$this->eao->name,$this->days);
|
|
||||||
|
|
||||||
default:
|
|
||||||
$this->fail('Unkown key:'.$key);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function middleware(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
Skip::when(function(): bool {
|
|
||||||
if ($this->eao->domain_id !== $this->ao->zone->domain_id) {
|
|
||||||
Log::error(sprintf('%s:! Echo area [%s] is not in domain [%s] for FTN [%s]',self::LOGKEY,$this->eao->name,$this->ao->zone->domain->name,$this->ao->ftn));
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
// Check that the user is subscribed
|
|
||||||
} elseif (! $this->ao->echoareas->contains($this->eao->id)) {
|
|
||||||
Log::error(sprintf('%s:! FTN [%s] is not subscribed to [%s]',self::LOGKEY,$this->ao->ftn,$this->eao->name));
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
// Check that an FTN can read the area
|
|
||||||
} elseif (! $this->eao->can_read($this->ao->security)) {
|
|
||||||
Log::error(sprintf('%s:! FTN [%s] doesnt have permission to receive [%s]',self::LOGKEY,$this->ao->ftn,$this->eao->name));
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
$c = 0;
|
|
||||||
$s = 0;
|
|
||||||
|
|
||||||
$earliest = NULL;
|
|
||||||
$latest = NULL;
|
|
||||||
|
|
||||||
foreach (Echomail::select(['id','datetime'])
|
|
||||||
->where('echoarea_id',$this->eao->id)
|
|
||||||
->where('datetime','>=',
|
|
||||||
Carbon::now()
|
|
||||||
->subDays($this->days)
|
|
||||||
->startOfDay()
|
|
||||||
)
|
|
||||||
->orderBy('datetime')
|
|
||||||
->cursor() as $eo) {
|
|
||||||
|
|
||||||
// Echomail hasnt been exported before
|
|
||||||
if (! $eo->seenby->count()) {
|
|
||||||
$eo->seenby()->attach($this->ao->id,['export_at'=>Carbon::now()]);
|
|
||||||
$c++;
|
|
||||||
|
|
||||||
if (($eo->datetime < $earliest) || (! $earliest))
|
|
||||||
$earliest = $eo->datetime;
|
|
||||||
|
|
||||||
if (($latest < $eo->datetime) || (! $latest))
|
|
||||||
$latest = $eo->datetime;
|
|
||||||
|
|
||||||
Log::debug(sprintf('Exported [%d] MSG (%s) dated (%s) to [%s]',$eo->id,$eo->msgid ?: '*NO MSGID*',$eo->datetime->format('Y-m-d H:i:s'),$this->ao->ftn3d));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$export = $eo->seenby->where('id',$this->ao->id)->pop();
|
|
||||||
|
|
||||||
if ($export) {
|
|
||||||
// Echomail is pending export
|
|
||||||
if ($export->pivot->export_at && is_null($export->pivot->sent_at) && is_null($export->pivot->sent_pkt)) {
|
|
||||||
$s++;
|
|
||||||
Log::debug(sprintf('Not exporting [%d] MSG (%s) dated (%s) already queued for [%s]',$eo->id,$eo->msgid ?: '*NO MSGID*',$eo->datetime->format('Y-m-d H:i:s'),$this->ao->ftn3d));
|
|
||||||
|
|
||||||
// Echomail has been exported
|
|
||||||
} elseif ($this->rescan) {
|
|
||||||
$eo->seenby()->updateExistingPivot($this->ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
|
|
||||||
$c++;
|
|
||||||
|
|
||||||
if (($eo->datetime < $earliest) || (! $earliest))
|
|
||||||
$earliest = $eo->datetime;
|
|
||||||
|
|
||||||
if (($latest < $eo->datetime) || (! $latest))
|
|
||||||
$latest = $eo->datetime;
|
|
||||||
|
|
||||||
Log::debug(sprintf('Re-exported [%d] MSG (%s) dated (%s) to [%s]',$eo->id,$eo->msgid ?: '*NO MSGID*',$eo->datetime,$this->ao->ftn3d));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$s++;
|
|
||||||
Log::debug(sprintf('Not resending previously sent message [%d], MSGID (%s) - sent in Pkt [%s] on [%s]',
|
|
||||||
$eo->id,
|
|
||||||
$eo->msgid ?: '* NO MSGID*',
|
|
||||||
$export->pivot->sent_pkt ?: '-',
|
|
||||||
$export->pivot->sent_at ?: '-',
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Echomail has not been exported
|
|
||||||
} else {
|
|
||||||
$eo->seenby()->attach($this->ao,['export_at'=>Carbon::now(),'sent_at'=>NULL,'sent_pkt'=>NULL]);
|
|
||||||
$c++;
|
|
||||||
|
|
||||||
if (($eo->datetime < $earliest) || (! $earliest))
|
|
||||||
$earliest = $eo->datetime;
|
|
||||||
|
|
||||||
if (($latest < $eo->datetime) || (! $latest))
|
|
||||||
$latest = $eo->datetime;
|
|
||||||
|
|
||||||
Log::debug(sprintf('Exported [%d] to [%s]',$eo->id,$this->ao->ftn3d));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Notification::route('netmail',$this->ao)
|
|
||||||
->notify(new Scan(collect([
|
|
||||||
'area'=>$this->eao->name,
|
|
||||||
'queued'=>$c,
|
|
||||||
'skipped'=>$s,
|
|
||||||
'earliest'=>$earliest,
|
|
||||||
'latest'=>$latest,
|
|
||||||
])));
|
|
||||||
|
|
||||||
Log::info(sprintf('%s:= Queued [%d], Skipped [%d] echomails for [%s] in [%s]',self::LOGKEY,$c,$s,$this->ao->ftn,$this->eao->name));
|
|
||||||
}
|
|
||||||
}
|
|
@ -36,7 +36,7 @@ class EchoareaImport implements ShouldQueue
|
|||||||
public function __construct(string $file,Domain $do,string $prefix='',bool $delete_recs=FALSE,bool $delete_file=FALSE)
|
public function __construct(string $file,Domain $do,string $prefix='',bool $delete_recs=FALSE,bool $delete_file=FALSE)
|
||||||
{
|
{
|
||||||
$this->file = $file;
|
$this->file = $file;
|
||||||
$this->do = $do->withoutRelations();
|
$this->do = $do;
|
||||||
$this->prefix = $prefix ?: '';
|
$this->prefix = $prefix ?: '';
|
||||||
$this->delete_file = $delete_file;
|
$this->delete_file = $delete_file;
|
||||||
$this->delete_recs = $delete_recs;
|
$this->delete_recs = $delete_recs;
|
||||||
|
@ -36,7 +36,7 @@ class FileareaImport implements ShouldQueue
|
|||||||
public function __construct(string $file,Domain $do,string $prefix='',bool $delete_recs=FALSE,bool $delete_file=FALSE)
|
public function __construct(string $file,Domain $do,string $prefix='',bool $delete_recs=FALSE,bool $delete_file=FALSE)
|
||||||
{
|
{
|
||||||
$this->file = $file;
|
$this->file = $file;
|
||||||
$this->do = $do->withoutRelations();
|
$this->do = $do;
|
||||||
$this->prefix = $prefix ?: '';
|
$this->prefix = $prefix ?: '';
|
||||||
$this->delete_file = $delete_file;
|
$this->delete_file = $delete_file;
|
||||||
$this->delete_recs = $delete_recs;
|
$this->delete_recs = $delete_recs;
|
||||||
|
@ -48,6 +48,21 @@ class MailSend #implements ShouldQueue
|
|||||||
->join('systems',['systems.id'=>'a.system_id'])
|
->join('systems',['systems.id'=>'a.system_id'])
|
||||||
->join('zones',['zones.id'=>'a.zone_id'])
|
->join('zones',['zones.id'=>'a.zone_id'])
|
||||||
->join('domains',['domains.id'=>'zones.domain_id'])
|
->join('domains',['domains.id'=>'zones.domain_id'])
|
||||||
|
->where(function($query) {
|
||||||
|
return $query->whereNull('autohold')
|
||||||
|
->orWhere('autohold',FALSE);
|
||||||
|
})
|
||||||
|
->when(! is_null($this->crash),function($query) {
|
||||||
|
return $query->when(
|
||||||
|
$this->crash,
|
||||||
|
function($query) {
|
||||||
|
return $query->where('pollmode',$this->crash);
|
||||||
|
},
|
||||||
|
function($query) {
|
||||||
|
return $query->whereNotNull('pollmode');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
->groupBy('a.system_id','a.id','a.zone_id','addresses.region_id','a.host_id','a.node_id','a.point_id','addresses.hub_id','addresses.role')
|
->groupBy('a.system_id','a.id','a.zone_id','addresses.region_id','a.host_id','a.node_id','a.point_id','addresses.hub_id','addresses.role')
|
||||||
->with(['system','zone.domain'])
|
->with(['system','zone.domain'])
|
||||||
->dontCache()
|
->dontCache()
|
||||||
@ -65,12 +80,6 @@ class MailSend #implements ShouldQueue
|
|||||||
} else {
|
} else {
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
->filter(function($item) {
|
|
||||||
if ($item->system->autohold)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return is_null($this->crash) || ($item->system->pollmode) || ($item->system->pollmode === $this->crash) ? $item : NULL;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach ($u->groupBy('ftn') as $oo) {
|
foreach ($u->groupBy('ftn') as $oo) {
|
||||||
|
@ -34,7 +34,7 @@ class MessageProcess implements ShouldQueue
|
|||||||
public function __construct(Echomail|Netmail $mo,bool $skipbot=FALSE)
|
public function __construct(Echomail|Netmail $mo,bool $skipbot=FALSE)
|
||||||
{
|
{
|
||||||
// @todo We need to serialize this model here, because laravel has an error unserializing it (Model Not Found)
|
// @todo We need to serialize this model here, because laravel has an error unserializing it (Model Not Found)
|
||||||
$this->mo = utf8_encode(serialize($mo->withoutRelations()));
|
$this->mo = utf8_encode(serialize($mo));
|
||||||
$this->skipbot = $skipbot;
|
$this->skipbot = $skipbot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class MessageProcess implements ShouldQueue
|
|||||||
// @todo generate exception when netmail to system that doesnt exist (node/point) and its this host's responsibility
|
// @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].',
|
Log::info(sprintf('%s:- Processing Netmail [%s] to (%s) [%s] from (%s) [%s].',
|
||||||
self::LOGKEY,
|
self::LOGKEY,
|
||||||
$this->mo->msgid ?: '*NO MSGID*',
|
$this->mo->msgid,
|
||||||
$this->mo->to,$this->mo->tftn->ftn,
|
$this->mo->to,$this->mo->tftn->ftn,
|
||||||
$this->mo->from,$this->mo->fftn->ftn,
|
$this->mo->from,$this->mo->fftn->ftn,
|
||||||
));
|
));
|
||||||
@ -81,7 +81,7 @@ class MessageProcess implements ShouldQueue
|
|||||||
Log::debug(sprintf('%s:- Checking for duplicate from host [%s].',self::LOGKEY,$this->mo->fftn->ftn));
|
Log::debug(sprintf('%s:- Checking for duplicate from host [%s].',self::LOGKEY,$this->mo->fftn->ftn));
|
||||||
|
|
||||||
$o = Netmail::where('msgid',$this->mo->msgid)
|
$o = Netmail::where('msgid',$this->mo->msgid)
|
||||||
->where('fftn_id',$this->mo->fftn_id)
|
->where('fftn_id',$this->mo->fftn->id)
|
||||||
->where('datetime','>',Carbon::now()->subYears(3))
|
->where('datetime','>',Carbon::now()->subYears(3))
|
||||||
->single();
|
->single();
|
||||||
|
|
||||||
@ -137,19 +137,12 @@ class MessageProcess implements ShouldQueue
|
|||||||
->single();
|
->single();
|
||||||
|
|
||||||
if ($uo && ($ao=$uo->system->match($this->mo->tftn->zone)?->pop())) {
|
if ($uo && ($ao=$uo->system->match($this->mo->tftn->zone)?->pop())) {
|
||||||
Log::info(sprintf('%s:- Forwarding Netmail [%s] to (%s) [%s] from (%s) [%s].',
|
|
||||||
self::LOGKEY,
|
|
||||||
$this->mo->msgid ?: '*NO MSGID*',
|
|
||||||
$this->mo->to,$ao->ftn,
|
|
||||||
$this->mo->from,$this->mo->fftn->ftn,
|
|
||||||
));
|
|
||||||
|
|
||||||
$note = "+--[ FORWARDED MESSAGE ]----------------------------------+\r";
|
$note = "+--[ FORWARDED MESSAGE ]----------------------------------+\r";
|
||||||
$note .= "+ This message has been forwarded to you, it was originally sent to you\r";
|
$note .= "+ This message has been forwarded to you, it was originally sent to you\r";
|
||||||
$note .= sprintf("+ at [%s]\r",$this->mo->tftn->ftn);
|
$note .= sprintf("+ at [%s]\r",$this->mo->tftn->ftn);
|
||||||
$note .= "+---------------------------------------------------------+\r\r";
|
$note .= "+---------------------------------------------------------+\r\r";
|
||||||
|
|
||||||
$this->mo->msg_src = $note.$this->mo->content;
|
$this->mo->msg = $note.$this->mo->content;
|
||||||
$this->mo->tftn_id = $ao->id;
|
$this->mo->tftn_id = $ao->id;
|
||||||
$this->mo->flags |= Message::FLAG_INTRANSIT;
|
$this->mo->flags |= Message::FLAG_INTRANSIT;
|
||||||
$this->mo->save();
|
$this->mo->save();
|
||||||
@ -206,7 +199,7 @@ class MessageProcess implements ShouldQueue
|
|||||||
// The packet sender
|
// The packet sender
|
||||||
$sender = $this->mo->set->get('set_sender');
|
$sender = $this->mo->set->get('set_sender');
|
||||||
|
|
||||||
// @todo Check that this does evaluate to true if a message has been rescanned
|
// @todo Check that this does evaulate to true if a message has been rescanned
|
||||||
$rescanned = $this->mo->kludges->get('RESCANNED',FALSE);
|
$rescanned = $this->mo->kludges->get('RESCANNED',FALSE);
|
||||||
|
|
||||||
// Echoarea doesnt exist, cant import the message
|
// Echoarea doesnt exist, cant import the message
|
||||||
@ -233,24 +226,17 @@ class MessageProcess implements ShouldQueue
|
|||||||
// Check for duplicate messages
|
// Check for duplicate messages
|
||||||
// FTS-0009.001
|
// FTS-0009.001
|
||||||
if ($this->mo->msgid) {
|
if ($this->mo->msgid) {
|
||||||
$o = ($x=Echomail::where('msgid',$this->mo->msgid)
|
$o = Echomail::where('msgid',$this->mo->msgid)
|
||||||
->where('fftn_id',$this->mo->fftn_id)
|
->where('fftn_id',$this->mo->fftn->id)
|
||||||
->where('datetime','>=',$this->mo->datetime->clone()->subYears(3))
|
->where('datetime','>=',$this->mo->date->subYears(3))
|
||||||
->where('datetime','<=',$this->mo->datetime)
|
->where('datetime','<=',$this->mo->date)
|
||||||
->dontCache())
|
|
||||||
->single();
|
->single();
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- Checking for duplicate from host id [%d], with msgid [%s] between [%s] and [%s].',
|
Log::debug(sprintf('%s:- Checking for duplicate from host id [%d].',self::LOGKEY,$this->mo->fftn->id));
|
||||||
self::LOGKEY,
|
|
||||||
$this->mo->fftn_id,
|
|
||||||
$this->mo->msgid,
|
|
||||||
$this->mo->datetime->clone()->subYears(3),
|
|
||||||
$this->mo->datetime,
|
|
||||||
));
|
|
||||||
|
|
||||||
if ($x->count()) {
|
if ($o) {
|
||||||
// @todo Actually update seenby
|
// @todo Actually update seenby
|
||||||
Log::alert(sprintf('%s:! Duplicate echomail (%s) in [%s] from (%s) [%s] to (%s) - ignoring.',
|
Log::alert(sprintf('%s:! Duplicate echomail [%s] in [%s] from (%s) [%s] to (%s) - updating seenby.',
|
||||||
self::LOGKEY,
|
self::LOGKEY,
|
||||||
$this->mo->msgid,
|
$this->mo->msgid,
|
||||||
$this->mo->echoarea->name,
|
$this->mo->echoarea->name,
|
||||||
@ -258,9 +244,37 @@ class MessageProcess implements ShouldQueue
|
|||||||
$this->mo->to,
|
$this->mo->to,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
//$o->save();
|
||||||
|
|
||||||
// @todo This duplicate message may have gone via a different path, be nice to record it.
|
// @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->mo->path,$sender->zone,$dummy);
|
||||||
|
|
||||||
|
$ppoid = NULL;
|
||||||
|
foreach ($path as $aoid) {
|
||||||
|
$po = DB::select('INSERT INTO echomail_path (echomail_id,address_id,parent_id) VALUES (?,?,?) RETURNING id',[
|
||||||
|
$o->id,
|
||||||
|
$aoid,
|
||||||
|
$ppoid,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$ppoid = $po[0]->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// @todo if we have an export for any of the seenby addresses, remove it
|
// @todo if we have an export for any of the seenby addresses, remove it
|
||||||
|
|
||||||
|
//$seenby = $this->parseAddresses('seenby',$this->mo->seenby,$sender->zone,$o->rogue_seenby);
|
||||||
|
//$this->mo->seenby()->syncWithoutDetaching($seenby);
|
||||||
|
|
||||||
|
// In case our rogue_seenby changed
|
||||||
|
//$this->mo->save();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,9 +282,8 @@ class MessageProcess implements ShouldQueue
|
|||||||
// Find another message with the same msg_crc
|
// Find another message with the same msg_crc
|
||||||
if ($this->mo->msg_crc) {
|
if ($this->mo->msg_crc) {
|
||||||
$o = Echomail::where('msg_crc',$xx=md5($this->mo->msg_crc))
|
$o = Echomail::where('msg_crc',$xx=md5($this->mo->msg_crc))
|
||||||
->where('fftn_id',$this->mo->fftn_id)
|
->where('fftn_id',$this->mo->fftn->id)
|
||||||
->where('datetime','>',Carbon::now()->subWeek())
|
->where('datetime','>',Carbon::now()->subWeek())
|
||||||
->dontCache()
|
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
if ($o->count())
|
if ($o->count())
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Facades\Notification;
|
|
||||||
|
|
||||||
use App\Models\{Address, Domain, System};
|
|
||||||
use App\Notifications\Netmails\NodesNew as NotificationNodesNew;
|
|
||||||
|
|
||||||
class NodesNew implements ShouldQueue
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
||||||
|
|
||||||
private const LOGKEY = 'JNN';
|
|
||||||
|
|
||||||
private ?Carbon $since; // New nodes since this date
|
|
||||||
private Address $ao; // Domain we are processing
|
|
||||||
private Domain $do; // Domain we are processing
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new job instance.
|
|
||||||
*/
|
|
||||||
public function __construct(Domain $do,Carbon $since=NULL,Address $ao=NULL)
|
|
||||||
{
|
|
||||||
$this->do = $do->withoutRelations();
|
|
||||||
$this->ao = $ao?->withoutRelations();
|
|
||||||
$this->since = $since;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the job.
|
|
||||||
*/
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
$since = ($this->since ?: Carbon::parse('last saturday'))->startOfDay();
|
|
||||||
|
|
||||||
$result = Address::FTN()
|
|
||||||
->ActiveFTN()
|
|
||||||
->join('systems',['systems.id'=>'addresses.system_id'])
|
|
||||||
->join('system_zone',['system_zone.system_id'=>'systems.id','system_zone.zone_id'=>'zones.id'])
|
|
||||||
->whereIn('zones.id',$this->do->zones->pluck('id'))
|
|
||||||
->where('systems.active',TRUE)
|
|
||||||
->where('systems.created_at','>=',$since)
|
|
||||||
->get();
|
|
||||||
|
|
||||||
if ($result->count()) {
|
|
||||||
Log::notice(sprintf('%s:- Sending new nodes since [%s] (%d)',self::LOGKEY,$since,$result->count()));
|
|
||||||
|
|
||||||
Notification::route('netmail',$this->ao->withoutRelations())
|
|
||||||
->notify(new NotificationNodesNew(
|
|
||||||
$since,
|
|
||||||
$result,
|
|
||||||
));
|
|
||||||
|
|
||||||
} else
|
|
||||||
Log::notice(sprintf('%s:- No nodes since [%s]',self::LOGKEY,$since));
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,7 +17,7 @@ use League\Flysystem\UnableToMoveFile;
|
|||||||
use App\Classes\File;
|
use App\Classes\File;
|
||||||
use App\Classes\FTN\Packet;
|
use App\Classes\FTN\Packet;
|
||||||
use App\Exceptions\InvalidPacketException;
|
use App\Exceptions\InvalidPacketException;
|
||||||
use App\Models\{Echomail,Netmail,System};
|
use App\Models\{Domain,Echomail,Netmail};
|
||||||
use App\Notifications\Netmails\PacketPasswordInvalid;
|
use App\Notifications\Netmails\PacketPasswordInvalid;
|
||||||
|
|
||||||
class PacketProcess implements ShouldQueue
|
class PacketProcess implements ShouldQueue
|
||||||
@ -27,15 +27,15 @@ class PacketProcess implements ShouldQueue
|
|||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
private string $filename;
|
private string $filename;
|
||||||
private System $so;
|
private Domain $do;
|
||||||
private Carbon $rcvd_time;
|
private Carbon $rcvd_time;
|
||||||
private bool $interactive;
|
private bool $interactive;
|
||||||
private bool $nobot;
|
private bool $nobot;
|
||||||
|
|
||||||
public function __construct(string $filename,System $so,bool $interactive=TRUE,Carbon $rcvd_time=NULL,bool $nobot=FALSE)
|
public function __construct(string $filename,Domain $do,bool $interactive=TRUE,Carbon $rcvd_time=NULL,bool $nobot=FALSE)
|
||||||
{
|
{
|
||||||
$this->filename = $filename;
|
$this->filename = $filename;
|
||||||
$this->so = $so->withoutRelations();
|
$this->do = $do;
|
||||||
$this->interactive = $interactive;
|
$this->interactive = $interactive;
|
||||||
$this->rcvd_time = $rcvd_time ?: Carbon::now();
|
$this->rcvd_time = $rcvd_time ?: Carbon::now();
|
||||||
$this->nobot = $nobot;
|
$this->nobot = $nobot;
|
||||||
@ -67,11 +67,9 @@ class PacketProcess implements ShouldQueue
|
|||||||
$f = new File($fs->path($this->filename));
|
$f = new File($fs->path($this->filename));
|
||||||
|
|
||||||
$processed = FALSE;
|
$processed = FALSE;
|
||||||
$bad_archive = FALSE;
|
|
||||||
|
|
||||||
foreach ($f as $packet) {
|
foreach ($f as $packet) {
|
||||||
try {
|
$pkt = Packet::process($packet,Arr::get(stream_get_meta_data($packet),'uri'),$f->itemSize(),$this->do);
|
||||||
$pkt = Packet::process($packet,Arr::get(stream_get_meta_data($packet),'uri'),$f->itemSize(),$this->so);
|
|
||||||
|
|
||||||
// Check that the packet is from a system that is defined in the DB
|
// Check that the packet is from a system that is defined in the DB
|
||||||
if (! $pkt->fftn) {
|
if (! $pkt->fftn) {
|
||||||
@ -81,21 +79,13 @@ class PacketProcess implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! our_nodes($pkt->fftn->zone->domain)->contains($pkt->fftn)) {
|
if (! our_nodes($pkt->fftn->zone->domain)->contains($pkt->fftn)) {
|
||||||
Log::error(sprintf('%s:! Packet [%s] is from a system that is not configured with us? [%s]',self::LOGKEY,$this->filename,$pkt->fftn_t));
|
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));
|
||||||
|
|
||||||
// @todo Notification::route('netmail',$pkt->fftn)->notify(new UnexpectedPacketFromYou($this->filename));
|
// @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
|
// @todo Parse the packet for netmails and process them. We'll only accept netmails to us, and ignore all others
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we dont have the tftn in the DB, then packet cannot be to us
|
|
||||||
if (! $pkt->tftn) {
|
|
||||||
Log::error(sprintf('%s:! Packet [%s] is from a system [%s] we dont know about?',self::LOGKEY,$this->filename,$pkt->tftn_t));
|
|
||||||
|
|
||||||
// @todo Notification::route('netmail',$pkt->fftn)->notify(new UnexpectedPacketToUs($this->filename));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the packet is to our address, if not we'll reject it.
|
// Check the packet is to our address, if not we'll reject it.
|
||||||
if (! our_address($pkt->tftn->zone->domain)->contains($pkt->tftn)) {
|
if (! our_address($pkt->tftn->zone->domain)->contains($pkt->tftn)) {
|
||||||
Log::error(sprintf('%s:! Packet [%s] is not to our address? [%s]',self::LOGKEY,$this->filename,$pkt->tftn->ftn));
|
Log::error(sprintf('%s:! Packet [%s] is not to our address? [%s]',self::LOGKEY,$this->filename,$pkt->tftn->ftn));
|
||||||
@ -155,15 +145,9 @@ class PacketProcess implements ShouldQueue
|
|||||||
|
|
||||||
if ($count === $pkt->count())
|
if ($count === $pkt->count())
|
||||||
$processed = TRUE;
|
$processed = TRUE;
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::error(sprintf('%s:! Got an exception [%s] processing packet',self::LOGKEY,$e->getMessage()));
|
|
||||||
|
|
||||||
$bad_archive = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((! $processed) || $bad_archive) {
|
if (! $processed) {
|
||||||
Log::alert(sprintf('%s:- Not deleting packet [%s], it doesnt seem to be processed?',self::LOGKEY,$this->filename));
|
Log::alert(sprintf('%s:- Not deleting packet [%s], it doesnt seem to be processed?',self::LOGKEY,$this->filename));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -60,15 +60,15 @@ class SystemHeartbeat #implements ShouldQueue
|
|||||||
// If we havent polled in heatbeat hours, poll system
|
// If we havent polled in heatbeat hours, poll system
|
||||||
foreach ($l as $oo) {
|
foreach ($l as $oo) {
|
||||||
if (Job::where('queue','poll')->get()->pluck('command.address.id')->search($oo->id) === FALSE) {
|
if (Job::where('queue','poll')->get()->pluck('command.address.id')->search($oo->id) === FALSE) {
|
||||||
if ((! $oo->system->last_seen)
|
if ((! $oo->system->last_session)
|
||||||
|| ($oo->system->hearbeat && ($oo->system->last_seen->addHours($oo->system->heartbeat) < Carbon::now()))
|
|| ($oo->system->hearbeat && ($oo->system->last_session->addHours($oo->system->heartbeat) < Carbon::now()))
|
||||||
|| ((! $oo->system->hearbeat) && ($oo->role_id < Address::NODE_NN) && ($oo->system->last_seen->addHours(6) < Carbon::now())))
|
|| ((! $oo->system->hearbeat) && ($oo->role_id < Address::NODE_NN) && ($oo->system->last_session->addHours(6) < Carbon::now())))
|
||||||
{
|
{
|
||||||
Log::info(sprintf('%s:- Polling [%s] (%s) - we havent seen them since [%s], heartbeat [%d]',
|
Log::info(sprintf('%s:- Polling [%s] (%s) - we havent seen them since [%s], heartbeat [%d]',
|
||||||
self::LOGKEY,
|
self::LOGKEY,
|
||||||
$oo->ftn,
|
$oo->ftn,
|
||||||
$oo->system->name,
|
$oo->system->name,
|
||||||
$oo->system->last_seen ?: 'Never',
|
$oo->system->last_session ?: 'Never',
|
||||||
$oo->system->heartbeat,
|
$oo->system->heartbeat,
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ class SystemHeartbeat #implements ShouldQueue
|
|||||||
Log::debug(sprintf('%s:= Not scheduling poll to [%s], we saw them [%s], heartbeat [%d]',
|
Log::debug(sprintf('%s:= Not scheduling poll to [%s], we saw them [%s], heartbeat [%d]',
|
||||||
self::LOGKEY,
|
self::LOGKEY,
|
||||||
$oo->ftn,
|
$oo->ftn,
|
||||||
$oo->system->last_seen,
|
$oo->system->last_session,
|
||||||
$oo->system->heartbeat
|
$oo->system->heartbeat
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ class EchomailListener implements ShouldQueue
|
|||||||
$ea = $event->eo->echoarea;
|
$ea = $event->eo->echoarea;
|
||||||
|
|
||||||
// Catch our messages that we've posted, so they dont go back
|
// Catch our messages that we've posted, so they dont go back
|
||||||
if (preg_match('/^@.+:/',$event->eo->from))
|
if (str_ends_with($event->eo->from,':'.config('matrix.server')))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ($ea && collect(config('matrix.rooms'))->contains($ea->name)) {
|
if ($ea && collect(config('matrix.rooms'))->contains($ea->name)) {
|
||||||
|
@ -42,7 +42,7 @@ class TestEmail extends Mailable
|
|||||||
->markdown('mail.system.test_email')
|
->markdown('mail.system.test_email')
|
||||||
->subject('Just a test...')
|
->subject('Just a test...')
|
||||||
->with([
|
->with([
|
||||||
'url'=>sprintf('https://%s',gethostname()),
|
'url'=>'https://localhost',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,28 +24,19 @@ use App\Traits\{QueryCacheableConfig,ScopeActive};
|
|||||||
*
|
*
|
||||||
* If an address is validated, we know that the system is using the address (we've confirmed that during a session).
|
* If an address is validated, we know that the system is using the address (we've confirmed that during a session).
|
||||||
* validated is update/removed is during a mailer session, confirming if the node has the address
|
* validated is update/removed is during a mailer session, confirming if the node has the address
|
||||||
* @todo Remove validated, if that system hasnt used the address for a defined period (eg: 30)
|
|
||||||
*
|
*
|
||||||
* We'll only trigger a poll to a system that we have mail for if active && validated, unless "forced".
|
* We'll only trigger a poll to a system that we have mail for if active && validated, unless "forced".
|
||||||
*
|
*
|
||||||
* Any mail for that address will be delivered, if active && validated.
|
* Any mail for that address will be delivered, if active && validated.
|
||||||
*
|
*
|
||||||
* Address status:
|
|
||||||
* + Active (active=true/validated=true) - mail can flow and in one of our networks (we have session details)
|
|
||||||
* + Pending (active=true/validated=false) - remote hasnt configured address during a session and in one of our networks
|
|
||||||
* + Known (active=true/validated=true) - the node presented this address, but we didnt auth it, and its a network we are not in
|
|
||||||
* + Unconfirm (active=true/validated=true) - the node presented this address, but we dont manage the address (it uses a different hub)
|
|
||||||
* + Nodelist (active=true/validated=true) - the node presented this address, but we dont manage the address and its in a recent nodelist
|
|
||||||
* + Delisted (active=false/validated=true) - this node shouldnt use this address any more
|
|
||||||
* + Freed (active=false/validated=false) - this node shouldnt is known to not be using this address any more
|
|
||||||
*
|
|
||||||
* Other Status
|
|
||||||
* + citizen - The address belongs to one of our jurisdiction (hub_id = our address, NC,RC,ZC)
|
|
||||||
* + foreign - The address doesnt belong to our jurisdiction
|
|
||||||
*
|
|
||||||
* @see \App\Http\Requests\AddressAdd::class for rules about AKA and role
|
* @see \App\Http\Requests\AddressAdd::class for rules about AKA and role
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Need to add
|
||||||
|
// Calculated Region for an FTN, ie: find the parent and use their region id
|
||||||
|
// - if creating an RC, then the region is part of the creation, ZC region is 0
|
||||||
|
// Then use this in createFTN
|
||||||
|
|
||||||
class Address extends Model
|
class Address extends Model
|
||||||
{
|
{
|
||||||
use QueryCacheableConfig,ScopeActive,SoftDeletes;
|
use QueryCacheableConfig,ScopeActive,SoftDeletes;
|
||||||
@ -61,10 +52,9 @@ class Address extends Model
|
|||||||
public const NODE_HC = 1<<3; // Hub
|
public const NODE_HC = 1<<3; // Hub
|
||||||
public const NODE_NN = 1<<4; // Node
|
public const NODE_NN = 1<<4; // Node
|
||||||
public const NODE_PVT = 1<<5; // Pvt (we dont have address information) @todo
|
public const NODE_PVT = 1<<5; // Pvt (we dont have address information) @todo
|
||||||
public const NODE_HOLD = 1<<6; // Hold (user has requested hold, we havent heard from the node for 7 days
|
public const NODE_HOLD = 1<<6; // Hold (user has requested hold, we havent heard from the node for 7 days @todo
|
||||||
public const NODE_DOWN = 1<<7; // Down we havent heard from the node for 30 days
|
public const NODE_DOWN = 1<<7; // Down we havent heard from the node for 30 days @todo
|
||||||
public const NODE_POINT = 1<<8; // Point
|
public const NODE_POINT = 1<<8; // Point
|
||||||
public const NODE_KEEP = 1<<9; // Dont mark an address hold/down or de-list automatically
|
|
||||||
public const NODE_UNKNOWN = 1<<15; // Unknown
|
public const NODE_UNKNOWN = 1<<15; // Unknown
|
||||||
public const NODE_ALL = 0x811f; // Mask to catch all nodes, excluding their status
|
public const NODE_ALL = 0x811f; // Mask to catch all nodes, excluding their status
|
||||||
|
|
||||||
@ -185,11 +175,10 @@ class Address extends Model
|
|||||||
*
|
*
|
||||||
* @param string $address
|
* @param string $address
|
||||||
* @param bool $trashed
|
* @param bool $trashed
|
||||||
* @param bool $recent
|
|
||||||
* @return Address|null
|
* @return Address|null
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function findFTN(string $address,bool $trashed=FALSE,bool $recent=FALSE): ?self
|
public static function findFTN(string $address,bool $trashed=FALSE): ?self
|
||||||
{
|
{
|
||||||
$ftn = self::parseFTN($address);
|
$ftn = self::parseFTN($address);
|
||||||
$o = NULL;
|
$o = NULL;
|
||||||
@ -198,11 +187,8 @@ class Address extends Model
|
|||||||
->select('addresses.*')
|
->select('addresses.*')
|
||||||
->join('zones',['zones.id'=>'addresses.zone_id'])
|
->join('zones',['zones.id'=>'addresses.zone_id'])
|
||||||
->join('domains',['domains.id'=>'zones.domain_id'])
|
->join('domains',['domains.id'=>'zones.domain_id'])
|
||||||
->when($trashed,function($query) use ($recent) {
|
->when($trashed,function($query) {
|
||||||
return $query->withTrashed()
|
$query->withTrashed();
|
||||||
->orderBy('updated_at','DESC')
|
|
||||||
->when($recent,fn($query)=>$query->where(fn($query)=>$query
|
|
||||||
->where('deleted_at','>=',Carbon::now()->subMonth())->orWhereNull('deleted_at')));
|
|
||||||
},function($query) {
|
},function($query) {
|
||||||
$query->active();
|
$query->active();
|
||||||
})
|
})
|
||||||
@ -223,7 +209,7 @@ class Address extends Model
|
|||||||
$o = $query
|
$o = $query
|
||||||
->where('region_id',$ftn['n'])
|
->where('region_id',$ftn['n'])
|
||||||
->where('host_id',$ftn['n'])
|
->where('host_id',$ftn['n'])
|
||||||
->with(['system:id,active,name,address,pkt_msgs,last_session,hold'])
|
->with(['system:id,active'])
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
// Look for a normal address
|
// Look for a normal address
|
||||||
@ -238,7 +224,7 @@ class Address extends Model
|
|||||||
})
|
})
|
||||||
->orWhere('host_id',$ftn['n']);
|
->orWhere('host_id',$ftn['n']);
|
||||||
})
|
})
|
||||||
->with(['system:id,active,name,address,pkt_msgs,last_session,hold'])
|
->with(['system:id,active'])
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
// Check and see if we are a flattened domain, our address might be available with a different zone.
|
// Check and see if we are a flattened domain, our address might be available with a different zone.
|
||||||
@ -255,7 +241,7 @@ class Address extends Model
|
|||||||
$o = self::findZone($do,$ftn['n'],$ftn['f'],$ftn['p'],$trashed);
|
$o = self::findZone($do,$ftn['n'],$ftn['f'],$ftn['p'],$trashed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($o && ($trashed || $o->system->active)) ? $o : NULL;
|
return ($o && $o->system->active) ? $o : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function newFTN(string $address): self
|
public static function newFTN(string $address): self
|
||||||
@ -263,26 +249,16 @@ class Address extends Model
|
|||||||
$ftn = self::parseFTN($address);
|
$ftn = self::parseFTN($address);
|
||||||
$do = $ftn['d'] ? Domain::where('name',$ftn['d'])->single() : NULL;
|
$do = $ftn['d'] ? Domain::where('name',$ftn['d'])->single() : NULL;
|
||||||
|
|
||||||
$o = new self;
|
|
||||||
$o->region_id = $ftn['r'];
|
|
||||||
$o->host_id = $ftn['n'];
|
|
||||||
$o->node_id = $ftn['f'];
|
|
||||||
$o->point_id = $ftn['p'];
|
|
||||||
|
|
||||||
$zo = Zone::where('zone_id',$ftn['z'])
|
$zo = Zone::where('zone_id',$ftn['z'])
|
||||||
->when($do,fn($query)=>$query->where('domain_id',$do->id))
|
->when($do,fn($query)=>$query->where('domain_id',$do->id))
|
||||||
->single();
|
->single();
|
||||||
|
|
||||||
|
$o = new self;
|
||||||
$o->zone_id = $zo?->id;
|
$o->zone_id = $zo?->id;
|
||||||
|
$o->region_id = $ftn['r'];
|
||||||
if (($ftn['z'] === 0) || (! $zo)) {
|
$o->host_id = $ftn['n'];
|
||||||
Log::alert(sprintf('%s:! newFTN was parsed an FTN [%s] with a zero zone, adding empty zone in domain',self::LOGKEY,$address));
|
$o->node_id = $ftn['f'];
|
||||||
|
$o->point_id = $ftn['p'];
|
||||||
$zo = new Zone;
|
|
||||||
$zo->domain_id = $do?->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
$o->zone()->associate($zo);
|
|
||||||
|
|
||||||
return $o;
|
return $o;
|
||||||
}
|
}
|
||||||
@ -353,42 +329,37 @@ class Address extends Model
|
|||||||
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - point address invalid [%d]',$ftn,$matches[4]));
|
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - point address invalid [%d]',$ftn,$matches[4]));
|
||||||
|
|
||||||
// Work out region
|
// Work out region
|
||||||
$region_id = NULL;
|
$region_id = 0;
|
||||||
$zone_id = NULL;
|
$zone_id = NULL;
|
||||||
|
|
||||||
// We can only work out region/zone if we have a domain - this is for 2D parsing
|
// We can only work out region if we have a domain
|
||||||
if ($matches[5] ?? NULL) {
|
if ($matches[5] ?? NULL) {
|
||||||
$o = new self;
|
$o = new self;
|
||||||
$o->host_id = $matches[2];
|
$o->host_id = $matches[2];
|
||||||
$o->node_id = $matches[3];
|
$o->node_id = $matches[3];
|
||||||
$o->point_id = empty($matches[4]) ? 0 : (int)$matches[4];
|
$o->point_id = empty($matches[4]) ? 0 : (int)$matches[4];
|
||||||
|
|
||||||
if ($matches[1] !== "0") {
|
$zo = Zone::select('zones.*')->where('zone_id',$matches[1])->join('domains',['domains.id'=>'zones.domain_id'])->where('domains.name',$matches[5])->single();
|
||||||
$zo = Zone::select('zones.*')
|
|
||||||
->where('zone_id',$matches[1])
|
|
||||||
->join('domains',['domains.id'=>'zones.domain_id'])
|
|
||||||
->where('domains.name',$matches[5])
|
|
||||||
->single();
|
|
||||||
|
|
||||||
// Try and find out the zone from the host_id
|
|
||||||
} else {
|
|
||||||
$zo = Zone::select('zones.*')
|
|
||||||
->where(fn($query)=>$query->where('host_id',$matches[2])->orWhere('region_id',$matches[2]))
|
|
||||||
->join('domains',['domains.id'=>'zones.domain_id'])
|
|
||||||
->join('addresses',['addresses.zone_id'=>'zones.id'])
|
|
||||||
->where('domains.name',$matches[5])
|
|
||||||
->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
$o->zone_id = $zo?->id;
|
$o->zone_id = $zo?->id;
|
||||||
$parent = $o->parent();
|
$parent = $o->parent();
|
||||||
|
$zone_id = $parent?->zone->zone_id;
|
||||||
|
|
||||||
|
// For flattened domains
|
||||||
|
if ($zo?->domain->flatten && is_null($zone_id))
|
||||||
|
foreach ($zo->domain->zones as $zoo) {
|
||||||
|
$o->zone_id = $zoo->id;
|
||||||
|
$parent = $o->parent();
|
||||||
|
|
||||||
|
if ($parent)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$region_id = $parent?->region_id;
|
$region_id = $parent?->region_id;
|
||||||
$zone_id = $parent?->zone->zone_id;
|
$zone_id = $parent?->zone->zone_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'z' => (int)($zone_id ?: $matches[1]),
|
'z' => (int)$zone_id ?: $matches[1],
|
||||||
'r' => (int)$region_id,
|
'r' => (int)$region_id,
|
||||||
'n' => (int)$matches[2],
|
'n' => (int)$matches[2],
|
||||||
'f' => (int)$matches[3],
|
'f' => (int)$matches[3],
|
||||||
@ -404,14 +375,16 @@ class Address extends Model
|
|||||||
*
|
*
|
||||||
* @param $query
|
* @param $query
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @note zones and domains needs to be joined in the base call, or use FTN()
|
|
||||||
*/
|
*/
|
||||||
public function scopeActiveFTN($query)
|
public function scopeActiveFTN($query)
|
||||||
{
|
{
|
||||||
return $query
|
return $query->select($this->getTable().'.*')
|
||||||
|
->join('zones',['zones.id'=>'addresses.zone_id'])
|
||||||
|
->join('domains',['domains.id'=>'zones.domain_id'])
|
||||||
->where('zones.active',TRUE)
|
->where('zones.active',TRUE)
|
||||||
->where('domains.active',TRUE)
|
->where('domains.active',TRUE)
|
||||||
->active();
|
->active()
|
||||||
|
->FTNorder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -423,21 +396,13 @@ class Address extends Model
|
|||||||
public function scopeFTN($query)
|
public function scopeFTN($query)
|
||||||
{
|
{
|
||||||
return $query
|
return $query
|
||||||
->select(['addresses.id','region_id','host_id','node_id','point_id','addresses.zone_id','addresses.active','role','security','addresses.system_id','addresses.active','validated','deleted_at'])
|
->select(['id','addresses.zone_id','host_id','node_id','point_id','system_id'])
|
||||||
->join('zones',['zones.id'=>'addresses.zone_id'])
|
|
||||||
->join('domains',['domains.id'=>'zones.domain_id'])
|
|
||||||
->orderBy('domains.name')
|
|
||||||
->orderBy('region_id')
|
|
||||||
->orderBy('host_id')
|
|
||||||
->orderBy('node_id')
|
|
||||||
->orderBy('point_id')
|
|
||||||
->with([
|
->with([
|
||||||
'zone:zones.id,domain_id,zone_id,active',
|
'zone:zones.id,domain_id,zone_id',
|
||||||
'zone.domain:domains.id,name,active,public',
|
'zone.domain:domains.id,name',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated use FTN() */
|
|
||||||
public function scopeFTNOrder($query)
|
public function scopeFTNOrder($query)
|
||||||
{
|
{
|
||||||
return $query
|
return $query
|
||||||
@ -483,7 +448,7 @@ class Address extends Model
|
|||||||
'node_id',
|
'node_id',
|
||||||
'point_id',
|
'point_id',
|
||||||
'system_id',
|
'system_id',
|
||||||
DB::raw('count(addresses.id) as uncollected_echomail'),
|
DB::raw('count(*) as uncollected_echomail'),
|
||||||
DB::raw('0 as uncollected_netmail'),
|
DB::raw('0 as uncollected_netmail'),
|
||||||
DB::raw('0 as uncollected_files'),
|
DB::raw('0 as uncollected_files'),
|
||||||
])
|
])
|
||||||
@ -520,7 +485,7 @@ class Address extends Model
|
|||||||
'system_id',
|
'system_id',
|
||||||
DB::raw('0 as uncollected_echomail'),
|
DB::raw('0 as uncollected_echomail'),
|
||||||
DB::raw('0 as uncollected_netmail'),
|
DB::raw('0 as uncollected_netmail'),
|
||||||
DB::raw('count(addresses.id) as uncollected_files')
|
DB::raw('count(*) as uncollected_files')
|
||||||
])
|
])
|
||||||
->UncollectedFiles();
|
->UncollectedFiles();
|
||||||
}
|
}
|
||||||
@ -558,7 +523,7 @@ class Address extends Model
|
|||||||
'point_id',
|
'point_id',
|
||||||
'system_id',
|
'system_id',
|
||||||
DB::raw('0 as uncollected_echomail'),
|
DB::raw('0 as uncollected_echomail'),
|
||||||
DB::raw('count(addresses.id) as uncollected_netmail'),
|
DB::raw('count(*) as uncollected_netmail'),
|
||||||
DB::raw('0 as uncollected_files')
|
DB::raw('0 as uncollected_files')
|
||||||
])
|
])
|
||||||
->UncollectedNetmail();
|
->UncollectedNetmail();
|
||||||
@ -584,7 +549,6 @@ class Address extends Model
|
|||||||
public function echoareas()
|
public function echoareas()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Echoarea::class)
|
return $this->belongsToMany(Echoarea::class)
|
||||||
->using(AddressEchoarea::class)
|
|
||||||
->orderBy('name')
|
->orderBy('name')
|
||||||
->withPivot(['subscribed']);
|
->withPivot(['subscribed']);
|
||||||
}
|
}
|
||||||
@ -784,9 +748,6 @@ class Address extends Model
|
|||||||
if (! $this->relationLoaded('zone'))
|
if (! $this->relationLoaded('zone'))
|
||||||
$this->load(['zone:id,domain_id,zone_id']);
|
$this->load(['zone:id,domain_id,zone_id']);
|
||||||
|
|
||||||
if (! $this->zone)
|
|
||||||
throw new InvalidFTNException(sprintf('Invalid Zone for FTN address [%d/%d.%d@%s]',$this->host_id ?: $this->region_id,$this->node_id,$this->point_id,$this->domain?->name));
|
|
||||||
|
|
||||||
return sprintf('%d:%s',$this->zone->zone_id,$this->getFTN2DAttribute());
|
return sprintf('%d:%s',$this->zone->zone_id,$this->getFTN2DAttribute());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1174,8 +1135,8 @@ class Address extends Model
|
|||||||
*/
|
*/
|
||||||
public function getNetmail(): ?Packet
|
public function getNetmail(): ?Packet
|
||||||
{
|
{
|
||||||
if ($count=($num=$this->netmailAlertWaiting())->count()) {
|
if (($num=$this->netmailAlertWaiting())->count()) {
|
||||||
Log::info(sprintf('%s:= Packaging [%d] netmail alerts to [%s]',self::LOGKEY,$count,$this->ftn));
|
Log::debug(sprintf('%s:= Packaging [%d] netmail alerts to [%s]',self::LOGKEY,$num->count(),$this->ftn));
|
||||||
|
|
||||||
$msgs = $num->get();
|
$msgs = $num->get();
|
||||||
|
|
||||||
@ -1199,11 +1160,11 @@ class Address extends Model
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($count=($num=$this->netmailWaiting())->count()) {
|
if (($num=$this->netmailWaiting())->count()) {
|
||||||
Log::info(sprintf('%s:= Got [%d] netmails for [%s] for sending',self::LOGKEY,$count,$this->ftn));
|
Log::debug(sprintf('%s:= Got [%d] netmails for [%s] for sending',self::LOGKEY,$num->count(),$this->ftn));
|
||||||
|
|
||||||
// Limit to max messages
|
// Limit to max messages
|
||||||
if ($count > $this->system->pkt_msgs)
|
if ($num->count() > $this->system->pkt_msgs)
|
||||||
Log::alert(sprintf('%s:= Only sending [%d] netmails for [%s]',self::LOGKEY,$this->system->pkt_msgs,$this->ftn));
|
Log::alert(sprintf('%s:= Only sending [%d] netmails for [%s]',self::LOGKEY,$this->system->pkt_msgs,$this->ftn));
|
||||||
|
|
||||||
return $this->system->packet($this)->mail($num->take($this->system->pkt_msgs)->get());
|
return $this->system->packet($this)->mail($num->take($this->system->pkt_msgs)->get());
|
||||||
@ -1228,17 +1189,10 @@ class Address extends Model
|
|||||||
*/
|
*/
|
||||||
public function netmailWaiting(): Builder
|
public function netmailWaiting(): Builder
|
||||||
{
|
{
|
||||||
// Addresses that our downstream of this address, except anybody that has session details with us
|
|
||||||
$ours = our_nodes($this->zone->domain)->pluck('id');
|
|
||||||
|
|
||||||
$addresses = $this->downstream()
|
|
||||||
->filter(fn($item)=>! $ours->contains($item->id))
|
|
||||||
->merge($this->system->match($this->zone,Address::NODE_ALL));
|
|
||||||
|
|
||||||
$netmails = $this
|
$netmails = $this
|
||||||
->UncollectedNetmail()
|
->UncollectedNetmail()
|
||||||
->select('netmails.id')
|
->select('netmails.id')
|
||||||
->whereIn('addresses.id',$addresses->pluck('id'))
|
->whereIn('addresses.id',$this->downlinks()->add($this)->pluck('id'))
|
||||||
->groupBy(['netmails.id'])
|
->groupBy(['netmails.id'])
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
|
||||||
|
|
||||||
class AddressEchoarea extends Pivot
|
|
||||||
{
|
|
||||||
protected $casts = [
|
|
||||||
'subscribed' => 'datetime:Y-m-d H:i',
|
|
||||||
];
|
|
||||||
}
|
|
@ -11,16 +11,9 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
use App\Models\Casts\CompressedStringOrNull;
|
use App\Casts\CompressedStringOrNull;
|
||||||
use App\Traits\{QueryCacheableConfig,ScopeActive};
|
use App\Traits\{QueryCacheableConfig,ScopeActive};
|
||||||
|
|
||||||
/**
|
|
||||||
* This represents an FTN Domain.
|
|
||||||
*
|
|
||||||
* We are either a member of the domain (because we have an AKA in it) or NOT.
|
|
||||||
*
|
|
||||||
* The assumption is, if we are a member of the domain, we receive/send mail to an uplink and possibly downlinks
|
|
||||||
*/
|
|
||||||
class Domain extends Model
|
class Domain extends Model
|
||||||
{
|
{
|
||||||
use HasFactory,QueryCacheableConfig,ScopeActive;
|
use HasFactory,QueryCacheableConfig,ScopeActive;
|
||||||
@ -35,30 +28,26 @@ class Domain extends Model
|
|||||||
/* SCOPES */
|
/* SCOPES */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A domain is public (visible), if the user is an admin or, the domain is marked public)
|
* Only query active records
|
||||||
*/
|
*/
|
||||||
public function scopePublic($query)
|
public function scopePublic($query)
|
||||||
{
|
{
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|
||||||
return $query
|
return $query
|
||||||
->active()
|
->when(((! $user) || (! $user->isAdmin())),function($query) { return $query->where('public',TRUE)->active(); });
|
||||||
->when((! $user) || (! $user->isAdmin()),
|
|
||||||
fn($query)=>$query->where('public',TRUE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RELATIONS */
|
/* RELATIONS */
|
||||||
|
|
||||||
public function echoareas()
|
public function echoareas()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Echoarea::class)
|
return $this->hasMany(Echoarea::class);
|
||||||
->orderBy('name');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fileareas()
|
public function fileareas()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Filearea::class)
|
return $this->hasMany(Filearea::class);
|
||||||
->orderBy('name');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function nodelist_filearea()
|
public function nodelist_filearea()
|
||||||
@ -66,7 +55,7 @@ class Domain extends Model
|
|||||||
return $this->belongsTo(Filearea::class);
|
return $this->belongsTo(Filearea::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function nodestatus_echoarea()
|
public function nodestatusarea()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Echoarea::class,'nodestatus_id');
|
return $this->belongsTo(Echoarea::class,'nodestatus_id');
|
||||||
}
|
}
|
||||||
@ -74,47 +63,38 @@ class Domain extends Model
|
|||||||
public function zones()
|
public function zones()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Zone::class)
|
return $this->hasMany(Zone::class)
|
||||||
->select(['id','zone_id','domain_id','active'])
|
->select(['id','zone_id','domain_id']);
|
||||||
->orderBy('zone_id');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ATTRIBUTES */
|
/* ATTRIBUTES */
|
||||||
|
|
||||||
/**
|
|
||||||
* We can accept applications if we have an address in the domain
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function getCanAcceptAppAttribute(): bool
|
public function getCanAcceptAppAttribute(): bool
|
||||||
{
|
{
|
||||||
return $this->isManaged()
|
return ($x=our_address($this))
|
||||||
|
&& $x->count()
|
||||||
|
&& $this->active
|
||||||
&& $this->accept_app
|
&& $this->accept_app
|
||||||
&& Auth::id();
|
&& Auth::id()
|
||||||
|
&& $this->userHasSystemsNotInNet(Auth::user())->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHomePageAttribute(?string $value): string
|
public function getHomePageAttribute(?string $value): string
|
||||||
{
|
{
|
||||||
|
//0xFD2FB528
|
||||||
return $this->castAttribute('homepage',$value) ?: 'No available information at the moment.';
|
return $this->castAttribute('homepage',$value) ?: 'No available information at the moment.';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* METHODS */
|
/* METHODS */
|
||||||
|
|
||||||
/**
|
|
||||||
* Show count of messages by day/week/month/all stats for each echoarea in this domain
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function echoarea_stats(): Collection
|
public function echoarea_stats(): Collection
|
||||||
{
|
{
|
||||||
return Cache::remember(md5(sprintf('%d-%s',$this->id,__METHOD__)),self::CACHE_TIME,function() {
|
|
||||||
$dt = Carbon::now()->startOfday();
|
$dt = Carbon::now()->startOfday();
|
||||||
$case = CaseBuilder::whenRaw("datetime >= '?'",$dt->subDay()->format('Y-m-d'))->thenRaw("'day'")
|
$case = CaseBuilder::whenRaw("datetime >= '?'",$dt->subDay()->format('Y-m-d'))->thenRaw("'day'")
|
||||||
->whenRaw("datetime >= '?'",$dt->subDays(7)->format('Y-m-d'))->thenRaw("'week'")
|
->whenRaw("datetime >= '?'",$dt->subDays(7)->format('Y-m-d'))->thenRaw("'week'")
|
||||||
->whenRaw("datetime >= '?'",$dt->subMonth()->format('Y-m-d'))->thenRaw("'month'")
|
->whenRaw("datetime >= '?'",$dt->subMonth()->format('Y-m-d'))->thenRaw("'month'")
|
||||||
->elseRaw("'all'");
|
->elseRaw("'all'");
|
||||||
|
|
||||||
return Echoarea::select(['echoareas.id','name','description','active',DB::raw('count(echomails.id) AS count'),DB::raw('min(datetime) as first_message'),DB::raw('max(datetime) as last_message')])
|
return Echoarea::select(['echoareas.id','name','description','active',DB::raw('count(echomails.id) AS count'),DB::raw('max(datetime) as last_message')])
|
||||||
->selectRaw($case->toRaw().' AS stats')
|
->selectRaw($case->toRaw().' AS stats')
|
||||||
->join('echomails',['echomails.echoarea_id'=>'echoareas.id'],NULL,NULL,'left outer')
|
->join('echomails',['echomails.echoarea_id'=>'echoareas.id'],NULL,NULL,'left outer')
|
||||||
->where('domain_id',$this->id)
|
->where('domain_id',$this->id)
|
||||||
@ -124,26 +104,19 @@ class Domain extends Model
|
|||||||
->orderBy('echoareas.name')
|
->orderBy('echoareas.name')
|
||||||
->orderBy('last_message','DESC')
|
->orderBy('last_message','DESC')
|
||||||
->get();
|
->get();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Show daily total of messages by echoarea in this domain
|
|
||||||
*
|
|
||||||
* @param Collection|NULL $systems
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function echoarea_total_daily(Collection $systems=NULL): Collection
|
public function echoarea_total_daily(Collection $systems=NULL): Collection
|
||||||
{
|
{
|
||||||
return Cache::remember(md5(sprintf('%d-%s',$this->id,$systems?->pluck('id')->join(','))),self::CACHE_TIME,function() use ($systems) {
|
return Cache::remember(md5(sprintf('%d-%s',$this->id,$systems?->pluck('id')->join(','))),self::CACHE_TIME,function() use ($systems) {
|
||||||
return DB::query()
|
return DB::query()
|
||||||
->select(['echoareas.name','echoareas.show',DB::raw('COUNT(echoareas.name) AS count'),DB::raw('datetime::date AS date')])
|
->select(['echoareas.name','echoareas.show',DB::raw('COUNT(*) AS count'),DB::raw('datetime::date AS date')])
|
||||||
->from($this->getTable())
|
->from($this->getTable())
|
||||||
->join('echoareas',['echoareas.domain_id'=>'domains.id'])
|
->join('echoareas',['echoareas.domain_id'=>'domains.id'])
|
||||||
->join('echomails',['echomails.echoarea_id'=>'echoareas.id'])
|
->join('echomails',['echomails.echoarea_id'=>'echoareas.id'])
|
||||||
->where('domains.id',$this->id)
|
->where('domains.id',$this->id)
|
||||||
->where('echomails.datetime','>=',Carbon::now()->subMonths(self::STATS_MONTHS)->startOfMonth())
|
->where('echomails.datetime','>=',Carbon::now()->subMonths(self::STATS_MONTHS)->startOfMonth())
|
||||||
->when($systems?->count(),fn($query)=>$query->whereIn('echomails.fftn_id',$systems->pluck('addresses')->flatten()->pluck('id')))
|
->when($systems?->count(),function($query) use ($systems) { return $query->whereIn('echomails.fftn_id',$systems->pluck('addresses')->flatten()->pluck('id')); })
|
||||||
->groupBy(['echoareas.name','echoareas.show','date'])
|
->groupBy(['echoareas.name','echoareas.show','date'])
|
||||||
->orderBy('echoareas.name')
|
->orderBy('echoareas.name')
|
||||||
->orderBy('date')
|
->orderBy('date')
|
||||||
@ -151,30 +124,6 @@ class Domain extends Model
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Show count of files by week/month/all status for each filearea in this domain
|
|
||||||
*/
|
|
||||||
public function filearea_stats()
|
|
||||||
{
|
|
||||||
return Cache::remember(md5(sprintf('%d-%s',$this->id,__METHOD__)),self::CACHE_TIME,function() {
|
|
||||||
$dt = Carbon::now()->startOfday();
|
|
||||||
$case = CaseBuilder::whenRaw("datetime >= '?'",$dt->subDays(7)->format('Y-m-d'))->thenRaw("'week'")
|
|
||||||
->whenRaw("datetime >= '?'",$dt->subMonth()->format('Y-m-d'))->thenRaw("'month'")
|
|
||||||
->elseRaw("'all'");
|
|
||||||
|
|
||||||
return Filearea::select(['fileareas.id','fileareas.name','description','active',DB::raw('count(files.id) AS count'),DB::raw('min(datetime) as first_file'),DB::raw('max(datetime) as last_file')])
|
|
||||||
->selectRaw($case->toRaw().' AS stats')
|
|
||||||
->join('files',['files.filearea_id'=>'fileareas.id'],NULL,NULL,'left outer')
|
|
||||||
->where('domain_id',$this->id)
|
|
||||||
->groupBy('fileareas.id')
|
|
||||||
->groupBy('fileareas.name')
|
|
||||||
->groupBy('stats')
|
|
||||||
->orderBy('fileareas.name')
|
|
||||||
->orderBy('last_file','DESC')
|
|
||||||
->get();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if this zone is managed by this host
|
* Determine if this zone is managed by this host
|
||||||
*
|
*
|
||||||
@ -183,6 +132,28 @@ class Domain extends Model
|
|||||||
*/
|
*/
|
||||||
public function isManaged(): bool
|
public function isManaged(): bool
|
||||||
{
|
{
|
||||||
return our_address($this)->count() > 0;
|
return ($x=our_address())
|
||||||
|
&& $x->pluck('zone.domain')
|
||||||
|
->pluck('id')
|
||||||
|
->contains($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Work out which of the users systems are not in this domain
|
||||||
|
*
|
||||||
|
* @param User $o
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function userHasSystemsNotInNet(User $o): Collection
|
||||||
|
{
|
||||||
|
$o->load('systems.akas.zone');
|
||||||
|
|
||||||
|
$result = collect();
|
||||||
|
foreach ($o->systems->filter(function($item) { return $item->active; }) as $so) {
|
||||||
|
if (! $so->akas->pluck('zone')->unique('domain_id')->pluck('domain_id')->contains($this->id))
|
||||||
|
$result->push($so);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ namespace App\Models;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
use App\Models\Casts\CollectionOrNull;
|
use App\Casts\CollectionOrNull;
|
||||||
|
|
||||||
class Dynamic extends Model
|
class Dynamic extends Model
|
||||||
{
|
{
|
||||||
|
@ -46,8 +46,7 @@ class Echoarea extends Model
|
|||||||
private const CACHE_TIME = 3600;
|
private const CACHE_TIME = 3600;
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'first_message' => 'datetime:Y-m-d H:i:s',
|
'last_message' => 'datetime:Y-m-d H:i:s'
|
||||||
'last_message' => 'datetime:Y-m-d H:i:s',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/* RELATIONS */
|
/* RELATIONS */
|
||||||
|
@ -9,10 +9,10 @@ use Illuminate\Support\Collection;
|
|||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
use App\Casts\{CollectionOrNull,CompressedStringOrNull,UTF8StringOrNull};
|
||||||
use App\Classes\FTN\Message;
|
use App\Classes\FTN\Message;
|
||||||
use App\Events\Echomail as EchomailEvent;
|
use App\Events\Echomail as EchomailEvent;
|
||||||
use App\Interfaces\Packet;
|
use App\Interfaces\Packet;
|
||||||
use App\Models\Casts\{CompressedStringOrNull,CollectionOrNull,UTF8StringOrNull};
|
|
||||||
use App\Traits\{MessageAttributes,MsgID,ParseAddresses,QueryCacheableConfig};
|
use App\Traits\{MessageAttributes,MsgID,ParseAddresses,QueryCacheableConfig};
|
||||||
|
|
||||||
final class Echomail extends Model implements Packet
|
final class Echomail extends Model implements Packet
|
||||||
@ -150,7 +150,7 @@ final class Echomail extends Model implements Packet
|
|||||||
// Make sure our origin contains our FTN
|
// Make sure our origin contains our FTN
|
||||||
$m = [];
|
$m = [];
|
||||||
if ((preg_match('#^(.*)\s+\(([0-9]+:[0-9]+/[0-9]+.*)\)+\s*$#',$model->set_origin,$m))
|
if ((preg_match('#^(.*)\s+\(([0-9]+:[0-9]+/[0-9]+.*)\)+\s*$#',$model->set_origin,$m))
|
||||||
&& (Address::findFTN(sprintf('%s@%s',$m[2],$model->fftn->domain->name),TRUE,TRUE)?->id === $model->fftn_id))
|
&& (Address::findFTN(sprintf('%s@%s',$m[2],$model->fftn->domain->name))?->id === $model->fftn_id))
|
||||||
{
|
{
|
||||||
$x = Origin::where('value',utf8_encode($m[1]))->single();
|
$x = Origin::where('value',utf8_encode($m[1]))->single();
|
||||||
|
|
||||||
@ -184,13 +184,13 @@ final class Echomail extends Model implements Packet
|
|||||||
Log::debug(sprintf('%s:^ Message [%d] from point address is [%d]',self::LOGKEY,$model->id,$model->fftn->point_id));
|
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
|
// Make sure our sender is first in the path
|
||||||
if (($model->fftn->point_id === 0) && (! $model->isFlagSet(Message::FLAG_LOCAL)) && (! $path->contains($model->fftn_id))) {
|
if ((! $model->isFlagSet(Message::FLAG_LOCAL)) && (! $path->contains($model->fftn_id))) {
|
||||||
Log::alert(sprintf('%s:? Echomail adding sender to start of PATH [%s].',self::LOGKEY,$model->fftn_id));
|
Log::alert(sprintf('%s:? Echomail adding sender to start of PATH [%s].',self::LOGKEY,$model->fftn_id));
|
||||||
$path->prepend($model->fftn_id);
|
$path->prepend($model->fftn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure our pktsrc is last in the path
|
// Make sure our pktsrc is last in the path
|
||||||
if ($model->set->has('set_sender') && (! $path->contains($model->set->get('set_sender')->id)) && ($model->set->get('set_sender')->point_id === 0)) {
|
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));
|
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);
|
$path->push($model->set->get('set_sender')->id);
|
||||||
}
|
}
|
||||||
@ -215,13 +215,13 @@ final class Echomail extends Model implements Packet
|
|||||||
$seenby = self::parseAddresses('seenby',$model->set->get('set_seenby'),$model->fftn->zone,$rogue);
|
$seenby = self::parseAddresses('seenby',$model->set->get('set_seenby'),$model->fftn->zone,$rogue);
|
||||||
|
|
||||||
// Make sure our sender is in the seenby
|
// Make sure our sender is in the seenby
|
||||||
if (($model->fftn->point_id === 0) && (! $model->isFlagSet(Message::FLAG_LOCAL)) && (! $seenby->contains($model->fftn_id))) {
|
if ((! $model->isFlagSet(Message::FLAG_LOCAL)) && (! $seenby->contains($model->fftn_id))) {
|
||||||
Log::alert(sprintf('%s:? Echomail adding sender to SEENBY [%s].',self::LOGKEY,$model->fftn_id));
|
Log::alert(sprintf('%s:? Echomail adding sender to SEENBY [%s].',self::LOGKEY,$model->fftn_id));
|
||||||
$seenby->push($model->fftn_id);
|
$seenby->push($model->fftn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure our pktsrc is in the seenby
|
// Make sure our pktsrc is in the seenby
|
||||||
if ($model->set->has('set_sender') && (! $seenby->contains($model->set->get('set_sender')->id)) && ($model->set->get('set_sender')->point_id === 0)) {
|
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));
|
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);
|
$seenby->push($model->set->get('set_sender')->id);
|
||||||
}
|
}
|
||||||
@ -250,7 +250,6 @@ final class Echomail extends Model implements Packet
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See if we need to export this message.
|
// See if we need to export this message.
|
||||||
// @todo We need to limit exporting if address/system is not active
|
|
||||||
if ($model->echoarea->sec_read) {
|
if ($model->echoarea->sec_read) {
|
||||||
$exportto = $model
|
$exportto = $model
|
||||||
->echoarea
|
->echoarea
|
||||||
@ -291,7 +290,6 @@ final class Echomail extends Model implements Packet
|
|||||||
return $this->belongsToMany(Address::class,'echomail_seenby')
|
return $this->belongsToMany(Address::class,'echomail_seenby')
|
||||||
->select(['id','zone_id','host_id','node_id'])
|
->select(['id','zone_id','host_id','node_id'])
|
||||||
->withPivot(['export_at','sent_at','sent_pkt'])
|
->withPivot(['export_at','sent_at','sent_pkt'])
|
||||||
->dontCache()
|
|
||||||
->FTN2DOrder();
|
->FTN2DOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ use Illuminate\Support\Facades\DB;
|
|||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
use App\Models\Casts\{CompressedStringOrNull,CollectionOrNull};
|
use App\Casts\{CollectionOrNull,CompressedStringOrNull};
|
||||||
|
|
||||||
class File extends Model
|
class File extends Model
|
||||||
{
|
{
|
||||||
|
@ -11,11 +11,6 @@ class Filearea extends Model
|
|||||||
{
|
{
|
||||||
use SoftDeletes,ScopeActive,AreaSecurity;
|
use SoftDeletes,ScopeActive,AreaSecurity;
|
||||||
|
|
||||||
protected $casts = [
|
|
||||||
'first_file' => 'datetime:Y-m-d H:i:s',
|
|
||||||
'last_file' => 'datetime:Y-m-d H:i:s',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'name',
|
'name',
|
||||||
];
|
];
|
||||||
@ -31,9 +26,4 @@ class Filearea extends Model
|
|||||||
{
|
{
|
||||||
return $this->belongsTo(Domain::class);
|
return $this->belongsTo(Domain::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function files()
|
|
||||||
{
|
|
||||||
return $this->hasMany(File::class);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -10,9 +10,9 @@ use Illuminate\Support\Collection;
|
|||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
use App\Casts\{CollectionOrNull,CompressedStringOrNull,UTF8StringOrNull};
|
||||||
use App\Interfaces\Packet;
|
use App\Interfaces\Packet;
|
||||||
use App\Models\Casts\{CompressedStringOrNull,CollectionOrNull,UTF8StringOrNull};
|
use App\Pivots\ViaPivot;
|
||||||
use App\Models\Pivots\ViaPivot;
|
|
||||||
use App\Traits\{MessageAttributes,MsgID};
|
use App\Traits\{MessageAttributes,MsgID};
|
||||||
|
|
||||||
final class Netmail extends Model implements Packet
|
final class Netmail extends Model implements Packet
|
||||||
@ -21,7 +21,7 @@ final class Netmail extends Model implements Packet
|
|||||||
|
|
||||||
private const LOGKEY = 'MN-';
|
private const LOGKEY = 'MN-';
|
||||||
public const UPDATED_AT = NULL;
|
public const UPDATED_AT = NULL;
|
||||||
private const PATH_REGEX = '/^([0-9]+:[0-9]+\/[0-9]+(\.?[0-9@a-zA-Z]*)?)\s+@([0-9.a-zA-Z]+)\s+(.*)$/';
|
private const PATH_REGEX = '/^([0-9]+:[0-9]+\/[0-9]+(\..*)?)\s+@([0-9.a-zA-Z]+)\s+(.*)$/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kludges that we absorb in this model
|
* Kludges that we absorb in this model
|
||||||
@ -46,12 +46,6 @@ final class Netmail extends Model implements Packet
|
|||||||
public function __get($key)
|
public function __get($key)
|
||||||
{
|
{
|
||||||
switch ($key) {
|
switch ($key) {
|
||||||
case 'get_fftn':
|
|
||||||
return $this->set->get('set_fftn') ?: $this->fftn->ftn;
|
|
||||||
|
|
||||||
case 'get_tftn':
|
|
||||||
return $this->set->get('set_tftn') ?: $this->tftn->ftn;
|
|
||||||
|
|
||||||
case 'set_fftn':
|
case 'set_fftn':
|
||||||
case 'set_tftn':
|
case 'set_tftn':
|
||||||
case 'set_path':
|
case 'set_path':
|
||||||
@ -148,7 +142,7 @@ final class Netmail extends Model implements Packet
|
|||||||
// Make sure our origin contains our FTN
|
// Make sure our origin contains our FTN
|
||||||
$m = [];
|
$m = [];
|
||||||
if ((preg_match('#^(.*)\s+\(([0-9]+:[0-9]+/[0-9]+.*)\)+\s*$#',$model->set_origin,$m))
|
if ((preg_match('#^(.*)\s+\(([0-9]+:[0-9]+/[0-9]+.*)\)+\s*$#',$model->set_origin,$m))
|
||||||
&& (Address::findFTN(sprintf('%s@%s',$m[2],$model->fftn->domain->name),TRUE,TRUE)?->id === $model->fftn_id))
|
&& (Address::findFTN(sprintf('%s@%s',$m[2],$model->fftn->domain->name))?->id === $model->fftn_id))
|
||||||
{
|
{
|
||||||
$x = Origin::where('value',utf8_encode($m[1]))->single();
|
$x = Origin::where('value',utf8_encode($m[1]))->single();
|
||||||
|
|
||||||
@ -247,11 +241,6 @@ final class Netmail extends Model implements Packet
|
|||||||
->using(ViaPivot::class);
|
->using(ViaPivot::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sent()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Address::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tftn()
|
public function tftn()
|
||||||
{
|
{
|
||||||
return $this
|
return $this
|
||||||
@ -277,16 +266,6 @@ final class Netmail extends Model implements Packet
|
|||||||
: $this->getRelationValue('path');
|
: $this->getRelationValue('path');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Split the body of a message into a collection of lines.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getBodyLinesAttribute(): array
|
|
||||||
{
|
|
||||||
return explode("\r",$this->msg_src);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* METHODS */
|
/* METHODS */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
use App\Models\Casts\UTF8StringOrNull;
|
use App\Casts\UTF8StringOrNull;
|
||||||
|
|
||||||
class Origin extends Model
|
class Origin extends Model
|
||||||
{
|
{
|
||||||
|
@ -71,6 +71,9 @@ class Setup extends Model
|
|||||||
case 'msgs_pkt':
|
case 'msgs_pkt':
|
||||||
return Arr::get($this->options,$key,self::MAX_MSGS_PKT);
|
return Arr::get($this->options,$key,self::MAX_MSGS_PKT);
|
||||||
|
|
||||||
|
case 'version':
|
||||||
|
return File::exists('VERSION') ? chop(File::get('VERSION')) : 'dev';
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return parent::__get($key);
|
return parent::__get($key);
|
||||||
}
|
}
|
||||||
@ -110,16 +113,6 @@ class Setup extends Model
|
|||||||
return hexstr($c);
|
return hexstr($c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Application version
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function version(): string
|
|
||||||
{
|
|
||||||
return File::exists('VERSION') ? chop(File::get('VERSION')) : 'dev';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RELATIONS */
|
/* RELATIONS */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@ -48,39 +47,35 @@ class System extends Model
|
|||||||
$uo = Auth::user();
|
$uo = Auth::user();
|
||||||
|
|
||||||
return $query
|
return $query
|
||||||
->when(
|
->when($uo && ! $uo->isAdmin(),function($query) use ($uo) {
|
||||||
$uo && ! $uo->isAdmin(),
|
return $query->whereIn('id',$uo->systems->pluck('id'))
|
||||||
fn($query)=>
|
->orWhere($this->getTable().'.active',TRUE);
|
||||||
$query
|
},function($query) { $query->where($this->getTable().'.active',TRUE); })
|
||||||
->whereIn('id',$uo->systems->pluck('id'))
|
|
||||||
->orWhere($this->getTable().'.active',TRUE),
|
|
||||||
fn($query)=>$query->where($this->getTable().'.active',TRUE))
|
|
||||||
->orderBy('name');
|
->orderBy('name');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RELATIONS */
|
/* RELATIONS */
|
||||||
|
|
||||||
/**
|
|
||||||
* All addresses assigned to a system, including addresses pending deletion
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function addresses()
|
public function addresses()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Address::class)
|
return $this->hasMany(Address::class)
|
||||||
->FTN()
|
->withTrashed()
|
||||||
->withTrashed();
|
->FTNorder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* System addresses that are active
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function akas()
|
public function akas()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Address::class)
|
return $this->hasMany(Address::class)
|
||||||
->FTN()
|
->select('addresses.*')
|
||||||
->ActiveFTN();
|
->join('zones',['zones.id'=>'addresses.zone_id'])
|
||||||
|
->join('domains',['domains.id'=>'zones.domain_id'])
|
||||||
|
->where('addresses.active',TRUE)
|
||||||
|
->where('zones.active',TRUE)
|
||||||
|
->where('domains.active',TRUE)
|
||||||
|
->orderBy('domains.name')
|
||||||
|
->with(['zone.domain'])
|
||||||
|
->FTNorder()
|
||||||
|
->orderBy('role','ASC');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mailers()
|
public function mailers()
|
||||||
@ -115,10 +110,9 @@ class System extends Model
|
|||||||
public function sessions()
|
public function sessions()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Zone::class)
|
return $this->belongsToMany(Zone::class)
|
||||||
->select(['zones.id','zones.zone_id','domain_id','zones.active'])
|
->select(['id','zones.zone_id','domain_id','active'])
|
||||||
->join('domains',['domains.id'=>'zones.domain_id'])
|
|
||||||
->withPivot(['sespass','pktpass','ticpass','fixpass','zt_ipv4','zt_ipv6','default'])
|
->withPivot(['sespass','pktpass','ticpass','fixpass','zt_ipv4','zt_ipv6','default'])
|
||||||
->orderBy('domains.name');
|
->dontCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,14 +135,7 @@ class System extends Model
|
|||||||
*/
|
*/
|
||||||
public function zcs()
|
public function zcs()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Zone::class)
|
return $this->hasMany(Zone::class);
|
||||||
->select(['zones.id','zone_id','domain_id','system_id','zones.active'])
|
|
||||||
->join('domains',['domains.id'=>'zones.domain_id'])
|
|
||||||
->orderBy('domains.name')
|
|
||||||
->orderBy('zone_id')
|
|
||||||
->with([
|
|
||||||
'domain:id,name,active',
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -194,73 +181,8 @@ class System extends Model
|
|||||||
return $val ?: Setup::findOrFail(config('app.id'))->msgs_pkt;
|
return $val ?: Setup::findOrFail(config('app.id'))->msgs_pkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLastSeenAttribute(): ?Carbon
|
|
||||||
{
|
|
||||||
return $this->logs_recent->first()?->created_at;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* METHODS */
|
/* METHODS */
|
||||||
|
|
||||||
public function addresses_common(): Collection
|
|
||||||
{
|
|
||||||
$our = our_address()->pluck('zone.domain_id')->unique();
|
|
||||||
|
|
||||||
// Return our akas, filter with our_addresses()
|
|
||||||
return $this->addresses->filter(fn($item)=>$our->contains($item->zone->domain_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the ACTIVE addresses that are common with our addresses
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function aka_common(): Collection
|
|
||||||
{
|
|
||||||
$our = our_address()->pluck('zone.domain_id')->unique();
|
|
||||||
|
|
||||||
// Return our akas, filter with our_addresses()
|
|
||||||
return $this->akas->filter(fn($item)=>$our->contains($item->zone->domain_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the ACTIVE addresses that we auth with
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function aka_known(): Collection
|
|
||||||
{
|
|
||||||
return $this->aka_common()
|
|
||||||
->filter(fn($item)=>$this->sessions->contains($item->zone_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the ACTIVE addresses in the same networks as us, but dont auth here
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function aka_unknown(): Collection
|
|
||||||
{
|
|
||||||
return $this->aka_common()
|
|
||||||
->filter(fn($item)=>! $this->sessions->contains($item->zone_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the AKAs that are in networks not common with us
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function aka_uncommon(): Collection
|
|
||||||
{
|
|
||||||
$our = our_address()->pluck('zone.domain_id')->unique();
|
|
||||||
|
|
||||||
// Return our akas, filter with our_addresses()
|
|
||||||
return $this->akas->filter(fn($item)=>! $our->contains($item->zone->domain_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function echoareas()
|
public function echoareas()
|
||||||
{
|
{
|
||||||
return Echoarea::select('echoareas.*')
|
return Echoarea::select('echoareas.*')
|
||||||
@ -302,13 +224,6 @@ class System extends Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function inDomain(Domain $o): bool
|
|
||||||
{
|
|
||||||
return $this->addresses
|
|
||||||
->filter(fn($item)=>$item->zone->domain_id === $o->id)
|
|
||||||
->count() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the system's address in the same zone
|
* Return the system's address in the same zone
|
||||||
* This function can filter based on the address type needed.
|
* This function can filter based on the address type needed.
|
||||||
@ -329,18 +244,32 @@ class System extends Model
|
|||||||
: $akas;
|
: $akas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the addresses and return which ones are in my zones
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Collection $addresses
|
||||||
|
* @param int $type
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function inMyZones(Collection $addresses,int $type=(Address::NODE_HC|Address::NODE_NN|Address::NODE_POINT)): Collection
|
||||||
|
{
|
||||||
|
$myzones = $this->addresses->pluck('zone_id')->unique();
|
||||||
|
|
||||||
|
return $addresses->filter(function($item) use ($myzones,$type) {
|
||||||
|
return ($item->role & $type) && ($myzones->search($item->zone_id) !== FALSE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the packet that this system uses
|
* Return the packet that this system uses
|
||||||
*
|
*
|
||||||
* @param Address $ao
|
* @param Address $ao
|
||||||
* @param string|null $password
|
* @param string|null $password
|
||||||
* @return Packet
|
* @return Packet
|
||||||
* @throws \Exception
|
|
||||||
*/
|
*/
|
||||||
public function packet(Address $ao,string $password=NULL): Packet
|
public function packet(Address $ao,string $password=NULL): Packet
|
||||||
{
|
{
|
||||||
if ($ao->system_id !== $this->id)
|
// @todo Check that the address is one of the system's addresses
|
||||||
throw new \Exception('Packet for [%s] is not for system [%d]',$ao->ftn,$this->id);
|
|
||||||
|
|
||||||
return
|
return
|
||||||
(new (collect(Packet::PACKET_TYPES)
|
(new (collect(Packet::PACKET_TYPES)
|
||||||
@ -353,7 +282,21 @@ class System extends Model
|
|||||||
{
|
{
|
||||||
return Job::where('queue',AddressPoll::QUEUE)
|
return Job::where('queue',AddressPoll::QUEUE)
|
||||||
->get()
|
->get()
|
||||||
->where(fn($item)=>$this->akas->pluck('id')->contains($item->command->address->id))
|
->where(function($item) {
|
||||||
|
return $this->akas->pluck('id')->search($item->command->address->id) !== FALSE; })
|
||||||
->last();
|
->last();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return other addresses that are no collected here, but are on the same network as us.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function uncommon(): Collection
|
||||||
|
{
|
||||||
|
$our = our_address();
|
||||||
|
|
||||||
|
return $this->akas->filter(fn($item)=>($item->parent() && (! $our->contains($item->parent()))));
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
use App\Models\Casts\UTF8StringOrNull;
|
use App\Casts\UTF8StringOrNull;
|
||||||
|
|
||||||
class Tagline extends Model
|
class Tagline extends Model
|
||||||
{
|
{
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
use App\Models\Casts\UTF8StringOrNull;
|
use App\Casts\UTF8StringOrNull;
|
||||||
|
|
||||||
class Tearline extends Model
|
class Tearline extends Model
|
||||||
{
|
{
|
||||||
|
@ -75,14 +75,19 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
|
|
||||||
/* GENERAL METHODS */
|
/* GENERAL METHODS */
|
||||||
|
|
||||||
public function addresses(): Collection
|
public function addresses(Domain $o=NULL): Collection
|
||||||
{
|
{
|
||||||
return Address::select('addresses.*')
|
return Address::select('addresses.*')
|
||||||
->join('systems',['systems.id'=>'addresses.system_id'])
|
->join('systems',['systems.id'=>'addresses.system_id'])
|
||||||
->join('system_user',['system_user.system_id'=>'systems.id'])
|
->join('system_user',['system_user.system_id'=>'systems.id'])
|
||||||
|
->when(! is_null($o),function($query) use ($o) {
|
||||||
|
return $query
|
||||||
|
->join('zones',['zones.id'=>'addresses.zone_id'])
|
||||||
|
->where('zones.domain_id',$o->id);
|
||||||
|
})
|
||||||
->where('system_user.user_id',$this->id)
|
->where('system_user.user_id',$this->id)
|
||||||
->ActiveFTN()
|
->activeFTN()
|
||||||
->FTN()
|
->with(['zone.domain'])
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
|||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
use App\Classes\FTN\Message;
|
use App\Classes\FTN\Message;
|
||||||
use App\Models\{Echoarea,Echomail,Netmail,Setup};
|
use App\Models\{Echoarea,Echomail,Setup};
|
||||||
|
|
||||||
abstract class Echomails extends Notification //implements ShouldQueue
|
abstract class Echomails extends Notification //implements ShouldQueue
|
||||||
{
|
{
|
||||||
@ -53,8 +53,8 @@ abstract class Echomails extends Notification //implements ShouldQueue
|
|||||||
|
|
||||||
$o->echoarea_id = $eo->id;
|
$o->echoarea_id = $eo->id;
|
||||||
|
|
||||||
$o->datetime = Carbon::now()->utc();
|
$o->datetime = Carbon::now();
|
||||||
$o->tzoffset = Carbon::now()->utcOffset();
|
$o->tzoffset = $o->datetime->utcOffset();
|
||||||
|
|
||||||
$o->flags = (Message::FLAG_LOCAL);
|
$o->flags = (Message::FLAG_LOCAL);
|
||||||
|
|
||||||
@ -62,13 +62,4 @@ abstract class Echomails extends Notification //implements ShouldQueue
|
|||||||
|
|
||||||
return $o;
|
return $o;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function sourceSummary(Echomail|Netmail $o,string $item=NULL): string
|
|
||||||
{
|
|
||||||
return sprintf("Your %s was received here on [%s] and it looks like you sent it on [%s].",
|
|
||||||
$item ?: sprintf('%s with ID [%s] to [%s]',$o instanceof Netmail ? 'Netmail' : 'Echomail',$o->msgid,$o->to),
|
|
||||||
Carbon::now()->utc()->toDateTimeString(),
|
|
||||||
$o->date->utc()->toDateTimeString(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user