2019-05-11 01:17:56 +00:00
|
|
|
<?php
|
|
|
|
|
2023-06-27 07:39:11 +00:00
|
|
|
use Carbon\Carbon;
|
|
|
|
use Illuminate\Support\Collection;
|
|
|
|
|
2023-12-12 21:41:15 +00:00
|
|
|
use App\Models\{Address,Domain,Setup,Zone};
|
2023-12-03 07:18:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate CCITT-CRC16 checksum
|
|
|
|
*/
|
2019-05-11 01:17:56 +00:00
|
|
|
if (! function_exists('crc16')) {
|
2023-06-27 07:39:11 +00:00
|
|
|
function crc16($data): int
|
|
|
|
{
|
|
|
|
$crc = 0x0000;
|
2023-11-18 05:57:30 +00:00
|
|
|
|
2023-06-27 07:39:11 +00:00
|
|
|
for ($i = 0; $i < strlen($data); $i++) {
|
|
|
|
$x = (($crc >> 8) ^ ord($data[$i])) & 0xFF;
|
|
|
|
$x ^= $x >> 4;
|
|
|
|
$crc = (($crc << 8) ^ ($x << 12) ^ ($x << 5) ^ $x) & 0xFFFF;
|
|
|
|
}
|
2023-11-18 05:57:30 +00:00
|
|
|
|
2023-06-27 07:39:11 +00:00
|
|
|
return $crc;
|
|
|
|
}
|
2019-05-11 01:17:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dump out data into a hex dump
|
|
|
|
*/
|
|
|
|
if (! function_exists('hex_dump')) {
|
2022-02-12 23:24:31 +00:00
|
|
|
function hex_dump($data,$newline="\n",$width=16): string
|
2019-05-11 01:17:56 +00:00
|
|
|
{
|
|
|
|
$result = '';
|
|
|
|
|
|
|
|
$pad = '.'; # padding for non-visible characters
|
|
|
|
$to = $from = '';
|
|
|
|
|
2022-02-12 23:24:31 +00:00
|
|
|
for ($i=0; $i<=0xFF; $i++) {
|
2019-05-11 01:17:56 +00:00
|
|
|
$from .= chr($i);
|
|
|
|
$to .= ($i >= 0x20 && $i <= 0x7E) ? chr($i) : $pad;
|
|
|
|
}
|
|
|
|
|
|
|
|
$hex = str_split(bin2hex($data),$width*2);
|
|
|
|
$chars = str_split(strtr($data,$from,$to),$width);
|
|
|
|
|
|
|
|
$offset = 0;
|
2022-02-12 23:24:31 +00:00
|
|
|
foreach ($hex as $i => $line) {
|
2019-05-11 01:17:56 +00:00
|
|
|
$result .= sprintf('%08X: %-48s [%s]%s',
|
|
|
|
$offset,
|
|
|
|
substr_replace(implode(' ',str_split($line,2)),' ',8*3,0),
|
|
|
|
$chars[$i],
|
|
|
|
$newline);
|
|
|
|
|
|
|
|
$offset += $width;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
2019-05-20 07:18:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-07-21 10:52:17 +00:00
|
|
|
* Send a value has hex chars
|
2019-05-20 07:18:18 +00:00
|
|
|
*/
|
2021-07-21 10:52:17 +00:00
|
|
|
if (! function_exists('hexstr')) {
|
2022-02-12 23:24:31 +00:00
|
|
|
function hexstr(int $int): string
|
2019-05-20 07:18:18 +00:00
|
|
|
{
|
2021-07-21 10:52:17 +00:00
|
|
|
if ($int > 0xffff)
|
|
|
|
throw new Exception('Int too large for hexstr');
|
2019-05-20 07:18:18 +00:00
|
|
|
|
2021-07-21 10:52:17 +00:00
|
|
|
$hexdigitslower = '0123456789abcdef';
|
|
|
|
$x = '';
|
2019-05-20 07:18:18 +00:00
|
|
|
|
2021-07-21 10:52:17 +00:00
|
|
|
if ($int > 0xff) {
|
|
|
|
$x .= substr($hexdigitslower,($int&0xf000)>>12,1);
|
|
|
|
$x .= substr($hexdigitslower,($int&0x0f00)>>8,1);
|
|
|
|
}
|
2019-05-20 07:18:18 +00:00
|
|
|
|
2021-07-21 10:52:17 +00:00
|
|
|
$x .= substr($hexdigitslower,($int&0x00f0)>>4,1);
|
|
|
|
$x .= substr($hexdigitslower,($int&0x000f),1);
|
2019-05-20 07:18:18 +00:00
|
|
|
|
2021-07-21 10:52:17 +00:00
|
|
|
return $x;
|
2019-05-20 07:18:18 +00:00
|
|
|
}
|
2021-07-23 14:53:35 +00:00
|
|
|
}
|
|
|
|
|
2023-12-03 07:18:05 +00:00
|
|
|
/**
|
|
|
|
* Return our addresses.
|
|
|
|
* If zone provided, limit the list to those within the zone
|
|
|
|
*
|
2023-12-14 05:53:56 +00:00
|
|
|
* @param Domain|NULL $do Limit the addresses for the specific domain
|
|
|
|
* @param Address|null $ao If address is presented, show the address we use when talking to that address
|
|
|
|
* @return Collection|Address|NULL
|
2023-12-03 07:18:05 +00:00
|
|
|
*/
|
2023-12-14 05:53:56 +00:00
|
|
|
function our_address(Domain $do=NULL,Address $ao=NULL): Collection|Address|NULL
|
2023-12-03 07:18:05 +00:00
|
|
|
{
|
2024-04-13 12:41:58 +00:00
|
|
|
static $so = NULL;
|
|
|
|
static $our = NULL;
|
2023-12-03 07:18:05 +00:00
|
|
|
|
2024-04-13 12:41:58 +00:00
|
|
|
if (! $so)
|
|
|
|
$so = Setup::findOrFail(config('app.id'));
|
|
|
|
|
|
|
|
if (! $our) {
|
|
|
|
$so->load(['system.akas.zone.domain']);
|
|
|
|
$our = $so->system->akas;
|
|
|
|
}
|
|
|
|
|
|
|
|
$filter = $our;
|
2023-12-14 05:53:56 +00:00
|
|
|
if ($do)
|
2024-04-13 12:41:58 +00:00
|
|
|
$filter = $our->filter(function($item) use ($do) { return $item->zone->domain_id === $do->id; })->sortBy('role');
|
2023-12-14 05:53:56 +00:00
|
|
|
|
|
|
|
// If we are looking for a specific address, and there is only 1 result, return it, otherwise return what we have
|
2024-04-13 12:41:58 +00:00
|
|
|
if ($ao && config('fido.strict') && ($x=$filter->filter(function($item) use ($ao) { return $item->role <= $ao->role; })->sortBy('role'))->count())
|
2023-12-14 05:53:56 +00:00
|
|
|
$our = $x;
|
|
|
|
|
2024-04-13 12:41:58 +00:00
|
|
|
return $ao ? $our->last() : ($do ? $filter : $our);
|
2023-12-03 07:18:05 +00:00
|
|
|
}
|
|
|
|
|
2023-12-12 21:41:15 +00:00
|
|
|
/**
|
|
|
|
* Return a list of nodes that collect mail directly from us
|
|
|
|
*
|
|
|
|
* @param Domain|NULL $do
|
|
|
|
* @return Collection
|
|
|
|
*/
|
|
|
|
function our_nodes(Domain $do=NULL): Collection
|
|
|
|
{
|
|
|
|
return Address::select(['addresses.id','addresses.zone_id','region_id','host_id','node_id','point_id','addresses.system_id','role'])
|
|
|
|
->join('system_zone',['system_zone.system_id'=>'addresses.system_id','system_zone.zone_id'=>'addresses.zone_id'])
|
|
|
|
->when(! is_null($do),function($query) use ($do) {
|
|
|
|
return $query
|
|
|
|
->join('zones',['zones.id'=>'addresses.zone_id'])
|
|
|
|
->where('domain_id',$do->id);
|
|
|
|
})
|
|
|
|
->active()
|
|
|
|
->FTNorder()
|
|
|
|
->get();
|
|
|
|
}
|
|
|
|
|
2021-07-23 14:53:35 +00:00
|
|
|
if (! function_exists('timew')) {
|
|
|
|
/**
|
|
|
|
* Convert a time into an 32 bit value. This is primarily used to create 8 character hex filenames that
|
|
|
|
* are unique using 1/10th second precision.
|
|
|
|
*
|
|
|
|
* Time is:
|
2023-12-07 01:07:11 +00:00
|
|
|
* + 02 bits least significant bits of year - giving us a 4 year timestamp
|
2021-07-23 14:53:35 +00:00
|
|
|
* + 04 bits Month
|
|
|
|
* + 05 bits Day
|
|
|
|
* + 05 bits Hour
|
|
|
|
* + 06 bits Min
|
|
|
|
* + 06 bits Sec
|
|
|
|
* + 04 bits 10th Sec
|
2023-12-07 01:07:11 +00:00
|
|
|
* = 32 bits
|
2021-07-23 14:53:35 +00:00
|
|
|
*
|
2023-06-27 07:39:11 +00:00
|
|
|
* @param Carbon|null $time
|
2021-07-23 14:53:35 +00:00
|
|
|
* @return int
|
2023-12-07 01:07:11 +00:00
|
|
|
* @todo Since this is used as part of our msgid, we need to use the first 2 bits to get our 3 year unique msgid, ie: year&0x03
|
2021-07-23 14:53:35 +00:00
|
|
|
*/
|
2023-06-27 07:39:11 +00:00
|
|
|
function timew(Carbon $time=NULL): int
|
2021-07-23 14:53:35 +00:00
|
|
|
{
|
|
|
|
static $delay = 0;
|
|
|
|
|
|
|
|
// If we are not passed a time, we'll use the time now
|
|
|
|
if (! $time) {
|
|
|
|
// In case we are called twice, we'll delay 1/10th second so we have a unique result.
|
2023-06-27 07:39:11 +00:00
|
|
|
if (Carbon::now()->getPreciseTimestamp(1) === $delay)
|
2021-07-23 14:53:35 +00:00
|
|
|
usleep(100000);
|
|
|
|
|
2023-06-27 07:39:11 +00:00
|
|
|
$time = Carbon::now();
|
2021-07-23 14:53:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$delay = $time->getPreciseTimestamp(1);
|
|
|
|
|
2023-12-07 01:07:11 +00:00
|
|
|
$t = 0;
|
|
|
|
$t = ($t | $time->year & 0x3) << 4;
|
|
|
|
$t = ($t | ($time->month & 0xf)) << 5;
|
2021-07-23 14:53:35 +00:00
|
|
|
$t = ($t | ($time->day & 0x1f)) << 5;
|
|
|
|
$t = ($t | ($time->hour & 0x1f)) << 6;
|
|
|
|
$t = ($t | ($time->minute & 0x3f)) << 6;
|
2023-12-07 01:07:11 +00:00
|
|
|
$t = ($t | ($time->second & 0x3f)) << 4;
|
|
|
|
$t = ($t | ((int)($time->milli/100)) & 0xf);
|
2021-07-23 14:53:35 +00:00
|
|
|
|
2023-12-07 01:07:11 +00:00
|
|
|
return $t;
|
2021-07-23 14:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-18 05:57:30 +00:00
|
|
|
if (! function_exists('wtime')) {
|
2021-07-23 14:53:35 +00:00
|
|
|
/**
|
|
|
|
* Convert a 40 bit integer into a time.
|
2023-12-07 01:07:11 +00:00
|
|
|
* We need to filter out loose bits, ie:
|
|
|
|
* + year all bits valid
|
|
|
|
* + month 11xx and 0000 are invalid
|
|
|
|
* + day all bits valid except 0000
|
|
|
|
* + hour 11xxx are invalid
|
|
|
|
* + min 1111xx are invalid
|
|
|
|
* + sec 1111xx are invalid
|
|
|
|
* + 1/2 11xx, 101x are invalid
|
2021-07-23 14:53:35 +00:00
|
|
|
* @see timew()
|
|
|
|
*
|
|
|
|
* @param int $time
|
|
|
|
* @param int|null $year
|
2023-06-27 07:39:11 +00:00
|
|
|
* @return Carbon
|
2021-07-23 14:53:35 +00:00
|
|
|
*/
|
2023-06-27 07:39:11 +00:00
|
|
|
function wtime(int $time,int $year=NULL): Carbon
|
2021-07-23 14:53:35 +00:00
|
|
|
{
|
|
|
|
if (! $year)
|
2023-06-27 07:39:11 +00:00
|
|
|
$year = Carbon::now()->year;
|
2021-07-23 14:53:35 +00:00
|
|
|
|
|
|
|
// Does the time have milli seconds?
|
|
|
|
if ($time > pow(2,26)-1) {
|
|
|
|
$milli = ($time & 0xf);
|
|
|
|
$time = $time >> 4;
|
2023-12-07 01:07:11 +00:00
|
|
|
if ($milli > 9)
|
|
|
|
$milli = 9;
|
2021-07-23 14:53:35 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
$milli = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
$sec = ($time & 0x3f);
|
2023-12-07 01:07:11 +00:00
|
|
|
if ($sec > 59)
|
|
|
|
$sec = 59;
|
2021-07-23 14:53:35 +00:00
|
|
|
$time = $time >> 6;
|
|
|
|
|
|
|
|
$min = ($time & 0x3f);
|
2023-12-07 01:07:11 +00:00
|
|
|
if ($min > 59)
|
|
|
|
$min = 59;
|
2021-07-23 14:53:35 +00:00
|
|
|
$time = $time >> 6;
|
|
|
|
|
|
|
|
$hr = ($time & 0x1f);
|
2023-12-07 01:07:11 +00:00
|
|
|
if ($hr > 23)
|
|
|
|
$hr = 23;
|
2021-07-23 14:53:35 +00:00
|
|
|
$time = $time >> 5;
|
|
|
|
|
|
|
|
$day = ($time & 0x1f);
|
|
|
|
$time = $time >> 5;
|
|
|
|
|
2023-12-07 01:07:11 +00:00
|
|
|
$month = ($time & 0xf);
|
|
|
|
if ($month > 12)
|
|
|
|
$month = 12;
|
|
|
|
$time = $time >> 4;
|
2021-07-23 14:53:35 +00:00
|
|
|
|
2023-12-07 01:07:11 +00:00
|
|
|
return Carbon::create(($year & 0xffc)+$time,$month,$day,$hr,$min,$sec+$milli/10);
|
2021-07-23 14:53:35 +00:00
|
|
|
}
|
2019-05-11 01:17:56 +00:00
|
|
|
}
|