Enabled ANSI and Videotex servers and frames

This commit is contained in:
Deon George 2018-12-09 09:43:18 +11:00
parent 6c91c69bd9
commit 0eb71ef7c6
11 changed files with 429 additions and 243 deletions

View File

@ -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';

View 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);
}
}

View 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);
}
}

View File

@ -9,13 +9,26 @@ 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)
{
$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');
@ -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();
}

View File

@ -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);
}
}

View File

@ -1,11 +0,0 @@
<?php
namespace App\Classes\Server;
use App\Classes\Server as AbstractServer;
use Illuminate\Support\Facades\Log;
class VideoTex extends AbstractServer {
}

View 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);
}
}

View File

@ -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();

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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));