New algorithm for calculating packet name, EMSI/BINKP inbound processing tested, Netmail rejection and intransit processing
This commit is contained in:
parent
2fdc6eabad
commit
ee30ef92c3
@ -163,7 +163,7 @@ class Message extends FTNBase
|
|||||||
*
|
*
|
||||||
* @param string $msg
|
* @param string $msg
|
||||||
* @param Domain|null $domain
|
* @param Domain|null $domain
|
||||||
* @return static
|
* @return Message
|
||||||
* @throws InvalidPacketException
|
* @throws InvalidPacketException
|
||||||
*/
|
*/
|
||||||
public static function parseMessage(string $msg,Domain $domain=NULL): self
|
public static function parseMessage(string $msg,Domain $domain=NULL): self
|
||||||
|
@ -62,7 +62,7 @@ class Packet extends FTNBase
|
|||||||
{
|
{
|
||||||
$this->messages = collect();
|
$this->messages = collect();
|
||||||
$this->domain = NULL;
|
$this->domain = NULL;
|
||||||
$this->name = sprintf('%08x',Carbon::now()->timestamp);
|
$this->name = sprintf('%08x',timew());
|
||||||
|
|
||||||
// If we are creating an outbound packet, we need to set our header
|
// If we are creating an outbound packet, we need to set our header
|
||||||
if ($o)
|
if ($o)
|
||||||
|
@ -19,7 +19,7 @@ abstract class Process
|
|||||||
/**
|
/**
|
||||||
* This function will format text to static::MSG_WIDTH, as well as adding the logo.
|
* This function will format text to static::MSG_WIDTH, as well as adding the logo.
|
||||||
*/
|
*/
|
||||||
protected static function format_msg(string $text): string
|
public static function format_msg(string $text,array $logo = []): string
|
||||||
{
|
{
|
||||||
$msg = utf8_decode(join("\r",static::msg_header()))."\r";
|
$msg = utf8_decode(join("\r",static::msg_header()))."\r";
|
||||||
$c = 0;
|
$c = 0;
|
||||||
@ -29,8 +29,8 @@ abstract class Process
|
|||||||
$ll = '';
|
$ll = '';
|
||||||
|
|
||||||
// Add our logo
|
// Add our logo
|
||||||
if ($c<count(static::$logo)) {
|
if ($c<count($logo)) {
|
||||||
$line = utf8_decode(Arr::get(static::$logo,$c++));
|
$line = utf8_decode(Arr::get($logo,$c++));
|
||||||
$ll = $line.' ';
|
$ll = $line.' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,8 +60,8 @@ abstract class Process
|
|||||||
}
|
}
|
||||||
|
|
||||||
// In case our text is shorter than the loo
|
// In case our text is shorter than the loo
|
||||||
for ($c; $c<count(static::$logo);$c++)
|
for ($c; $c<count($logo);$c++)
|
||||||
$msg .= utf8_decode(Arr::get(static::$logo,$c))."\r";
|
$msg .= utf8_decode(Arr::get($logo,$c))."\r";
|
||||||
|
|
||||||
return $msg;
|
return $msg;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ use App\Models\{Netmail,Setup};
|
|||||||
*/
|
*/
|
||||||
final class Ping extends Process
|
final class Ping extends Process
|
||||||
{
|
{
|
||||||
protected static array $logo = [
|
private static array $logo = [
|
||||||
'ÚÄ¿þÚÄ¿ÚÄ¿',
|
'ÚÄ¿þÚÄ¿ÚÄ¿',
|
||||||
'³ ³Â³ ³Àij',
|
'³ ³Â³ ³Àij',
|
||||||
'ÃÄÙÁÁ ÁÄÄÙ'
|
'ÃÄÙÁÁ ÁÄÄÙ'
|
||||||
@ -29,7 +29,8 @@ final class Ping extends Process
|
|||||||
|
|
||||||
Log::info(sprintf('Processing PING message from (%s) [%s]',$msg->user_from,$msg->fftn));
|
Log::info(sprintf('Processing PING message from (%s) [%s]',$msg->user_from,$msg->fftn));
|
||||||
|
|
||||||
$reply = sprintf("Your ping was received here on %s and it took %s to get here.\r",
|
$reply = sprintf("Your ping was received here on %s and it looks like you sent it on %s. If that is correct, then it took %s to get here.\r",
|
||||||
|
$msg->date->toDateTimeString(),
|
||||||
Carbon::now()->toDateTimeString(),
|
Carbon::now()->toDateTimeString(),
|
||||||
$msg->date->diffForHumans(['parts'=>3,'syntax'=>CarbonInterface::DIFF_ABSOLUTE])
|
$msg->date->diffForHumans(['parts'=>3,'syntax'=>CarbonInterface::DIFF_ABSOLUTE])
|
||||||
);
|
);
|
||||||
@ -46,7 +47,7 @@ final class Ping extends Process
|
|||||||
$o->subject = 'Ping Reply';
|
$o->subject = 'Ping Reply';
|
||||||
$o->fftn_id = ($x=$msg->tftn_o) ? $x->id : NULL;
|
$o->fftn_id = ($x=$msg->tftn_o) ? $x->id : NULL;
|
||||||
$o->tftn_id = ($x=$msg->fftn_o) ? $x->id : NULL;
|
$o->tftn_id = ($x=$msg->fftn_o) ? $x->id : NULL;
|
||||||
$o->msg = static::format_msg($reply);
|
$o->msg = static::format_msg($reply,self::$logo);
|
||||||
$o->reply = $msg->msgid;
|
$o->reply = $msg->msgid;
|
||||||
|
|
||||||
$o->tagline = 'My ping pong opponent was not happy with my serve. He kept returning it.';
|
$o->tagline = 'My ping pong opponent was not happy with my serve. He kept returning it.';
|
||||||
|
@ -120,6 +120,7 @@ final class Send extends Item
|
|||||||
*
|
*
|
||||||
* @param string $file
|
* @param string $file
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
* @todo Catch if we add the same file twice
|
||||||
*/
|
*/
|
||||||
public function add(string $file): void
|
public function add(string $file): void
|
||||||
{
|
{
|
||||||
@ -277,7 +278,8 @@ final class Send extends Item
|
|||||||
throw new Exception('No file open for seek');
|
throw new Exception('No file open for seek');
|
||||||
|
|
||||||
if ($this->sending instanceof Mail) {
|
if ($this->sending instanceof Mail) {
|
||||||
$rc = ($pos < $this->size) ? $pos : $this->size;
|
$pos = ($pos < $this->size) ? $pos : $this->size;
|
||||||
|
$rc = TRUE;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$rc = (fseek($this->f,$pos,SEEK_SET) === 0);
|
$rc = (fseek($this->f,$pos,SEEK_SET) === 0);
|
||||||
|
@ -623,14 +623,6 @@ final class Binkp extends BaseProtocol
|
|||||||
// @todo lock nodes
|
// @todo lock nodes
|
||||||
$this->node->ftn = $o;
|
$this->node->ftn = $o;
|
||||||
|
|
||||||
// Add our mail to the queue if we have authenticated
|
|
||||||
if ($this->node->aka_authed)
|
|
||||||
foreach ($this->node->aka_remote as $ao) {
|
|
||||||
$this->send->mail($ao);
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::info(sprintf('%s: = Node has [%lu] mail and [%lu] files - [%lu] items',__METHOD__,$this->send->mail_size,$this->send->file_size,$this->send->total_count));
|
|
||||||
|
|
||||||
$rc = $this->node->aka_num;
|
$rc = $this->node->aka_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,8 +645,6 @@ final class Binkp extends BaseProtocol
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->msgs(self::BPM_NUL,sprintf('TRF %lu %lu',$this->send->mail_size,$this->send->file_size));
|
|
||||||
|
|
||||||
if ($this->md_challenge) {
|
if ($this->md_challenge) {
|
||||||
$this->msgs(self::BPM_PWD,sprintf('CRAM-MD5-%s',$this->node->get_md5chal($this->md_challenge)));
|
$this->msgs(self::BPM_PWD,sprintf('CRAM-MD5-%s',$this->node->get_md5chal($this->md_challenge)));
|
||||||
|
|
||||||
@ -697,6 +687,8 @@ final class Binkp extends BaseProtocol
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* We received EOB from the remote.
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private function M_eob(string $buf): int
|
private function M_eob(string $buf): int
|
||||||
@ -718,7 +710,7 @@ final class Binkp extends BaseProtocol
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->send->total_count)
|
if ($this->send->total_count)
|
||||||
$this->sessionClear(self::SE_NOFILES);
|
$this->sessionClear(self::SE_NOFILES|self::SE_SENTEOB);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -1066,6 +1058,14 @@ final class Binkp extends BaseProtocol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add our mail to the queue if we have authenticated
|
||||||
|
if ($this->node->aka_authed)
|
||||||
|
foreach ($this->node->aka_remote as $ao) {
|
||||||
|
$this->send->mail($ao);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->msgs(self::BPM_NUL,sprintf('TRF %lu %lu',$this->send->mail_size,$this->send->file_size));
|
||||||
|
|
||||||
Log::debug(sprintf('%s: = End',__METHOD__));
|
Log::debug(sprintf('%s: = End',__METHOD__));
|
||||||
return $this->binkp_hsdone();
|
return $this->binkp_hsdone();
|
||||||
}
|
}
|
||||||
@ -1142,6 +1142,12 @@ final class Binkp extends BaseProtocol
|
|||||||
if (strlen($tmp))
|
if (strlen($tmp))
|
||||||
$this->msgs(self::BPM_NUL,sprintf('OPT%s',$tmp));
|
$this->msgs(self::BPM_NUL,sprintf('OPT%s',$tmp));
|
||||||
|
|
||||||
|
// Add our mail to the queue if we have authenticated
|
||||||
|
if ($this->node->aka_authed)
|
||||||
|
foreach ($this->node->aka_remote as $ao) {
|
||||||
|
$this->send->mail($ao);
|
||||||
|
}
|
||||||
|
|
||||||
$this->msgs(self::BPM_NUL,sprintf('TRF %lu %lu',$this->send->mail_size,$this->send->file_size));
|
$this->msgs(self::BPM_NUL,sprintf('TRF %lu %lu',$this->send->mail_size,$this->send->file_size));
|
||||||
$this->msgs(self::BPM_OK,sprintf('%ssecure',$have_pwd ? '' : 'non-'));
|
$this->msgs(self::BPM_OK,sprintf('%ssecure',$have_pwd ? '' : 'non-'));
|
||||||
|
|
||||||
@ -1235,7 +1241,7 @@ final class Binkp extends BaseProtocol
|
|||||||
if ($rd && ! $this->binkp_recv())
|
if ($rd && ! $this->binkp_recv())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (($this->mqueue->count() || $wd) && ! $this->binkp_send())
|
if (($this->mqueue->count() || $wd) && ! $this->binkp_send() && (! $this->send->total_count))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface
|
|||||||
if (! parent::onConnect($client)) {
|
if (! parent::onConnect($client)) {
|
||||||
$this->session(self::SESSION_ZMODEM,$client);
|
$this->session(self::SESSION_ZMODEM,$client);
|
||||||
$this->client->close();
|
$this->client->close();
|
||||||
Log::info(sprintf('%s: = End - Connection closed [%s]',__METHOD__,$client->getAddress()));
|
Log::info(sprintf('%s: = End - Connection closed [%s]',__METHOD__,$client->address_remote));
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -246,30 +246,6 @@ final class SocketClient {
|
|||||||
return new self($socket,$speed);
|
return new self($socket,$speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the client's address
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @todo change to __get()
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public function getAddress(): string
|
|
||||||
{
|
|
||||||
return $this->address;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the port in use
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
* @todo change to __get()
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public function getPort(): int
|
|
||||||
{
|
|
||||||
return $this->port;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $timeout
|
* @param int $timeout
|
||||||
* @return int
|
* @return int
|
||||||
|
@ -52,6 +52,6 @@ class BinkpSend extends Command
|
|||||||
$o = new Binkp(Setup::findOrFail(config('app.id')));
|
$o = new Binkp(Setup::findOrFail(config('app.id')));
|
||||||
$o->session(Binkp::SESSION_BINKP,$client,$no);
|
$o->session(Binkp::SESSION_BINKP,$client,$no);
|
||||||
|
|
||||||
Log::info(sprintf('Connection ended: %s',$client->getAddress()),['m'=>__METHOD__]);
|
Log::info(sprintf('Connection ended: %s',$client->address_remote),['m'=>__METHOD__]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,6 @@ class ZmodemSend extends Command
|
|||||||
$o = new ZmodemClass;
|
$o = new ZmodemClass;
|
||||||
$o->session(Protocol::SESSION_ZMODEM,$client);
|
$o->session(Protocol::SESSION_ZMODEM,$client);
|
||||||
|
|
||||||
Log::info(sprintf('Connection ended: %s',$client->getAddress()),['m'=>__METHOD__]);
|
Log::info(sprintf('Connection ended: %s',$client->address_remote),['m'=>__METHOD__]);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,9 +7,10 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
|||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
use App\Classes\FTN\Message;
|
use App\Classes\FTN\{Message,Process};
|
||||||
use App\Models\Setup;
|
use App\Models\{Netmail,Setup};
|
||||||
|
|
||||||
class ProcessPacket implements ShouldQueue
|
class ProcessPacket implements ShouldQueue
|
||||||
{
|
{
|
||||||
@ -34,6 +35,8 @@ class ProcessPacket implements ShouldQueue
|
|||||||
// If we are a netmail
|
// If we are a netmail
|
||||||
if ($this->msg->isNetmail()) {
|
if ($this->msg->isNetmail()) {
|
||||||
// @todo Enable checks to reject old messages
|
// @todo Enable checks to reject old messages
|
||||||
|
// @todo Enable checks to reject duplicate
|
||||||
|
// @todo Enable checks to see if this is a file request or file send
|
||||||
|
|
||||||
// Determine if the message is to this system, or in transit
|
// Determine if the message is to this system, or in transit
|
||||||
if ($ftns->search(function($item) { return $this->msg->tftn == $item->ftn; }) !== FALSE) {
|
if ($ftns->search(function($item) { return $this->msg->tftn == $item->ftn; }) !== FALSE) {
|
||||||
@ -51,16 +54,74 @@ class ProcessPacket implements ShouldQueue
|
|||||||
|
|
||||||
// If not processed, no users here!
|
// If not processed, no users here!
|
||||||
if (! $processed) {
|
if (! $processed) {
|
||||||
dump('message not processed, no users here');
|
$reject = [
|
||||||
|
'ÚÄ¿ÚÄ¿ ÂÚÄ¿ÚÄ¿Ú¿',
|
||||||
|
'³ ³ÄÙ ³³ÄÙ³ ³ ',
|
||||||
|
'Á ÀÄÙÀÄÙÀÄÙÀÄÙ Á '
|
||||||
|
];
|
||||||
|
|
||||||
|
Log::info(sprintf('Netmail to the Hub from (%s) [%s] but no users here.',$this->msg->user_from,$this->msg->fftn));
|
||||||
|
|
||||||
|
$reply = "Your Netmail was not processed by the hub and cannot be delivered to anybody (as there are no users here).\r";
|
||||||
|
|
||||||
|
$reply .= "\r";
|
||||||
|
$reply .= "\r";
|
||||||
|
$reply .= "This is your original message:\r";
|
||||||
|
$reply .= "------------------------------ BEING MESSAGE ------------------------------\r";
|
||||||
|
$reply .= sprintf("TO: %s\r",$this->msg->user_to);
|
||||||
|
$reply .= sprintf("SUBJECT: %s\r",$this->msg->subject);
|
||||||
|
$reply .= $this->msg->message;
|
||||||
|
$reply .= "------------------------------ CONTROL LINES ------------------------------\r";
|
||||||
|
$reply .= sprintf("DATE: %s\r",$this->msg->date->format('Y-m-d H:i:s'));
|
||||||
|
$reply .= sprintf("MSGID: %s\r",$this->msg->msgid);
|
||||||
|
|
||||||
|
foreach ($this->msg->kludge as $k=>$v)
|
||||||
|
$reply .= sprintf("@%s: %s\n",strtoupper($k),$v);
|
||||||
|
foreach ($this->msg->via as $via)
|
||||||
|
$reply .= sprintf("VIA: %s\n",$via);
|
||||||
|
|
||||||
|
$reply .= "------------------------------ END MESSAGE ------------------------------\r";
|
||||||
|
|
||||||
|
$o = new Netmail();
|
||||||
|
$o->to = $this->msg->user_from;
|
||||||
|
$o->from = Setup::PRODUCT_NAME;
|
||||||
|
$o->subject = 'Message Undeliverable - '.$this->msg->msgid;
|
||||||
|
$o->fftn_id = ($x=$this->msg->tftn_o) ? $x->id : NULL;
|
||||||
|
$o->tftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL;
|
||||||
|
$o->msg = Process::format_msg($reply,$reject);
|
||||||
|
$o->reply = $this->msg->msgid;
|
||||||
|
|
||||||
|
$o->tagline = 'Do you think it was fate which brought us together? Nah, bad luck :(';
|
||||||
|
$o->tearline = sprintf('--- %s (%s)',Setup::PRODUCT_NAME,(new Setup)->version);
|
||||||
|
$o->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If in transit, store for collection
|
// If in transit, store for collection
|
||||||
} else {
|
} else {
|
||||||
|
Log::info(sprintf('Netmail [%s] in transit to (%s) [%s] from (%s) [%s].',
|
||||||
|
$this->msg->msgid,
|
||||||
|
$this->msg->user_to,$this->msg->tftn,
|
||||||
|
$this->msg->user_from,$this->msg->fftn,
|
||||||
|
));
|
||||||
|
|
||||||
// @todo Check if the message is to a system we know about
|
// @todo Check if the message is to a system we know about
|
||||||
// @todo In transit loop checking
|
// @todo In transit loop checking
|
||||||
// @todo In transit TRACE response
|
// @todo In transit TRACE response
|
||||||
|
|
||||||
dump('netmail in transit');
|
$o = new Netmail();
|
||||||
|
$o->to = $this->msg->user_to;
|
||||||
|
$o->from = $this->msg->user_from;
|
||||||
|
$o->subject = $this->msg->subject;
|
||||||
|
$o->fftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL;
|
||||||
|
$o->tftn_id = ($x=$this->msg->tftn_o) ? $x->id : NULL;
|
||||||
|
$o->msg = $this->msg->message;
|
||||||
|
$o->tearline = $this->msg->tearline;
|
||||||
|
$o->origin = $this->msg->origin;
|
||||||
|
$o->kluge = json_encode($this->msg->kludge);
|
||||||
|
$o->flags = $this->msg->flags;
|
||||||
|
$o->cost = $this->msg->cost;
|
||||||
|
|
||||||
|
$o->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Else we are echomail
|
// Else we are echomail
|
||||||
|
@ -75,4 +75,88 @@ if (! function_exists('hexstr')) {
|
|||||||
|
|
||||||
return $x;
|
return $x;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
* + 02 bits unused
|
||||||
|
* + 04 bits Month
|
||||||
|
* + 05 bits Day
|
||||||
|
* + 05 bits Hour
|
||||||
|
* + 06 bits Min
|
||||||
|
* + 06 bits Sec
|
||||||
|
* + 04 bits 10th Sec
|
||||||
|
* = 32 (2 bits free)
|
||||||
|
*
|
||||||
|
* @param \Carbon\Carbon|null $time
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
function timew(\Carbon\Carbon $time=NULL): int
|
||||||
|
{
|
||||||
|
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.
|
||||||
|
if (\Carbon\Carbon::now()->getPreciseTimestamp(1) == $delay)
|
||||||
|
usleep(100000);
|
||||||
|
|
||||||
|
$time = \Carbon\Carbon::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
$delay = $time->getPreciseTimestamp(1);
|
||||||
|
|
||||||
|
$t = ($time->month & 0xf) << 5;
|
||||||
|
$t = ($t | ($time->day & 0x1f)) << 5;
|
||||||
|
$t = ($t | ($time->hour & 0x1f)) << 6;
|
||||||
|
$t = ($t | ($time->minute & 0x3f)) << 6;
|
||||||
|
$t = ($t | ($time->second & 0x3f));
|
||||||
|
|
||||||
|
return hexdec(sprintf('%07x%1x',$t,(round($time->milli/100) & 0x7f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! function_exists('dwtime')) {
|
||||||
|
/**
|
||||||
|
* Convert a 40 bit integer into a time.
|
||||||
|
* @see timew()
|
||||||
|
*
|
||||||
|
* @param int $time
|
||||||
|
* @param int|null $year
|
||||||
|
* @return \Carbon\Carbon
|
||||||
|
*/
|
||||||
|
function wtime(int $time,int $year=NULL): \Carbon\Carbon
|
||||||
|
{
|
||||||
|
if (! $year)
|
||||||
|
$year = \Carbon\Carbon::now()->year;
|
||||||
|
|
||||||
|
// Does the time have milli seconds?
|
||||||
|
if ($time > pow(2,26)-1) {
|
||||||
|
$milli = ($time & 0xf);
|
||||||
|
$time = $time >> 4;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$milli = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sec = ($time & 0x3f);
|
||||||
|
$time = $time >> 6;
|
||||||
|
|
||||||
|
$min = ($time & 0x3f);
|
||||||
|
$time = $time >> 6;
|
||||||
|
|
||||||
|
$hr = ($time & 0x1f);
|
||||||
|
$time = $time >> 5;
|
||||||
|
|
||||||
|
$day = ($time & 0x1f);
|
||||||
|
$time = $time >> 5;
|
||||||
|
|
||||||
|
$month = ($time & 0x1f);
|
||||||
|
|
||||||
|
return \Carbon\Carbon::create($year,$month,$day,$hr,$min,$sec+$milli/10);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user