Enabled ANSI and Videotex servers and frames
This commit is contained in:
parent
6c91c69bd9
commit
0eb71ef7c6
@ -28,22 +28,26 @@ use Illuminate\Support\Facades\Log;
|
||||
*
|
||||
* @package App\Classes
|
||||
*/
|
||||
class Frame
|
||||
abstract class Frame
|
||||
{
|
||||
private $frame = NULL;
|
||||
private $output = NULL;
|
||||
private $frame_length = 22;
|
||||
private $frame_width = 40;
|
||||
protected $frame = NULL;
|
||||
protected $output = NULL;
|
||||
|
||||
private $header_length = 20; // 20
|
||||
private $pagenum_length = 9; // 11 (prefixed with a color, suffixed with frame)
|
||||
private $cost_length = 7; // 9 (prefixed with a color, suffixed with unit)
|
||||
private $cost_unit = 'u';
|
||||
// All this vars should be overridden in the child class
|
||||
/*
|
||||
protected $frame_length = 22;
|
||||
protected $frame_width = 40;
|
||||
|
||||
protected $header_length = 20; // 20
|
||||
protected $pagenum_length = 9; // 11 (prefixed with a color, suffixed with frame)
|
||||
protected $cost_length = 7; // 9 (prefixed with a color, suffixed with unit)
|
||||
protected $cost_unit = 'u';
|
||||
*/
|
||||
|
||||
public $fields = NULL; // The fields in this frame.
|
||||
|
||||
// Magic Fields that are pre-filled
|
||||
private $fieldmap = [
|
||||
protected $fieldmap = [
|
||||
'a'=>'address#',
|
||||
'd'=>'%date',
|
||||
];
|
||||
@ -80,6 +84,7 @@ class Frame
|
||||
}
|
||||
|
||||
// Calculate fields and render output.
|
||||
$this->fields = collect(); // Fields in this frame.
|
||||
$this->fields($startline);
|
||||
}
|
||||
|
||||
@ -118,115 +123,7 @@ class Frame
|
||||
*
|
||||
* @param int $startline
|
||||
*/
|
||||
public function fields($startline=0,$fieldchar='.')
|
||||
{
|
||||
$infield = FALSE; // In a field
|
||||
$fieldtype = NULL; // Type of field
|
||||
$fieldlength = 0; // Length of field
|
||||
$this->fields = collect(); // Fields in this frame.
|
||||
|
||||
if ($startline)
|
||||
$this->output .= str_repeat(DOWN,$startline);
|
||||
|
||||
// $fieldadrline = 1;
|
||||
|
||||
// Scan the frame for a field start
|
||||
for ($y=$startline;$y<=$this->frame_length;$y++)
|
||||
{
|
||||
// Fields can only be on a single line
|
||||
$fieldx = $fieldy = FALSE;
|
||||
|
||||
for ($x=0;$x<$this->frame_width;$x++)
|
||||
{
|
||||
$posn = $y*40+$x;
|
||||
|
||||
// If the frame is not big enough, fill it with spaces.
|
||||
$byte = ord(isset($this->frame->content{$posn}) ? $this->frame->content{$posn} : ' ')%128;
|
||||
|
||||
// Check for start-of-field
|
||||
if ($byte == ord(ESC)) { // Esc designates start of field (Esc-K is end of edit)
|
||||
$infield = TRUE;
|
||||
$fieldlength = 1;
|
||||
$fieldtype = ord(substr($this->frame->content,$posn+1,1))%128;
|
||||
$this->output .= $fieldchar;
|
||||
|
||||
} else {
|
||||
if ($infield) {
|
||||
if ($byte == $fieldtype) {
|
||||
$fieldlength++;
|
||||
$byte = ord($fieldchar); // Replace field with $fieldchar.
|
||||
|
||||
if ($fieldx === FALSE) {
|
||||
$fieldx = $x;
|
||||
$fieldy = $y;
|
||||
}
|
||||
|
||||
// Is this a magic field?
|
||||
// @todo For page redisplay *00, we should show entered contents - for refresh *09 we should show updated contents
|
||||
if (array_get($this->fieldmap,chr($fieldtype)) ) {
|
||||
$field = $this->fieldmap[chr($fieldtype)];
|
||||
//dump(['infield','byte'=>$byte,'fieldtype'=>$fieldtype,'field'=>$field,'strpos'=>strpos($field,'#')]);
|
||||
|
||||
/*
|
||||
// address field has many lines. increment when hit on first character.
|
||||
if ($fieldlength == 1 && strpos($field,'#') !== false) {
|
||||
$field = str_replace('#',$fieldadrline,$field);
|
||||
dump(['field'=>$field,'fieldadrline'=>$fieldadrline,'fieldadrline'=>$fieldadrline]);
|
||||
$fieldadrline++;
|
||||
}
|
||||
*/
|
||||
|
||||
// Replace field with Date
|
||||
if ($field == '%date') {
|
||||
// Drop the last dot and replace it.
|
||||
if ($fieldlength == 2) {
|
||||
$datetime = date('D d M H:ia');
|
||||
$this->output = rtrim($this->output,$fieldchar);
|
||||
$this->output .= $datetime{0};
|
||||
}
|
||||
|
||||
if ($fieldlength > 1 AND $fieldlength <= strlen($datetime))
|
||||
$byte = ord($datetime{$fieldlength-1});
|
||||
}
|
||||
|
||||
// @todo user data
|
||||
/* else if (isset($user[$field])) {
|
||||
if ($fieldlength <= strlen($user[$field])) {
|
||||
$byte = ord($user[$field]{$fieldlength-1});
|
||||
}
|
||||
} /*else // pre-load field contents. PAM or *00 ?
|
||||
if (isset($fields[what]['value'])) {
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->fields->push(new FrameFields([
|
||||
'type'=>chr($fieldtype),
|
||||
'length'=>$fieldlength,
|
||||
'x'=>$fieldx-1, // Adjust for the ESC char
|
||||
'y'=>$fieldy,
|
||||
]));
|
||||
|
||||
Log::debug(sprintf('Frame: %s, Field found at [%s,%s], Type: %s, Length: %s',$this->page(),$fieldx-1,$fieldy,$fieldtype,$fieldlength));
|
||||
|
||||
$infield = FALSE;
|
||||
$fieldx = $fieldy = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// truncate end of lines @todo havent validated this code or used it?
|
||||
if (isset($pageflags['tru']) && substr($this->frame->content,$posn,40-$x) === str_repeat(' ',40-$x)) {
|
||||
$this->output .= CR . LF;
|
||||
break;
|
||||
}
|
||||
|
||||
if (! $infield OR $fieldlength > 1)
|
||||
$this->output .= ($byte < 32) ? ESC.chr($byte+64) : chr($byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
abstract public function fields($startline=0,$fieldchar='.');
|
||||
|
||||
/**
|
||||
* Returns the current frame.
|
||||
@ -349,7 +246,7 @@ class Frame
|
||||
else
|
||||
$color = GREEN;
|
||||
|
||||
return sprintf($color.'% '.$this->cost_length.'.0f%s',$cost,$this->cost_unit);
|
||||
return sprintf($color.'% '.static::$cost_length.'.0f%s',$cost,static::$cost_unit);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -360,9 +257,9 @@ class Frame
|
||||
*/
|
||||
private function render_header(string $header)
|
||||
{
|
||||
$filler = ($this->strlenv($header) < $this->header_length) ? str_repeat(' ',$this->header_length-$this->strlenv($header)) : '';
|
||||
$filler = ($this->strlenv($header) < static::$header_length) ? str_repeat(' ',static::$header_length-$this->strlenv($header)) : '';
|
||||
|
||||
return substr($header.$filler,0,$this->header_length+substr_count($this->header,ESC));
|
||||
return substr($header.$filler,0,static::$header_length+strlen($header)-$this->strlenv($header));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -381,7 +278,7 @@ class Frame
|
||||
if (strlen($frame) !== 1)
|
||||
throw new \Exception('Frame invalid',500);
|
||||
|
||||
return sprintf(WHITE.'% '.$this->pagenum_length.'.0f%s',$num,$frame);
|
||||
return sprintf(WHITE.'% '.static::$pagenum_length.'.0f%s',$num,$frame);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -403,11 +300,9 @@ class Frame
|
||||
* @param $text
|
||||
* @return int
|
||||
*/
|
||||
function strlenv($text):int {
|
||||
return strlen($text)-substr_count($text,ESC);
|
||||
}
|
||||
abstract function strlenv($text):int;
|
||||
|
||||
public static function testFrame()
|
||||
public static function testFrame(Server $so)
|
||||
{
|
||||
// Simulate a DB load
|
||||
$o = new \App\Models\Frame;
|
||||
@ -419,7 +314,8 @@ class Frame
|
||||
$o->index = 'a';
|
||||
|
||||
// Header
|
||||
$o->content .= substr(R_RED.'T'.R_BLUE.'E'.R_GREEN.'S'.R_YELLOW.'T-12345678901234567890',0,20).
|
||||
$sid = R_RED.'T'.R_BLUE.'E'.R_GREEN.'S'.R_YELLOW.'T';
|
||||
$o->content .= substr($sid.'-'.str_repeat('12345678901234567890',4),0,static::$header_length+(strlen($sid)-$so->strlenv($sid))).
|
||||
R_WHITE.'999999999a'.R_RED.sprintf('%07.0f',999).'u';
|
||||
|
||||
$o->content .= str_repeat('+-',18).' '.R_RED.'01';
|
||||
|
27
app/Classes/Frame/Ansi.php
Normal file
27
app/Classes/Frame/Ansi.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Frame;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\Frame as AbstractFrame;
|
||||
|
||||
class Ansi extends AbstractFrame
|
||||
{
|
||||
public static $frame_length = 22;
|
||||
public static $frame_width = 80;
|
||||
|
||||
public static $header_length = 60;
|
||||
public static $pagenum_length = 9;
|
||||
public static $cost_length = 7;
|
||||
public static $cost_unit = 'u';
|
||||
|
||||
public function fields($startline=0,$fieldchar='.')
|
||||
{
|
||||
$this->output .= str_replace(LF,CR.LF,$this->frame->content);
|
||||
}
|
||||
|
||||
public function strlenv($text):int {
|
||||
return strlen($text ? preg_replace('/'.ESC.'\[[0-9;?]+[a-zA-Z]/','',$text) : $text);
|
||||
}
|
||||
}
|
132
app/Classes/Frame/Videotex.php
Normal file
132
app/Classes/Frame/Videotex.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Frame;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\Frame as AbstractFrame;
|
||||
use App\Classes\FrameFields;
|
||||
|
||||
class Videotex extends AbstractFrame
|
||||
{
|
||||
public static $frame_length = 22;
|
||||
public static $frame_width = 40;
|
||||
|
||||
public static $header_length = 20;
|
||||
public static $pagenum_length = 9;
|
||||
public static $cost_length = 7;
|
||||
public static $cost_unit = 'u';
|
||||
|
||||
public function fields($startline=0,$fieldchar='.')
|
||||
{
|
||||
$infield = FALSE; // In a field
|
||||
$fieldtype = NULL; // Type of field
|
||||
$fieldlength = 0; // Length of field
|
||||
|
||||
if ($startline)
|
||||
$this->output .= str_repeat(DOWN,$startline);
|
||||
|
||||
// $fieldadrline = 1;
|
||||
|
||||
// Scan the frame for a field start
|
||||
for ($y=$startline;$y<=static::$frame_length;$y++)
|
||||
{
|
||||
// Fields can only be on a single line
|
||||
$fieldx = $fieldy = FALSE;
|
||||
|
||||
for ($x=0;$x<static::$frame_width;$x++)
|
||||
{
|
||||
$posn = $y*40+$x;
|
||||
|
||||
// If the frame is not big enough, fill it with spaces.
|
||||
$byte = ord(isset($this->frame->content{$posn}) ? $this->frame->content{$posn} : ' ')%128;
|
||||
|
||||
// Check for start-of-field
|
||||
if ($byte == ord(ESC)) { // Esc designates start of field (Esc-K is end of edit)
|
||||
$infield = TRUE;
|
||||
$fieldlength = 1;
|
||||
$fieldtype = ord(substr($this->frame->content,$posn+1,1))%128;
|
||||
$this->output .= $fieldchar;
|
||||
|
||||
} else {
|
||||
if ($infield) {
|
||||
if ($byte == $fieldtype) {
|
||||
$fieldlength++;
|
||||
$byte = ord($fieldchar); // Replace field with $fieldchar.
|
||||
|
||||
if ($fieldx === FALSE) {
|
||||
$fieldx = $x;
|
||||
$fieldy = $y;
|
||||
}
|
||||
|
||||
// Is this a magic field?
|
||||
// @todo For page redisplay *00, we should show entered contents - for refresh *09 we should show updated contents
|
||||
if (array_get($this->fieldmap,chr($fieldtype)) ) {
|
||||
$field = $this->fieldmap[chr($fieldtype)];
|
||||
//dump(['infield','byte'=>$byte,'fieldtype'=>$fieldtype,'field'=>$field,'strpos'=>strpos($field,'#')]);
|
||||
|
||||
/*
|
||||
// address field has many lines. increment when hit on first character.
|
||||
if ($fieldlength == 1 && strpos($field,'#') !== false) {
|
||||
$field = str_replace('#',$fieldadrline,$field);
|
||||
dump(['field'=>$field,'fieldadrline'=>$fieldadrline,'fieldadrline'=>$fieldadrline]);
|
||||
$fieldadrline++;
|
||||
}
|
||||
*/
|
||||
|
||||
// Replace field with Date
|
||||
if ($field == '%date') {
|
||||
// Drop the last dot and replace it.
|
||||
if ($fieldlength == 2) {
|
||||
$datetime = date('D d M H:ia');
|
||||
$this->output = rtrim($this->output,$fieldchar);
|
||||
$this->output .= $datetime{0};
|
||||
}
|
||||
|
||||
if ($fieldlength > 1 AND $fieldlength <= strlen($datetime))
|
||||
$byte = ord($datetime{$fieldlength-1});
|
||||
}
|
||||
|
||||
// @todo user data
|
||||
/* else if (isset($user[$field])) {
|
||||
if ($fieldlength <= strlen($user[$field])) {
|
||||
$byte = ord($user[$field]{$fieldlength-1});
|
||||
}
|
||||
} /*else // pre-load field contents. PAM or *00 ?
|
||||
if (isset($fields[what]['value'])) {
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->fields->push(new FrameFields([
|
||||
'type'=>chr($fieldtype),
|
||||
'length'=>$fieldlength,
|
||||
'x'=>$fieldx-1, // Adjust for the ESC char
|
||||
'y'=>$fieldy,
|
||||
]));
|
||||
|
||||
Log::debug(sprintf('Frame: %s, Field found at [%s,%s], Type: %s, Length: %s',$this->page(),$fieldx-1,$fieldy,$fieldtype,$fieldlength));
|
||||
|
||||
$infield = FALSE;
|
||||
$fieldx = $fieldy = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// truncate end of lines @todo havent validated this code or used it?
|
||||
if (isset($pageflags['tru']) && substr($this->frame->content,$posn,40-$x) === str_repeat(' ',40-$x)) {
|
||||
$this->output .= CR . LF;
|
||||
break;
|
||||
}
|
||||
|
||||
if (! $infield OR $fieldlength > 1)
|
||||
$this->output .= ($byte < 32) ? ESC.chr($byte+64) : chr($byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function strlenv($text):int {
|
||||
return strlen($text)-substr_count($text,ESC);
|
||||
}
|
||||
}
|
@ -9,17 +9,30 @@ use Sock\{SocketClient,SocketException};
|
||||
|
||||
use App\Classes\Frame as FrameClass;
|
||||
use App\Models\Frame as FrameModel;
|
||||
use App\Models\Mode;
|
||||
|
||||
abstract class Server {
|
||||
// Size of Bottom Line Pollution
|
||||
private $blp = 0;
|
||||
private $mo = NULL; // Our Mode object
|
||||
protected $blp = 0; // Size of Bottom Line Pollution
|
||||
|
||||
public function __construct()
|
||||
public function __construct(Mode $o)
|
||||
{
|
||||
define('MSG_TIMEWARP_ON', WHITE . 'TIMEWARP ON' . GREEN . 'VIEW INFO WITH *02');
|
||||
define('MSG_TIMEWARP_OFF', WHITE . 'TIMEWARP OFF' . GREEN . 'VIEWING DATE IS FIXED');
|
||||
define('MSG_TIMEWARP_TO', GREEN . 'TIMEWARP TO %s');
|
||||
define('MSG_TIMEWARP', WHITE . 'OTHER VERSIONS EXIST' . GREEN . 'KEY *02 TO VIEW');
|
||||
$this->mo = $o;
|
||||
|
||||
define('MSG_SENDORNOT', GREEN.'KEY 1 TO SEND, 2 NOT TO SEND');
|
||||
define('MSG_SENT', GREEN.'MESSAGE SENT - KEY _ TO CONTINUE');
|
||||
define('MSG_NOTSENT', GREEN.'MESSAGE NOT SENT - KEY _ TO CONTINUE');
|
||||
|
||||
define('ERR_DATABASE', RED.'UNAVAILABLE AT PRESENT - PLSE TRY LATER');
|
||||
define('ERR_NOTSENT', WHITE.'MESSAGE NOT SENT DUE TO AN ERROR');
|
||||
define('ERR_PRIVATE', WHITE.'PRIVATE PAGE'.GREEN.'- FOR EXPLANATION *37_..');
|
||||
define('ERR_ROUTE', WHITE.'MISTAKE?'.GREEN.'TRY AGAIN OR TELL US ON *08');
|
||||
define('ERR_PAGE',ERR_ROUTE);
|
||||
|
||||
define('MSG_TIMEWARP_ON', WHITE.'TIMEWARP ON'.GREEN.'VIEW INFO WITH *02');
|
||||
define('MSG_TIMEWARP_OFF', WHITE.'TIMEWARP OFF'.GREEN.'VIEWING DATE IS FIXED');
|
||||
define('MSG_TIMEWARP_TO', GREEN.'TIMEWARP TO %s');
|
||||
define('MSG_TIMEWARP', WHITE.'OTHER VERSIONS EXIST'.GREEN.'KEY *02 TO VIEW');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,7 +68,7 @@ abstract class Server {
|
||||
// $client->send(TCP_IAC.TCP_AYT); // AYT
|
||||
$client->send(TCP_IAC . TCP_DO . TCP_OPT_TERMTYPE . TCP_IAC . TCP_SB . TCP_OPT_TERMTYPE . TCP_OPT_ECHO . TCP_IAC . TCP_SE); // Request Term Type
|
||||
|
||||
$client->send(CLS);
|
||||
$client->send(CLS.COFF);
|
||||
|
||||
// Setup VARS
|
||||
$timewarp = FALSE; // Is timewarp active.
|
||||
@ -151,6 +164,14 @@ abstract class Server {
|
||||
|
||||
continue;
|
||||
|
||||
case TCP_OPT_WINDOWSIZE:
|
||||
$session_note .= 'WINDOWSIZE';
|
||||
$session_init = FALSE;
|
||||
$read = '';
|
||||
Log::debug($session_note);
|
||||
|
||||
continue;
|
||||
|
||||
default:
|
||||
if ($session_option AND $read) {
|
||||
$session_term .= $read;
|
||||
@ -575,16 +596,18 @@ abstract class Server {
|
||||
// Look for requested page
|
||||
case ACTION_GOTO:
|
||||
// If we wanted a "Searching..." message, this is where to put it.
|
||||
|
||||
try {
|
||||
$fo = $timewarpalt
|
||||
? new FrameClass(FrameModel::findOrFail($timewarpalt))
|
||||
: (new FrameModel)->fetch($page['frame'],$page['index']);
|
||||
? $this->mo->frame(FrameModel::findOrFail($timewarpalt))
|
||||
: $this->mo->frameLoad($page['frame'],$page['index'],$this);
|
||||
|
||||
} catch (ModelNotFoundException $e) {
|
||||
$this->sendBaseline($client,ERR_PAGE);
|
||||
$mode = $action = FALSE;
|
||||
|
||||
// We initialise $fo anyway
|
||||
$fo = $this->mo->frame($this->testFrame());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -649,6 +672,7 @@ abstract class Server {
|
||||
case 'i':
|
||||
$client->send($output);
|
||||
$mode = $action = false;
|
||||
|
||||
break;
|
||||
|
||||
// Active Frame. Prestel uses this for a Response Frame.
|
||||
@ -684,8 +708,8 @@ abstract class Server {
|
||||
case 't':
|
||||
$client->send($output);
|
||||
$action = ACTION_TERMINATE;
|
||||
break;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -719,7 +743,7 @@ abstract class Server {
|
||||
|
||||
$line .= BLUE.$date.' '.$o->note;
|
||||
|
||||
$output .= $this->outputPosition(0,$y++).$line.str_repeat(' ',40-$this->strlenv($line));
|
||||
$output .= $this->outputPosition(0,$y++).$line.str_repeat(' ',40-$this->strlenv($line)); // @todo should use frame::page_length
|
||||
}
|
||||
|
||||
if ($timewarp) {
|
||||
@ -750,7 +774,7 @@ abstract class Server {
|
||||
|
||||
// Something bad happened. We'll log it and then disconnect.
|
||||
} catch (\Exception $e) {
|
||||
Log::emergency($e->getMessage());
|
||||
Log::emergency($e->getMessage(),['line'=>$e->getLine(),'file'=>$e->getFile()]);
|
||||
}
|
||||
|
||||
$client->close();
|
||||
@ -784,16 +808,7 @@ abstract class Server {
|
||||
* @param $text
|
||||
* @param bool $reposition
|
||||
*/
|
||||
function sendBaseline($client,$text,$reposition=FALSE) {
|
||||
$client->send(HOME.UP.$text.
|
||||
($this->blp > $this->strlenv($text)
|
||||
? str_repeat(' ',$this->blp-$this->strlenv($text)).
|
||||
($reposition ? HOME.UP.str_repeat(RIGHT,$this->strlenv($text)) : '')
|
||||
: '')
|
||||
);
|
||||
|
||||
$this->blp = $this->strlenv($text);
|
||||
}
|
||||
abstract function sendBaseline($client,$text,$reposition=FALSE);
|
||||
|
||||
/**
|
||||
* Calculate the length of text
|
||||
@ -802,9 +817,12 @@ abstract class Server {
|
||||
*
|
||||
* @param $text
|
||||
* @return int
|
||||
* @todo Implement this as a helper
|
||||
*/
|
||||
function strlenv($text):int {
|
||||
return strlen($text)-substr_count($text,ESC);
|
||||
}
|
||||
abstract function strlenv($text):int;
|
||||
|
||||
/**
|
||||
* Return a test frame appropriate for this server.
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function testFrame();
|
||||
}
|
@ -2,10 +2,72 @@
|
||||
|
||||
namespace App\Classes\Server;
|
||||
|
||||
use App\Classes\Server as AbstractServer;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class Ansi extends AbstractServer {
|
||||
use App\Classes\Server as AbstractServer;
|
||||
use App\Models\Mode;
|
||||
|
||||
class Ansi extends AbstractServer {
|
||||
public function __construct(Mode $o)
|
||||
{
|
||||
define('ESC', chr(27));
|
||||
define('CON', ESC.'[?25h'); // Cursor On
|
||||
define('COFF', ESC.'[?25l'); // Cursor Off
|
||||
define('HOME', ESC.'[0;0f');
|
||||
define('LEFT', ESC.'[D'); // Move Cursor
|
||||
define('RIGHT', ESC.'[C'); // Move Cursor
|
||||
define('DOWN', chr(10)); // Move Cursor
|
||||
define('UP', chr(11)); // Move Cursor
|
||||
define('CR', chr(13));
|
||||
define('LF', chr(10));
|
||||
define('CLS', ESC.'[2J');
|
||||
define('HASH', '#'); // Enter
|
||||
define('STAR', '*'); // Star Entry
|
||||
define('SPACE', ' '); // Space
|
||||
|
||||
// NOTE: This consts are effective output
|
||||
define('RED', ESC.'[0;31m'.SPACE);
|
||||
define('GREEN', ESC.'[0;32m'.SPACE);
|
||||
define('YELLOW', ESC.'[1;33m'.SPACE);
|
||||
define('BLUE', ESC.'[0;34m'.SPACE);
|
||||
define('MAGENTA', ESC.'[0;35m'.SPACE);
|
||||
define('CYAN', ESC.'[0;36m'.SPACE);
|
||||
define('WHITE', ESC.'[1;37m'.SPACE);
|
||||
define('NEWBG', '');
|
||||
|
||||
// Raw attributes - used when storing frames.
|
||||
define('R_RED', RED);
|
||||
define('R_GREEN', GREEN);
|
||||
define('R_YELLOW', YELLOW);
|
||||
define('R_BLUE', BLUE);
|
||||
define('R_MAGENTA', MAGENTA);
|
||||
define('R_CYAN', CYAN);
|
||||
define('R_WHITE', WHITE);
|
||||
//define('FLASH',chr(8));
|
||||
|
||||
parent::__construct($o);
|
||||
}
|
||||
|
||||
// Abstract function
|
||||
public function sendBaseline($client,$text,$reposition=FALSE) {
|
||||
$client->send(ESC.'[24;0f'.$text.
|
||||
($this->blp > $this->strlenv($text)
|
||||
? str_repeat(' ',$this->blp-$this->strlenv($text)).
|
||||
($reposition ? ESC.'[24;0f'.str_repeat(RIGHT,$this->strlenv($text)) : '')
|
||||
: '')
|
||||
);
|
||||
|
||||
$this->blp = $this->strlenv($text);
|
||||
}
|
||||
|
||||
// Abstract function
|
||||
public function strlenv($text):int {
|
||||
return strlen($text ? preg_replace('/'.ESC.'\[[0-9;?]+[a-zA-Z]/','',$text) : $text);
|
||||
}
|
||||
|
||||
// Abstract function
|
||||
public function testFrame()
|
||||
{
|
||||
return \App\Classes\Frame\Ansi::testFrame($this);
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Server;
|
||||
|
||||
use App\Classes\Server as AbstractServer;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class VideoTex extends AbstractServer {
|
||||
|
||||
}
|
72
app/Classes/Server/Videotex.php
Normal file
72
app/Classes/Server/Videotex.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Server;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\Server as AbstractServer;
|
||||
use App\Models\Mode;
|
||||
|
||||
class Videotex extends AbstractServer {
|
||||
public function __construct(Mode $o)
|
||||
{
|
||||
define('ESC', chr(27));
|
||||
define('CON', chr(17)); // Cursor On
|
||||
define('COFF', chr(20)); // Cursor Off
|
||||
define('HOME', chr(30));
|
||||
define('LEFT', chr(8)); // Move Cursor
|
||||
define('RIGHT', chr(9)); // Move Cursor
|
||||
define('DOWN', chr(10)); // Move Cursor
|
||||
define('UP', chr(11)); // Move Cursor
|
||||
define('CR', chr(13));
|
||||
define('LF', chr(10));
|
||||
define('CLS', chr(12));
|
||||
define('HASH', '_'); // Enter
|
||||
define('STAR', '*'); // Star Entry
|
||||
define('SPACE', ''); // Space
|
||||
|
||||
// NOTE: This consts are effective output
|
||||
define('RED', ESC.'A');
|
||||
define('GREEN', ESC.'B');
|
||||
define('YELLOW', ESC.'C');
|
||||
define('BLUE', ESC.'D');
|
||||
define('MAGENTA', ESC.'E');
|
||||
define('CYAN', ESC.'F');
|
||||
define('WHITE', ESC.'G');
|
||||
define('NEWBG', ESC.']');
|
||||
|
||||
// Raw attributes - used when storing frames.
|
||||
define('R_RED', chr(1));
|
||||
define('R_GREEN', chr(2));
|
||||
define('R_YELLOW', chr(3));
|
||||
define('R_BLUE', chr(4));
|
||||
define('R_MAGENTA', chr(5));
|
||||
define('R_CYAN', chr(6));
|
||||
define('R_WHITE', chr(7));
|
||||
define('FLASH', chr(8));
|
||||
|
||||
parent::__construct($o);
|
||||
}
|
||||
|
||||
public function sendBaseline($client,$text,$reposition=FALSE) {
|
||||
$client->send(HOME.UP.$text.
|
||||
($this->blp > $this->strlenv($text)
|
||||
? str_repeat(' ',$this->blp-$this->strlenv($text)).
|
||||
($reposition ? HOME.UP.str_repeat(RIGHT,$this->strlenv($text)) : '')
|
||||
: '')
|
||||
);
|
||||
|
||||
$this->blp = $this->strlenv($text);
|
||||
}
|
||||
|
||||
// Abstract function
|
||||
public function strlenv($text):int {
|
||||
return strlen($text)-substr_count($text,ESC);
|
||||
}
|
||||
|
||||
// Abstract function
|
||||
public function testFrame()
|
||||
{
|
||||
return \App\Classes\Frame\Videotex::testFrame($this);
|
||||
}
|
||||
}
|
@ -60,7 +60,7 @@ class Server extends Command
|
||||
throw new SocketException(SocketException::CANT_ACCEPT,'Missing pcntl extension');
|
||||
}
|
||||
|
||||
$mo = Mode::where('name',$this->option('mode'))->firstOrFail();
|
||||
$mo = Mode::where('name','LIKE',$this->option('mode'))->firstOrFail();
|
||||
|
||||
$server = new SocketServer(config('app.port'),config('app.bind'));
|
||||
$server->init();
|
||||
|
@ -25,22 +25,6 @@ class Frame extends Model
|
||||
return $this->frame.$this->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a specific frame from the database
|
||||
*
|
||||
* @param int $page
|
||||
* @param string $frame
|
||||
* @return mixed
|
||||
*/
|
||||
public function fetch(int $frame,string $index='a'): \App\Classes\Frame
|
||||
{
|
||||
// Return our internal test frame.
|
||||
if ($frame == '999' and $index == 'a')
|
||||
return new \App\Classes\Frame(\App\Classes\Frame::testFrame());
|
||||
|
||||
return new \App\Classes\Frame($this->where('frame',$frame)->where('index',$index)->firstOrFail());
|
||||
}
|
||||
|
||||
public function hasFlag(string $flag)
|
||||
{
|
||||
// @todo When flags is in the DB update this.
|
||||
|
@ -5,24 +5,73 @@ namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use App\Classes\Frame as FrameClass;
|
||||
use App\Classes\Frame\Ansi as AnsiFrame;
|
||||
use App\Classes\Frame\Videotex as VideotexFrame;
|
||||
|
||||
use App\Classes\Server;
|
||||
use App\Classes\Server\Ansi as AnsiServer;
|
||||
use App\Classes\Server\Videotex as VideotexServer;
|
||||
|
||||
class Mode extends Model
|
||||
{
|
||||
public function frames()
|
||||
{
|
||||
return $this->hasMany(Frame::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a frame class for the Model
|
||||
*
|
||||
* @param Model $o
|
||||
* @return FrameClass
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function frame(Model $o): FrameClass
|
||||
{
|
||||
switch (strtolower($this->name)) {
|
||||
case 'ansi':
|
||||
return new AnsiFrame($o);
|
||||
case 'videotex':
|
||||
return new VideotexFrame($o);
|
||||
default:
|
||||
throw new \Exception('Unknown Frame type: '.$mo->name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a specific frame from the DB
|
||||
*
|
||||
* @param int $frame
|
||||
* @param string $index
|
||||
* @return FrameClass
|
||||
* @throws \Exception
|
||||
*/
|
||||
//@todo Move Server $so first
|
||||
public function frameLoad(int $frame,string $index='a',Server $so): FrameClass
|
||||
{
|
||||
return $this->frame(
|
||||
// Return our internal test frame.
|
||||
($frame == '999' and $index == 'a')
|
||||
? $so->testFrame()
|
||||
: $this->frames()
|
||||
->where('frame','=',$frame)
|
||||
->where('index','=',$index)
|
||||
->firstOrFail()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return our server instance
|
||||
*/
|
||||
public function server()
|
||||
{
|
||||
switch ($this->name) {
|
||||
case 'Ansi':
|
||||
case 'VideoTex':
|
||||
$class = 'App\\Classes\\Server\\'.$this->name;
|
||||
|
||||
break;
|
||||
switch (strtolower($this->name)) {
|
||||
case 'ansi': return new AnsiServer($this);
|
||||
case 'videotex': return new VideotexServer($this);
|
||||
|
||||
default:
|
||||
throw new \Exception('Unknown server type: '.$this->name);
|
||||
}
|
||||
|
||||
return new $class;
|
||||
}
|
||||
}
|
@ -18,46 +18,12 @@ define('ACTION_TERMINATE',6);
|
||||
define('ACTION_SUBMITRF',7); // Offer to submit a response frame
|
||||
define('ACTION_STAR',8);
|
||||
|
||||
define('CON', chr(17)); // Cursor On
|
||||
define('COFF', chr(20)); // Cursor Off
|
||||
define('HOME', chr(30));
|
||||
define('LEFT', chr(8)); // Move Cursor
|
||||
define('RIGHT', chr(9)); // Move Cursor
|
||||
define('DOWN', chr(10)); // Move Cursor
|
||||
define('UP', chr(11)); // Move Cursor
|
||||
define('CR', chr(13));
|
||||
define('LF', chr(10));
|
||||
define('CLS', chr(12));
|
||||
define('ESC', chr(27));
|
||||
define('HASH','_'); // Enter
|
||||
define('STAR','*'); // Star Entry
|
||||
|
||||
// Keyboard presses
|
||||
define('KEY_LEFT',chr(136));
|
||||
define('KEY_RIGHT',chr(137));
|
||||
define('KEY_DOWN',chr(138));
|
||||
define('KEY_UP',chr(139));
|
||||
|
||||
// NOTE: This consts are effective output
|
||||
define('RED', ESC . 'A');
|
||||
define('GREEN', ESC . 'B');
|
||||
define('YELLOW', ESC . 'C');
|
||||
define('BLUE', ESC . 'D');
|
||||
define('MAGENTA', ESC . 'E');
|
||||
define('CYAN', ESC . 'F');
|
||||
define('WHITE', ESC . 'G');
|
||||
define('NEWBG', ESC . ']');
|
||||
|
||||
// Raw attributes - used when storing frames.
|
||||
define('R_RED',chr(1));
|
||||
define('R_GREEN',chr(2));
|
||||
define('R_YELLOW',chr(3));
|
||||
define('R_BLUE',chr(4));
|
||||
define('R_MAGENT',chr(5));
|
||||
define('R_CYAN',chr(6));
|
||||
define('R_WHITE',chr(7));
|
||||
define('FLASH',chr(8));
|
||||
|
||||
define('TCP_IAC',chr(255));
|
||||
define('TCP_DONT',chr(254));
|
||||
define('TCP_DO',chr(253));
|
||||
@ -67,18 +33,9 @@ define('TCP_SB',chr(250));
|
||||
define('TCP_AYT',chr(246));
|
||||
define('TCP_SE',chr(240));
|
||||
|
||||
define('TCP_OPT_LINEMODE',chr(34));
|
||||
define('TCP_OPT_TERMTYPE',chr(24));
|
||||
define('TCP_OPT_SUP_GOAHEAD',chr(3));
|
||||
define('TCP_OPT_ECHO',chr(1));
|
||||
define('TCP_BINARY',chr(0));
|
||||
|
||||
define('MSG_SENDORNOT', GREEN . 'KEY 1 TO SEND, 2 NOT TO SEND');
|
||||
define('MSG_SENT', GREEN . 'MESSAGE SENT - KEY _ TO CONTINUE');
|
||||
define('MSG_NOTSENT', GREEN . 'MESSAGE NOT SENT - KEY _ TO CONTINUE');
|
||||
|
||||
define('ERR_ROUTE', WHITE . 'MISTAKE?' . GREEN . 'TRY AGAIN OR TELL US ON *08');
|
||||
define('ERR_PAGE', ERR_ROUTE);
|
||||
define('ERR_PRIVATE', WHITE . 'PRIVATE PAGE' . GREEN . '- FOR EXPLANATION *37_..');
|
||||
define('ERR_DATABASE', RED . 'UNAVAILABLE AT PRESENT - PLSE TRY LATER');
|
||||
define('ERR_NOTSENT', WHITE . 'MESSAGE NOT SENT DUE TO AN ERROR');
|
||||
define('TCP_OPT_ECHO',chr(1));
|
||||
define('TCP_OPT_SUP_GOAHEAD',chr(3));
|
||||
define('TCP_OPT_TERMTYPE',chr(24));
|
||||
define('TCP_OPT_WINDOWSIZE',chr(31));
|
||||
define('TCP_OPT_LINEMODE',chr(34));
|
Reference in New Issue
Block a user