Updated Videotex frame to use Parser

This commit is contained in:
Deon George
2018-12-29 23:24:41 +11:00
parent 35b5bc2263
commit 390f52a460
12 changed files with 200 additions and 140 deletions

View File

@@ -56,16 +56,9 @@ abstract class Frame
public $fields = NULL; // The fields in this frame.
// Magic Fields that are pre-filled
protected $fieldmap = [
'a'=>'address#',
'd'=>'%date',
];
// Fields that are editable
private $fieldoptions = [
'p'=>['edit'=>TRUE,'mask'=>'*'], // Password
'u'=>['edit'=>TRUE], // User
't'=>['edit'=>TRUE], // Text
];
@@ -395,7 +388,7 @@ abstract class Frame
// Simulate a DB load
$o = new \App\Models\Frame;
$o->content = '';
$content = '';
$o->flags = ['ip'];
$o->type = 'a';
$o->frame = 999;
@@ -406,14 +399,16 @@ abstract class Frame
// Header
$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))).
$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 .= R_WHITE.str_repeat('+-',static::$frame_width/2-3).' '.R_RED.'01';
$o->content .= R_WHITE.'Name: '.ESC.str_repeat('u',5).' |'.str_repeat('+-',static::$frame_width/2-8).'|';
$o->content .= R_WHITE.'Date: '.ESC.str_repeat('d',17).' |'.str_repeat('+-',static::$frame_width/2-14).'|';
$o->content .= R_WHITE.'Address: '.ESC.str_repeat('t',19).' |'.str_repeat('+-',static::$frame_width/2-17).'|';
$o->content .= R_WHITE.' : '.ESC.str_repeat('t',19).' |'.str_repeat('+-',static::$frame_width/2-17).'|';
$content .= R_WHITE.str_repeat('+-',static::$frame_width/2-3).' '.R_RED.'01';
$content .= R_WHITE.'Name: '.ESC.str_repeat('t',5).' |'.str_repeat('+-',static::$frame_width/2-8).'|';
$content .= R_WHITE.'Date: '.ESC.str_repeat('d',17).' |'.str_repeat('+-',static::$frame_width/2-14).'|';
$content .= R_WHITE.'Address: '.ESC.str_repeat('t',19).' |'.str_repeat('+-',static::$frame_width/2-17).'|';
$content .= R_WHITE.' : '.ESC.str_repeat('t',19).' |'.str_repeat('+-',static::$frame_width/2-17).'|';
$o->content = $content;
return $o;
}

View File

@@ -5,7 +5,7 @@ namespace App\Classes\Frame;
use Illuminate\Support\Facades\Log;
use App\Classes\Frame as AbstractFrame;
use App\Classes\FrameFields;
use App\Classes\Parser\Videotex as VideotexParser;
class Videotex extends AbstractFrame
{
@@ -31,107 +31,11 @@ class Videotex extends AbstractFrame
// @todo Change to use a Parser, like we do for ANSI
public function fields($startline=1)
{
$infield = FALSE; // In a field
$fieldtype = NULL; // Type of field
$fieldlength = 0; // Length of field
// $fieldadrline = 1;
$o = new VideotexParser($this->frame->content,$startline);
$this->output .= (string)$o;
// Scan the frame for a field start
for ($y=$startline-1;$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*static::$frame_width+$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 .= static::$if_filler;
} else {
if ($infield) {
if ($byte == $fieldtype) {
$fieldlength++;
$byte = ord(static::$if_filler); // Replace field with static::$if_filler.
if ($fieldx === FALSE) {
$fieldx = $x;
$fieldy = $y;
}
// Is this a magic field?
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,static::$if_filler);
$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);
}
}
$this->fields = $o->fields;
}
public function strlenv($text):int {

View File

@@ -4,4 +4,27 @@ namespace App\Classes;
abstract class Parser
{
protected $content = '';
protected $startline = 0;
public $fields = NULL;
// Magic Fields that are pre-filled
protected $fieldmap = [
'a'=>'address#',
'd'=>'%date',
];
public function __construct(string $content,int $startline=1)
{
$this->content = $content;
$this->startline = $startline;
$this->fields = collect();
}
public function __toString(): string
{
return $this->parse($this->startline);
}
abstract protected function parse($startline): string;
}

View File

@@ -9,22 +9,6 @@ use App\Classes\Parser as AbstractParser;
use App\Classes\Frame\Ansi as AnsiFrame;
class Ansi extends AbstractParser {
private $content = '';
private $startline = 0;
public $fields = NULL;
public function __construct(string $content,int $startline=1)
{
$this->content = $content;
$this->startline = $startline;
$this->fields = collect();
}
public function __toString(): string
{
return $this->parse($this->startline);
}
/**
* Parse a string and look for the next character that is not $char
*
@@ -48,7 +32,7 @@ class Ansi extends AbstractParser {
* @param int $offset
* @return string
*/
private function parse($startline): string
protected function parse($startline): string
{
// Our starting coordinates
$x = 1;

View File

@@ -0,0 +1,122 @@
<?php
namespace App\Classes\Parser;
use Illuminate\Support\Facades\Log;
use App\Classes\FrameFields;
use App\Classes\Parser as AbstractParser;
use App\Classes\Frame\Videotex as VideotexFrame;
class Videotex extends AbstractParser
{
protected function parse($startline): string
{
// Our starting coordinates
$output = '';
$infield = FALSE; // In a field
$fieldtype = NULL; // Type of field
$fieldlength = 0; // Length of field
// $fieldadrline = 1;
// Scan the frame for a field start
for ($y=$startline-1;$y<=VideotexFrame::$frame_length;$y++)
{
// Fields can only be on a single line
$fieldx = $fieldy = FALSE;
for ($x=0;$x<VideotexFrame::$frame_width;$x++)
{
$posn = $y*VideotexFrame::$frame_width+$x;
// If the frame is not big enough, fill it with spaces.
$byte = ord(isset($this->content{$posn}) ? $this->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->content,$posn+1,1))%128;
$output .= VideotexFrame::$if_filler;
} else {
if ($infield) {
if ($byte == $fieldtype) {
$fieldlength++;
$byte = ord(VideotexFrame::$if_filler); // Replace field with VideotexFrame::$if_filler.
if ($fieldx === FALSE) {
$fieldx = $x;
$fieldy = $y;
}
// Is this a magic field?
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');
$output = rtrim($output,VideotexFrame::$if_filler);
$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 Field found at [%s,%s], Type: %s, Length: %s',$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->content,$posn,40-$x) === str_repeat(' ',40-$x)) {
$output .= CR . LF;
break;
}
if (! $infield OR $fieldlength > 1)
$output .= ($byte < 32) ? ESC.chr($byte+64) : chr($byte);
}
}
return $output;
}
}

View File

@@ -230,7 +230,7 @@ abstract class Server {
// If we are the main login screen, see if it is a new user
if ($fo->isCUG(0))
{
if ($current['field']->type == 'u' AND array_get($fielddata,$current['fieldnum']) == 'NEW')
if ($current['field']->type == 't' AND array_get($fielddata,$current['fieldnum']) == 'NEW')
{
$action = ACTION_GOTO;
$page = ['frame'=>'981']; // @todo This should be in the DB.
@@ -392,7 +392,7 @@ abstract class Server {
$page = $ao->page;
} else {
$this->sendBaseline($client, RED . 'NO method exists...');
$this->sendBaseline($client, RED.'NO method exists...');
$mode = MODE_RFSENT;
}
@@ -404,9 +404,19 @@ abstract class Server {
$mode = MODE_RFNOTSENT;
// If a Control method was rejected, we can clear it
if ($control AND $method->count())
if ($control AND $method->count()) {
$method->pop();
if ($method->count()) {
$control = $method->last()->state['control'];
} else {
$mode = $save->state['mode'];
$action = $save->state['action'];
$control = FALSE;
}
}
break;
case STAR:
@@ -682,6 +692,19 @@ abstract class Server {
if ($history->count() > 1)
$history->pop();
if ($control AND $method->count()) {
$method->pop();
if ($method->count()) {
$control = $method->last()->state['control'];
} else {
$mode = $save->state['mode'];
$action = $save->state['action'];
$control = FALSE;
}
}
$page = $history->last();
$this->log('debug','Backing up to:',$page);

View File

@@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Model;
class Frame extends Model
{
public $cache_content = '';
public function cug()
{
return $this->belongsTo(CUG::class);
@@ -32,9 +34,14 @@ class Frame extends Model
*/
public function getContentAttribute()
{
return is_resource($this->attributes['content'])
? stream_get_contents($this->attributes['content'])
: $this->attributes['content'];
// For stream resources, we need to cache this result.
if (! $this->cache_content) {
$this->cache_content = is_resource($this->attributes['content'])
? stream_get_contents($this->attributes['content'])
: $this->attributes['content'];
}
return $this->cache_content;
}
/**