Internal rework pending editframe

This commit is contained in:
Deon George 2019-07-12 10:42:01 +07:00
parent 4f79a1a997
commit 264747e2f3
14 changed files with 611 additions and 428 deletions

View File

@ -2,18 +2,36 @@
namespace App\Classes; namespace App\Classes;
use App\Classes\Control\EditFrame;
use App\Classes\Control\Register; use App\Classes\Control\Register;
use App\Classes\Control\Telnet; use App\Classes\Control\Telnet;
abstract class Control abstract class Control
{ {
// Has this control class finished with input
protected $complete = FALSE; protected $complete = FALSE;
// The server object that is running this control class
protected $so = NULL; protected $so = NULL;
// The frame applicable for this control (not the current rendered frame, thats in $so)
protected $fo = NULL;
/**
* What is the state of the server outside of this control.
* Should only contain
* + mode = Mode to follow outside of the control method
* + action = Action to run after leaving the control method
*
* @var array
*/
public $state = []; public $state = [];
public function __construct(Server $so) { public function __construct(Server $so,Frame $fo=NULL) {
$this->so = $so; $this->so = $so;
$this->fo = $fo;
// Boot control, preparing anything before keyboard entry
$this->boot(); $this->boot();
} }
@ -31,8 +49,11 @@ abstract class Control
} }
// @todo Change to Dynamic Calls by the existence of files in App\Classes\Control // @todo Change to Dynamic Calls by the existence of files in App\Classes\Control
public static function factory(string $name, Server $so) { public static function factory(string $name,Server $so,Frame $fo=NULL) {
switch ($name) { switch ($name) {
case 'editframe':
return new EditFrame($so,$fo);
case 'register': case 'register':
return new Register($so); return new Register($so);
@ -44,5 +65,5 @@ abstract class Control
} }
} }
abstract public function handle(string $char); abstract public function handle(string $read);
} }

View File

@ -12,7 +12,6 @@ use Illuminate\Support\Facades\Validator;
* Class Register handles registration * Class Register handles registration
* *
* @todo REMOVE the force .WHITE at the end of each sendBaseline() * @todo REMOVE the force .WHITE at the end of each sendBaseline()
*
* @package App\Classes\Control * @package App\Classes\Control
*/ */
class Register extends Control class Register extends Control
@ -21,7 +20,7 @@ class Register extends Control
protected function boot() protected function boot()
{ {
$this->so->sendBaseline($this->so->client(),GREEN.'Select User Name'.WHITE); $this->so->sendBaseline($this->so->co,GREEN.'Select User Name'.WHITE);
} }
/** /**
@ -37,124 +36,114 @@ class Register extends Control
*/ */
public function handle(string $read,array $current=[]) public function handle(string $read,array $current=[])
{ {
// Ignore CR
if ($read == CR)
return '';
// If we got a # we'll be completing field input. // If we got a # we'll be completing field input.
if ($read == HASH OR $read == LF) { if ($read == HASH OR $read == LF) {
// Does our field have data...
if (array_get($current['fielddata'],$current['fieldnum'])) {
switch ($current['fieldnum']) {
// Username
case 0:
// See if the requested username already exists
if (User::where('login', $current['fielddata'][$current['fieldnum']])->exists()) {
$this->so->sendBaseline($this->so->co,RED.'USER ALREADY EXISTS'.WHITE);
// Our registration page return '';
// @todo get this from the DB }
if ($current['page']['frame'] == '981') {
// Does our field have data... $this->data['user'] = $current['fielddata'][$current['fieldnum']];
if (array_get($current['fielddata'],$current['fieldnum'])) { $this->so->sendBaseline($this->so->co,GREEN.'Enter Real Name'.WHITE);
switch ($current['fieldnum']) {
// Username
case 0:
// See if the requested username already exists
if (User::where('login', $current['fielddata'][$current['fieldnum']])->exists()) {
$this->so->sendBaseline($this->so->client(), RED . 'USER ALREADY EXISTS'.WHITE);
return ''; break;
}
$this->data['user'] = $current['fielddata'][$current['fieldnum']]; // Real Name
$this->so->sendBaseline($this->so->client(), GREEN . 'Enter Real Name'.WHITE); case 1:
$this->data['name'] = $current['fielddata'][$current['fieldnum']];
$this->so->sendBaseline($this->so->co,GREEN.'Enter Email Address'.WHITE);
break; break;
// Real Name // Email Address
case 1: case 2:
$this->data['name'] = $current['fielddata'][$current['fieldnum']]; if (Validator::make(['email'=>$current['fielddata'][$current['fieldnum']]],[
$this->so->sendBaseline($this->so->client(), GREEN . 'Enter Email Address'.WHITE); 'email'=>'email',
])->fails()) {
$this->so->sendBaseline($this->so->co,RED.'INVALID EMAIL ADDRESS'.WHITE);
break; return '';
};
// Email Address // See if the requested email already exists
case 2: if (User::where('email', $current['fielddata'][$current['fieldnum']])->exists()) {
if (Validator::make(['email'=>$current['fielddata'][$current['fieldnum']]],[ $this->so->sendBaseline($this->so->co,RED.'USER ALREADY EXISTS'.WHITE);
'email'=>'email',
])->fails()) {
$this->so->sendBaseline($this->so->client(), RED . 'INVALID EMAIL ADDRESS'.WHITE);
return ''; return '';
}; }
// See if the requested email already exists $this->data['email'] = $current['fielddata'][$current['fieldnum']];
if (User::where('email', $current['fielddata'][$current['fieldnum']])->exists()) { $this->data['token'] = sprintf('%06.0f',rand(0,999999));
$this->so->sendBaseline($this->so->client(), RED . 'USER ALREADY EXISTS'.WHITE);
return ''; $this->so->sendBaseline($this->so->co,YELLOW.'PROCESSING...'.WHITE);
} Mail::to($this->data['email'])->sendNow(new SendToken($this->data['token']));
$this->data['email'] = $current['fielddata'][$current['fieldnum']]; if (Mail::failures()) {
$this->data['token'] = sprintf('%06.0f',rand(0,999999)); dump('Failure?');
$this->so->sendBaseline($this->so->client(), YELLOW . 'PROCESSING...'.WHITE); dump(Mail::failures());
Mail::to($this->data['email'])->sendNow(new SendToken($this->data['token'])); }
if (Mail::failures()) { $this->so->sendBaseline($this->so->co,GREEN.'Enter Password'.WHITE);
dump('Failure?');
dump(Mail::failures()); break;
}
$this->so->sendBaseline($this->so->client(), GREEN . 'Enter Password'.WHITE); // Enter Password
case 3:
$this->data['password'] = $current['fielddata'][$current['fieldnum']];
$this->so->sendBaseline($this->so->co,GREEN.'Confirm Password'.WHITE);
break; break;
// Enter Password // Confirm Password
case 3: case 4:
$this->data['password'] = $current['fielddata'][$current['fieldnum']]; if ($this->data['password'] !== $current['fielddata'][$current['fieldnum']]) {
$this->so->sendBaseline($this->so->client(), GREEN . 'Confirm Password'.WHITE); $this->so->sendBaseline($this->so->co,RED.'PASSWORD DOESNT MATCH, *09 TO START AGAIN'.WHITE);
break; return '';
}
// Confirm Password $this->so->sendBaseline($this->so->co,GREEN.'Enter Location'.WHITE);
case 4:
if ($this->data['password'] !== $current['fielddata'][$current['fieldnum']]) {
$this->so->sendBaseline($this->so->client(), RED . 'PASSWORD DOESNT MATCH, *09 TO START AGAIN'.WHITE);
return ''; break;
}
$this->so->sendBaseline($this->so->client(), GREEN . 'Enter Location'.WHITE); // Enter Location
case 5:
$this->data['location'] = $current['fielddata'][$current['fieldnum']];
$this->so->sendBaseline($this->so->co,GREEN.'Enter TOKEN emailed to you'.WHITE);
break; break;
// Enter Location // Enter Token
case 5: case 6:
$this->data['location'] = $current['fielddata'][$current['fieldnum']]; if ($this->data['token'] !== $current['fielddata'][$current['fieldnum']]) {
$this->so->sendBaseline($this->so->client(), GREEN . 'Enter TOKEN emailed to you'.WHITE); $this->so->sendBaseline($this->so->co,RED.'TOKEN DOESNT MATCH, *09 TO START AGAIN'.WHITE);
break; return '';
}
// Enter Token break;
case 6:
if ($this->data['token'] !== $current['fielddata'][$current['fieldnum']]) {
$this->so->sendBaseline($this->so->client(), RED . 'TOKEN DOESNT MATCH, *09 TO START AGAIN'.WHITE);
return ''; default:
} $this->so->sendBaseline($this->so->co,RED.'HUH?');
}
break; } else {
// If we are MODE_BL, we need to return the HASH, otherwise nothing.
default: if (in_array($this->state['mode'],[MODE_BL,MODE_SUBMITRF,MODE_RFNOTSENT])) {
$this->so->sendBaseline($this->so->client(), RED . 'HUH?'); return $read;
}
} else { } else {
// If we are MODE_BL, we need to return the HASH, otherwise nothing. $this->so->sendBaseline($this->so->co,RED.'FIELD REQUIRED...'.WHITE);
if (in_array($this->state['mode'],[MODE_BL,MODE_SUBMITRF,MODE_RFNOTSENT])) {
return $read;
} else { return '';
$this->so->sendBaseline($this->so->client(), RED . 'FIELD REQUIRED...'.WHITE);
return '';
}
} }
} }
} }
@ -174,14 +163,14 @@ class Register extends Control
$o->location = $this->data['location']; $o->location = $this->data['location'];
$o->save(); $o->save();
$this->so->sendBaseline($this->so->client(), GREEN . 'ACCOUNT CREATED, PRESS '.HASH.' TO CONTINUE...'.WHITE); $this->so->sendBaseline($this->so->co,GREEN.'ACCOUNT CREATED, PRESS '.HASH.' TO CONTINUE...'.WHITE);
$this->state['action'] = ACTION_NEXT; $this->state['action'] = ACTION_NEXT;
// Add to CUG 0 // Add to CUG 0
$o->cugs()->attach(0); $o->cugs()->attach(0);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->so->sendBaseline($this->so->client(), RED . 'SOMETHING WENT WRONG...'.WHITE); $this->so->sendBaseline($this->so->co,RED.'SOMETHING WENT WRONG...'.WHITE);
$this->so->log('error',$e->getMessage()); $this->so->log('error',$e->getMessage());
$this->state['action'] = ACTION_RELOAD; $this->state['action'] = ACTION_RELOAD;
} }

View File

@ -2,11 +2,12 @@
namespace App\Classes; namespace App\Classes;
use App\Models\Mode; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\User; use App\User;
use App\Models\CUG; use App\Models\{CUG,Mode};
use App\Models\Frame as FrameModel;
/** /**
* Handles all aspects of frame * Handles all aspects of frame
@ -34,12 +35,14 @@ use App\Models\CUG;
*/ */
abstract class Frame abstract class Frame
{ {
protected $frame = NULL; // This holds the parser object for this frame.
protected $output = ''; protected $po = NULL;
protected $startline = 1;
// This holds the frame object as retrieved from the DB
protected $fo = NULL;
// All this vars should be overridden in the child class
/* /*
// All this vars should be overridden in the child class
protected $frame_length = 22; protected $frame_length = 22;
protected $frame_width = 40; protected $frame_width = 40;
@ -54,9 +57,8 @@ abstract class Frame
const FRAMETYPE_LOGIN = 'l'; const FRAMETYPE_LOGIN = 'l';
const FRAMETYPE_TERMINATE = 't'; const FRAMETYPE_TERMINATE = 't';
public $fields = NULL; // The fields in this frame.
// Fields that are editable // Fields that are editable
// @todo This needs rework.
private $fieldoptions = [ private $fieldoptions = [
'p'=>['edit'=>TRUE,'mask'=>'*'], // Password 'p'=>['edit'=>TRUE,'mask'=>'*'], // Password
't'=>['edit'=>TRUE], // Text 't'=>['edit'=>TRUE], // Text
@ -65,38 +67,44 @@ abstract class Frame
// @todo Move this to the database // @todo Move this to the database
private $header = RED.'T'.BLUE.'E'.GREEN.'S'.YELLOW.'T'.MAGENTA.'!'; private $header = RED.'T'.BLUE.'E'.GREEN.'S'.YELLOW.'T'.MAGENTA.'!';
public function __construct(\App\Models\Frame $o) public function __construct(FrameModel $o)
{ {
$this->frame = $o; $this->fo = $o;
$startline = 1;
$this->output = $this->frame->cls ? CLS : HOME; if ($this->fo->exists) {
if (! $this->hasFlag('ip') AND (! $this->isCUG(0) OR $this->type() !== self::FRAMETYPE_LOGIN)) {
$startline = 2;
if (! $this->hasFlag('ip') AND (! $this->isCUG(0) OR $this->type() !== self::FRAMETYPE_LOGIN)) { } elseif ($this->isCUG(0) AND $this->type() === self::FRAMETYPE_LOGIN) {
// Set the page header: CUG/Site Name | Page # | Cost $startline = 2;
$this->output .= $this->render_header($this->header). }
$this->render_page($this->frame->frame,$this->frame->index).
$this->render_cost($this->frame->cost);
$this->startline = 2;
} elseif ($this->isCUG(0) AND $this->type() === self::FRAMETYPE_LOGIN) {
$this->startline = 2;
$this->output .= str_repeat(DOWN,$this->startline-1);
} }
// Calculate fields and render output. // Our parser object
$this->fields = collect(); // Fields in this frame. $this->po = $this->parser($startline);
$this->fields($this->startline);
} }
/** /**
* Render the frame * Render the frame
* *
* @return null|string * @return null|string
* @throws \Exception
*/ */
public function __toString() public function __toString()
{ {
return $this->output; $output = $this->fo->cls ? CLS : HOME;
if (! $this->hasFlag('ip') AND (! $this->isCUG(0) OR $this->type() !== self::FRAMETYPE_LOGIN)) {
$output .= $this->render_header($this->header).
$this->render_page($this->fo->frame,$this->fo->index).
$this->render_cost($this->fo->cost);
} elseif ($this->isCUG(0) AND $this->type() === self::FRAMETYPE_LOGIN) {
$output .= str_repeat(DOWN,1);
}
return $output.(string)$this->po;
} }
/** /**
@ -106,9 +114,9 @@ abstract class Frame
*/ */
public function alts(Mode $o) public function alts(Mode $o)
{ {
return \App\Models\Frame::where('frame',$this->frame()) return FrameModel::where('frame',$this->fo->frame)
->where('index',$this->index()) ->where('index',$this->index())
->where('id','<>',$this->frame->id) ->where('id','<>',$this->fo->id)
->where('mode_id',$o->id) ->where('mode_id',$o->id)
->where('access',1) ->where('access',1)
->limit(9); ->limit(9);
@ -119,23 +127,33 @@ abstract class Frame
*/ */
public function created() public function created()
{ {
return $this->frame->created_at; return $this->fo->created_at;
} }
/** /**
* Convert the frame from Binary to Output * Return fields within the frame.
* Look for fields within the frame.
*
* @param int $startline
*/ */
abstract public function fields($startline=0); public function fields()
{
return $this->po->fields;
}
/** /**
* Returns the current frame. * Returns the current frame.
*/ */
public function frame() public function frame()
{ {
return $this->frame->frame; return $this->fo->frame;
}
public function frame_length()
{
return static::$frame_length;
}
public function frame_width()
{
return static::$frame_width;
} }
/** /**
@ -149,7 +167,7 @@ abstract class Frame
public function getCUG() public function getCUG()
{ {
$co = NULL; $co = NULL;
$frame = $this->frame->frame; $frame = $this->fo->frame;
while (! $co) while (! $co)
{ {
@ -171,7 +189,7 @@ abstract class Frame
*/ */
public function getField(int $id) public function getField(int $id)
{ {
return $this->fields->get($id); return $this->fields()->get($id);
} }
/** /**
@ -183,7 +201,7 @@ abstract class Frame
*/ */
public function getFieldId($type='edit',$after=0) public function getFieldId($type='edit',$after=0)
{ {
return $this->fields return $this->fields()
->search(function($item,$key) use ($type,$after) { ->search(function($item,$key) use ($type,$after) {
return $key >= $after AND $this->isFieldEditable($item->type); return $key >= $after AND $this->isFieldEditable($item->type);
}); });
@ -204,7 +222,7 @@ abstract class Frame
*/ */
public function hasFlag($flag) public function hasFlag($flag)
{ {
return $this->frame->hasFlag($flag); return $this->fo->hasFlag($flag);
} }
/** /**
@ -214,7 +232,7 @@ abstract class Frame
*/ */
public function id() public function id()
{ {
return $this->frame->id; return $this->fo->id;
} }
/** /**
@ -224,7 +242,7 @@ abstract class Frame
*/ */
public function index() public function index()
{ {
return $this->frame->index; return $this->fo->index;
} }
/** /**
@ -232,16 +250,25 @@ abstract class Frame
*/ */
public function index_next() public function index_next()
{ {
return chr(ord($this->frame->index)+1); return chr(ord($this->fo->index)+1);
}
/**
* Return the previous index
*/
public function index_prev()
{
return $this->fo->index == 'a' ? 'a' : chr(ord($this->fo->index)-1);
} }
public function isAccessible():bool public function isAccessible():bool
{ {
return $this->frame->access ? TRUE : FALSE; return $this->fo->access ? TRUE : FALSE;
} }
/** /**
* Determine if the frame is a particular CUG * Determine if the frame is a particular CUG
*
* @param int $cug * @param int $cug
* @return bool * @return bool
*/ */
@ -273,10 +300,10 @@ abstract class Frame
*/ */
public function isFramePublic(): bool public function isFramePublic(): bool
{ {
return $this->frame->public ? TRUE : FALSE; return $this->fo->public ? TRUE : FALSE;
} }
// @todo To implement
// @todo To implement
public function isOwner(User $o):bool public function isOwner(User $o):bool
{ {
return FALSE; return FALSE;
@ -287,7 +314,7 @@ abstract class Frame
*/ */
public function page(bool $as_array=FALSE) public function page(bool $as_array=FALSE)
{ {
return $as_array ? ['frame'=>$this->frame->frame,'index'=>$this->frame->index] : $this->frame->page; return $as_array ? ['frame'=>$this->fo->frame,'index'=>$this->fo->index] : $this->fo->page;
} }
/** /**
@ -296,11 +323,19 @@ abstract class Frame
* @param bool $as_array * @param bool $as_array
* @return mixed * @return mixed
*/ */
public function pagenext(bool $as_array=FALSE) public function page_next(bool $as_array=FALSE)
{ {
return $as_array ? ['frame'=>$this->frame->frame,'index'=>$this->index_next()] : $this->frame->frame.$this->index_next(); return $as_array ? ['frame'=>$this->fo->frame,'index'=>$this->index_next()] : $this->fo->frame.$this->index_next();
} }
/**
* Load the parser
*
* @param int $startline
* @return Parser
*/
abstract protected function parser(int $startline): Parser;
/** /**
* Render the cost of the frame * Render the cost of the frame
* *
@ -359,6 +394,8 @@ abstract class Frame
* Get the route for the key press * Get the route for the key press
* *
* @param string $read * @param string $read
* @return string
* @throws \Exception
*/ */
public function route(string $read) public function route(string $read)
{ {
@ -366,11 +403,11 @@ abstract class Frame
throw new \Exception('Routes are single digit'); throw new \Exception('Routes are single digit');
// If we dont have a route record... // If we dont have a route record...
if (! $this->frame->route) if (! $this->fo->route)
return '*'; return '*';
$key = 'r'.$read; $key = 'r'.$read;
return $this->frame->route->{$key}; return $this->fo->route->{$key};
} }
/** /**
@ -381,12 +418,12 @@ abstract class Frame
* @param $text * @param $text
* @return int * @return int
*/ */
abstract function strlenv($text):int; abstract public static function strlenv($text):int;
public static function testFrame(Server $so) public static function testFrame()
{ {
// Simulate a DB load // Simulate a DB load
$o = new \App\Models\Frame; $o = new FrameModel;
$content = ''; $content = '';
$o->flags = ['ip']; $o->flags = ['ip'];
@ -399,7 +436,7 @@ abstract class Frame
// Header // Header
$sid = R_RED.'T'.R_BLUE.'E'.R_GREEN.'S'.R_YELLOW.'T'; $sid = R_RED.'T'.R_BLUE.'E'.R_GREEN.'S'.R_YELLOW.'T';
$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)-static::strlenv($sid))).
R_WHITE.str_repeat('9',static::$pagenum_length).'a'.R_RED.sprintf('%07.0f',999).'u'; R_WHITE.str_repeat('9',static::$pagenum_length).'a'.R_RED.sprintf('%07.0f',999).'u';
$content .= R_WHITE.str_repeat('+-',static::$frame_width/2-3).' '.R_RED.'01'; $content .= R_WHITE.str_repeat('+-',static::$frame_width/2-3).' '.R_RED.'01';
@ -410,7 +447,7 @@ abstract class Frame
$o->content = $content; $o->content = $content;
return $o; return new static($o);
} }
/** /**
@ -418,6 +455,6 @@ abstract class Frame
*/ */
public function type() public function type()
{ {
return $this->frame->type(); return $this->fo->type();
} }
} }

View File

@ -24,7 +24,7 @@ class Login extends Action
$this->mode = 2; // MODE_FIELD $this->mode = 2; // MODE_FIELD
// $this->action = 2; // ACTION_GOTO // $this->action = 2; // ACTION_GOTO
$this->so->sendBaseline($this->so->client(),RED.'INVALID DETAILS, TRY AGAIN *00'); $this->so->sendBaseline($this->so->co,RED.'INVALID DETAILS, TRY AGAIN *00');
return FALSE; return FALSE;
} }
@ -33,7 +33,7 @@ class Login extends Action
$this->uo = User::where('login',array_get($fielddata,0))->firstOrFail(); $this->uo = User::where('login',array_get($fielddata,0))->firstOrFail();
} catch (ModelNotFoundException $e) { } catch (ModelNotFoundException $e) {
$this->so->sendBaseline($this->so->client(),RED.'USER NOT FOUND, TRY AGAIN *00'); $this->so->sendBaseline($this->so->co,RED.'USER NOT FOUND, TRY AGAIN *00');
return FALSE; return FALSE;
} }
@ -41,7 +41,7 @@ class Login extends Action
if ($this->uo->password != array_get($fielddata,1)) if ($this->uo->password != array_get($fielddata,1))
{ {
$this->uo = new User; $this->uo = new User;
$this->so->sendBaseline($this->so->client(),RED.'INVALID PASSWORD, TRY AGAIN *00'); $this->so->sendBaseline($this->so->co,RED.'INVALID PASSWORD, TRY AGAIN *00');
return FALSE; return FALSE;
} }

View File

@ -2,12 +2,14 @@
namespace App\Classes\Frame; namespace App\Classes\Frame;
use App\Classes\Parser;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Classes\Frame as AbstractFrame; use App\Classes\Frame;
use App\Classes\Parser\Ansi as AnsiParser; use App\Classes\Parser\Ansi as AnsiParser;
use App\Models\Frame as FrameModel;
class Ansi extends AbstractFrame class Ansi extends Frame
{ {
public static $frame_length = 22; public static $frame_length = 22;
public static $frame_width = 80; public static $frame_width = 80;
@ -19,7 +21,7 @@ class Ansi extends AbstractFrame
public static $if_filler = '.'; public static $if_filler = '.';
public function __construct(\App\Models\Frame $o,string $msg='') public function __construct(FrameModel $o,string $msg='')
{ {
parent::__construct($o); parent::__construct($o);
@ -28,15 +30,12 @@ class Ansi extends AbstractFrame
$this->output .= ESC.'[24;0f'.$msg.HOME; $this->output .= ESC.'[24;0f'.$msg.HOME;
} }
public function fields($startline=1) protected function parser(int $startline): Parser
{ {
$o = new AnsiParser($this->frame->content,$startline); return new AnsiParser($this->fo->content,self::$frame_width,$startline);
$this->output .= (string)$o;
$this->fields = $o->fields;
} }
public function strlenv($text):int { public static function strlenv($text):int {
return strlen($text ? preg_replace('/'.ESC.'\[[0-9;?]+[a-zA-Z]/','',$text) : $text); return strlen($text ? preg_replace('/'.ESC.'\[[0-9;?]+[a-zA-Z]/','',$text) : $text);
} }
} }

View File

@ -4,10 +4,12 @@ namespace App\Classes\Frame;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Classes\Frame as AbstractFrame; use App\Classes\Frame;
use App\Classes\Parser;
use App\Classes\Parser\Videotex as VideotexParser; use App\Classes\Parser\Videotex as VideotexParser;
use App\Models\Frame as FrameModel;
class Videotex extends AbstractFrame class Videotex extends Frame
{ {
public static $frame_length = 22; public static $frame_length = 22;
public static $frame_width = 40; public static $frame_width = 40;
@ -19,7 +21,7 @@ class Videotex extends AbstractFrame
public static $if_filler = '.'; public static $if_filler = '.';
public function __construct(\App\Models\Frame $o,string $msg='') public function __construct(FrameModel $o,string $msg='')
{ {
parent::__construct($o); parent::__construct($o);
@ -28,17 +30,12 @@ class Videotex extends AbstractFrame
$this->output .= HOME.UP.$msg.HOME; $this->output .= HOME.UP.$msg.HOME;
} }
// @todo Change to use a Parser, like we do for ANSI protected function parser(int $startline): Parser
public function fields($startline=1)
{ {
return new VideotexParser($this->fo->content,self::$frame_width,$startline);
$o = new VideotexParser($this->frame->content,$startline);
$this->output .= (string)$o;
$this->fields = $o->fields;
} }
public function strlenv($text):int { public static function strlenv($text):int {
return strlen($text)-substr_count($text,ESC); return strlen($text)-substr_count($text,ESC);
} }
} }

View File

@ -2,11 +2,22 @@
namespace App\Classes; namespace App\Classes;
/**
* The Frame Parser looks into frames for ESC codes that renders dynamic information
*/
abstract class Parser abstract class Parser
{ {
protected $content = ''; // Fields in the frame
protected $startline = 0; public $fields = [];
public $fields = NULL;
// Parsed frame, ready to send to client
public $output = '';
// Position array of frame control chars
protected $frame_data = [];
// Position array of frame chars
protected $frame_content = [];
// Magic Fields that are pre-filled // Magic Fields that are pre-filled
protected $fieldmap = [ protected $fieldmap = [
@ -14,17 +25,16 @@ abstract class Parser
'd'=>'%date', 'd'=>'%date',
]; ];
public function __construct(string $content,int $startline=1) public function __construct(string $content,int $width,int $startline=1)
{ {
$this->content = $content;
$this->startline = $startline;
$this->fields = collect(); $this->fields = collect();
$this->output = $this->parse($startline,$content,$width);
} }
public function __toString(): string public function __toString(): string
{ {
return $this->parse($this->startline); return $this->output;
} }
abstract protected function parse($startline): string; abstract protected function parse(int $startline,string $content,int $width): string;
} }

View File

@ -16,11 +16,11 @@ class Ansi extends AbstractParser {
* @param int $start * @param int $start
* @return bool|int * @return bool|int
*/ */
private function findEOF(string $char,int $start) private function findEOF(string $char,int $start,string $content)
{ {
for ($c=$start;$c <= strlen($this->content);$c++) for ($c=$start;$c <= strlen($content);$c++)
{ {
if ($this->content{$c} != $char) if ($content{$c} != $char)
return $c-$start; return $c-$start;
} }
@ -32,7 +32,7 @@ class Ansi extends AbstractParser {
* @param int $offset * @param int $offset
* @return string * @return string
*/ */
protected function parse($startline): string protected function parse(int $startline,string $content,int $width): string
{ {
// Our starting coordinates // Our starting coordinates
$x = 1; $x = 1;
@ -40,10 +40,10 @@ class Ansi extends AbstractParser {
$output = ''; $output = '';
// Scan the frame for a field start // Scan the frame for a field start
for ($c=0; $c<=strlen($this->content); $c++) for ($c=0; $c<=strlen($content); $c++)
{ {
// If the frame is not big enough, fill it with spaces. // If the frame is not big enough, fill it with spaces.
$byte = isset($this->content{$c}) ? $this->content{$c} : ' '; $byte = isset($content{$c}) ? $content{$c} : ' ';
$advance = 0; $advance = 0;
switch ($byte) { switch ($byte) {
@ -58,7 +58,7 @@ class Ansi extends AbstractParser {
case ESC: case ESC:
$advance = 1; $advance = 1;
// Is the next byte something we know about // Is the next byte something we know about
$nextbyte = isset($this->content{$c+$advance}) ? $this->content{$c+$advance} : ' '; $nextbyte = isset($content{$c+$advance}) ? $content{$c+$advance} : ' ';
switch ($nextbyte) { switch ($nextbyte) {
case '[': case '[':
@ -68,7 +68,7 @@ class Ansi extends AbstractParser {
// Find our end CSI param // Find our end CSI param
$matches = []; $matches = [];
$a = preg_match('/([0-9]+[;]?)+([a-zA-Z])/',$this->content,$matches,NULL,$c+$advance); $a = preg_match('/([0-9]+[;]?)+([a-zA-Z])/',$content,$matches,NULL,$c+$advance);
if (! $a) if (! $a)
break; break;
@ -76,6 +76,13 @@ class Ansi extends AbstractParser {
$advance += strlen($matches[0])-1; $advance += strlen($matches[0])-1;
$chars .= $matches[0]; $chars .= $matches[0];
if (! isset($this->frame_data[$y][$x]))
$this->frame_data[$y][$x] = '';
else
$this->frame_data[$y][$x] .= '|';
$this->frame_data[$y][$x] .= $matches[0];
switch ($matches[2]) { switch ($matches[2]) {
// We ignore 'm' they are color CSIs // We ignore 'm' they are color CSIs
case 'm': break; case 'm': break;
@ -96,10 +103,11 @@ class Ansi extends AbstractParser {
break; break;
default: default:
$c--; // Allow for the original ESC // Allow for the original ESC
$c--;
$advance++; $advance++;
$fieldtype = ord($nextbyte)%128; // @todo Do we need the %128 for ANSI? $fieldtype = ord($nextbyte);
$fieldlength = $this->findEOF(chr($fieldtype),$c+2)+1; $fieldlength = $this->findEOF(chr($fieldtype),$c+2,$content)+1;
$byte = ''; $byte = '';
@ -122,6 +130,7 @@ class Ansi extends AbstractParser {
$x++; $x++;
} }
$this->frame_content[$y][$x] = $byte;
$output .= $byte; $output .= $byte;
if ($advance) { if ($advance) {
@ -129,7 +138,7 @@ class Ansi extends AbstractParser {
$c += $advance; $c += $advance;
} }
if ($x > 80) { if ($x > $width) {
$x = 1; $x = 1;
$y++; $y++;
} }

View File

@ -10,7 +10,7 @@ use App\Classes\Frame\Videotex as VideotexFrame;
class Videotex extends AbstractParser class Videotex extends AbstractParser
{ {
protected function parse($startline): string protected function parse(int $startline,string $content,int $width): string
{ {
// Our starting coordinates // Our starting coordinates
$output = ''; $output = '';
@ -32,13 +32,13 @@ class Videotex extends AbstractParser
$posn = $y*VideotexFrame::$frame_width+$x; $posn = $y*VideotexFrame::$frame_width+$x;
// If the frame is not big enough, fill it with spaces. // If the frame is not big enough, fill it with spaces.
$byte = ord(isset($this->content{$posn}) ? $this->content{$posn} : ' ')%128; $byte = ord(isset($content{$posn}) ? $content{$posn} : ' ')%128;
// Check for start-of-field // Check for start-of-field
if ($byte == ord(ESC)) { // Esc designates start of field (Esc-K is end of edit) if ($byte == ord(ESC)) { // Esc designates start of field (Esc-K is end of edit)
$infield = TRUE; $infield = TRUE;
$fieldlength = 1; $fieldlength = 1;
$fieldtype = ord(substr($this->content,$posn+1,1))%128; $fieldtype = ord(substr($content,$posn+1,1))%128;
$output .= VideotexFrame::$if_filler; $output .= VideotexFrame::$if_filler;
} else { } else {
@ -107,8 +107,8 @@ class Videotex extends AbstractParser
} }
// truncate end of lines @todo havent validated this code or used it? // 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)) { if (isset($pageflags['tru']) && substr($content,$posn,$width-$x) === str_repeat(' ',$width-$x)) {
$output .= CR . LF; $output .= CR.LF;
break; break;
} }

View File

@ -13,11 +13,23 @@ use App\Models\Frame as FrameModel;
use App\Models\Mode; use App\Models\Mode;
abstract class Server { abstract class Server {
private $mo = NULL; // Our Mode object // Our Mode object, this determines if we are an ANSI or VIDEOTEX server
private $co = NULL; private $mo = NULL;
protected $blp = 0; // Size of Bottom Line Pollution
protected $baseline = ''; // Whats on the baseline currently // The client connection object of the currently connected client.
protected $pid = NULL; // Client PID public $co = NULL;
// The currently rendered Frame to the client of Frame/*
public $fo = NULL;
// Size of Bottom Line Pollution
protected $blp = 0;
// Whats on the baseline currently
protected $baseline = '';
// Client PID
protected $pid = NULL;
public function __construct(Mode $o) public function __construct(Mode $o)
{ {
@ -31,6 +43,7 @@ abstract class Server {
define('MODE_RFSENT', 6); define('MODE_RFSENT', 6);
define('MODE_RFERROR', 7); define('MODE_RFERROR', 7);
define('MODE_RFNOTSENT', 8); define('MODE_RFNOTSENT', 8);
define('MODE_CONTROL', 9); // Do nothing, a method is controlling input
define('ACTION_RELOAD', 1); define('ACTION_RELOAD', 1);
define('ACTION_GOTO', 2); define('ACTION_GOTO', 2);
@ -40,16 +53,11 @@ abstract class Server {
define('ACTION_TERMINATE', 6); define('ACTION_TERMINATE', 6);
define('ACTION_SUBMITRF', 7); // Offer to submit a response frame define('ACTION_SUBMITRF', 7); // Offer to submit a response frame
define('ACTION_STAR', 8); define('ACTION_STAR', 8);
define('ACTION_EDIT', 9); // Edit current frame
define('CONTROL_TELNET', 1); // Telnet session control define('CONTROL_TELNET', 1); // Telnet session control
define('CONTROL_METHOD', 2); // Send input to an external method define('CONTROL_METHOD', 2); // Send input to an external method
define('CONTROL_EDIT', 3); // Controller to edit frame
// Keyboard presses
define('KEY_DELETE', chr(8));
define('KEY_LEFT', chr(136));
define('KEY_RIGHT', chr(137));
define('KEY_DOWN', chr(138));
define('KEY_UP', chr(139));
define('TCP_IAC', chr(255)); define('TCP_IAC', chr(255));
define('TCP_DONT', chr(254)); define('TCP_DONT', chr(254));
@ -67,11 +75,12 @@ abstract class Server {
define('TCP_OPT_WINDOWSIZE', chr(31)); define('TCP_OPT_WINDOWSIZE', chr(31));
define('TCP_OPT_LINEMODE', chr(34)); define('TCP_OPT_LINEMODE', chr(34));
// Status messages
define('MSG_SENDORNOT', GREEN.'KEY 1 TO SEND, 2 NOT TO SEND'); define('MSG_SENDORNOT', GREEN.'KEY 1 TO SEND, 2 NOT TO SEND');
define('MSG_SENT', GREEN.'MESSAGE SENT - KEY '.HASH.' TO CONTINUE'); define('MSG_SENT', GREEN.'MESSAGE SENT - KEY '.HASH.' TO CONTINUE');
define('MSG_NOTSENT', GREEN.'MESSAGE NOT SENT - KEY '.HASH.' TO CONTINUE'); define('MSG_NOTSENT', GREEN.'MESSAGE NOT SENT - KEY '.HASH.' TO CONTINUE');
define('ERR_DATABASE', RED.'UNAVAILABLE AT PRESENT - PLSE TRY LATER'); define('ERR_DATABASE', RED.'UNAVAILABLE AT PRESENT - PLS TRY LATER');
define('ERR_NOTSENT', WHITE.'MESSAGE NOT SENT DUE TO AN ERROR'); define('ERR_NOTSENT', WHITE.'MESSAGE NOT SENT DUE TO AN ERROR');
define('ERR_PRIVATE', WHITE.'PRIVATE PAGE'.GREEN.'- FOR EXPLANATION *37'.HASH.'..'); define('ERR_PRIVATE', WHITE.'PRIVATE PAGE'.GREEN.'- FOR EXPLANATION *37'.HASH.'..');
define('ERR_ROUTE', WHITE.'MISTAKE?'.GREEN.'TRY AGAIN OR TELL US ON *08'); define('ERR_ROUTE', WHITE.'MISTAKE?'.GREEN.'TRY AGAIN OR TELL US ON *08');
@ -84,11 +93,13 @@ abstract class Server {
define('MSG_TIMEWARP', WHITE.'OTHER VERSIONS EXIST'.GREEN.'KEY *02 TO VIEW'); define('MSG_TIMEWARP', WHITE.'OTHER VERSIONS EXIST'.GREEN.'KEY *02 TO VIEW');
} }
public function client() /**
{ * Write something to the system log.
return $this->co; *
} * @param string $mode
* @param string $message
* @param array $data
*/
public function log(string $mode,string $message,array $data=[]) public function log(string $mode,string $message,array $data=[])
{ {
Log::$mode(sprintf('%s: %s',$this->pid,$message),$data); Log::$mode(sprintf('%s: %s',$this->pid,$message),$data);
@ -111,7 +122,9 @@ abstract class Server {
elseif ($pid) elseif ($pid)
return; return;
$fo = NULL; // The next page we will load - this should have frame=,index=
$next_page = NULL;
$this->co = $client; $this->co = $client;
$this->pid = getmypid(); $this->pid = getmypid();
$this->log('info','Connection from: ',['client'=>$client->getAddress(),'server'=>$this->mo->name]); $this->log('info','Connection from: ',['client'=>$client->getAddress(),'server'=>$this->mo->name]);
@ -136,7 +149,6 @@ abstract class Server {
$action = ACTION_GOTO; // Initial action. $action = ACTION_GOTO; // Initial action.
$control = FALSE; // Logic in control $control = FALSE; // Logic in control
$mode = FALSE; // Current mode. $mode = FALSE; // Current mode.
$save = FALSE; //
$cmd = ''; // Current *command being typed in $cmd = ''; // Current *command being typed in
$user = new User; // The logged in user $user = new User; // The logged in user
$method = collect(); // Method in control for CONTROL_METHOD $method = collect(); // Method in control for CONTROL_METHOD
@ -147,19 +159,28 @@ abstract class Server {
$current['fieldpos'] = 0; // For current field, position within. $current['fieldpos'] = 0; // For current field, position within.
$current['prevmode'] = FALSE; // Previous mode - in case we need to go back to MODE_FIELD $current['prevmode'] = FALSE; // Previous mode - in case we need to go back to MODE_FIELD
$fielddata = [];
// @todo Get the login/start page, and if it is not available, throw the ERR_DATEBASE error. // @todo Get the login/start page, and if it is not available, throw the ERR_DATEBASE error.
if (isset($config['loginpage'])) { if (isset($config['loginpage'])) {
$page = ['frame'=>$config['loginpage']]; $next_page = ['frame'=>$config['loginpage']];
} else if (!empty($service['start_page'])) { } else if (!empty($service['start_page'])) {
$page = ['frame'=>$service['start_page']]; $next_page = ['frame'=>$service['start_page']];
} else { } else {
$page = ['frame'=>'980']; // next page $next_page = ['frame'=>'980']; // Default Login Page
} }
while ($action != ACTION_TERMINATE) { while ($action != ACTION_TERMINATE) {
// Read a character from the client session // Read a character from the client session
// @todo Add a timeout to read, and log user off if timeout exceeded.
$read = $client->read(1); $read = $client->read(1);
printf(". Got: %s (%s): Mode: [%s], Action: [%s], Control: [%s]\n",$read,ord($read),$mode,$action,$control); echo "\n";
printf(". Got: %s (%s): Mode: [%s], Action: [%s], Control: [%s]\n",
(ord($read) < 32 ? '.' : $read),
ord($read),
serialize($mode),
serialize($action),
$control);
// It appears that read will return '' instead of false when a disconnect has occurred. // It appears that read will return '' instead of false when a disconnect has occurred.
// We'll set it to NULL so its caught later // We'll set it to NULL so its caught later
@ -174,17 +195,15 @@ abstract class Server {
$control = CONTROL_TELNET; $control = CONTROL_TELNET;
// Remember our Telnet Session Object // Remember our Telnet Session Object
// @todo We might need to clear out the old mode/action states if (! $session)
if (! $session) {
$session = Control::factory('telnet',$this); $session = Control::factory('telnet',$this);
}
$method->push($session); $method->push($session);
} }
} }
if ($control AND $method->count()) { if ($control AND $method->count()) {
printf("= Control going to method: %s\n", get_class($method->last())); printf("= Start CONTROL: Going to method: %s\n",get_class($method->last()));
// Capture our state when we enter this method. // Capture our state when we enter this method.
if (! array_key_exists('control',$method->last()->state)) { if (! array_key_exists('control',$method->last()->state)) {
@ -200,7 +219,7 @@ abstract class Server {
$mode = $method->last()->state['mode']; $mode = $method->last()->state['mode'];
if ($method->last()->complete()) { if ($method->last()->complete()) {
printf("- Control complete: %s\n",get_class($method->last())); printf("- Complete CONTROL: %s\n",get_class($method->last()));
$save = $method->pop(); $save = $method->pop();
if ($method->count()) { if ($method->count()) {
@ -214,28 +233,34 @@ abstract class Server {
dump(sprintf('End: Control is now: %s: Method Count: %s',is_object($control) ? get_class($control) : serialize($control),$method->count())); dump(sprintf('End: Control is now: %s: Method Count: %s',is_object($control) ? get_class($control) : serialize($control),$method->count()));
} }
printf("- End CONTROL: Read %s (%s): Mode: [%s], Action: [%s], Control: [%s]\n",
(ord($read) < 32 ? '.' : $read),
ord($read),
serialize($mode),
serialize($action),
$control);
} }
printf("- End Control: Read %s (%s): Mode: [%s], Action: [%s], Control: [%s]\n",$read,ord($read),$mode,$action,$control); printf("= Start MODE: %s\n",serialize($mode));
switch ($mode) { switch ($mode) {
// Key presses during field input. // Key presses during field input.
case MODE_FIELD: case MODE_FIELD:
$cmd = ''; $cmd = '';
$action = FALSE; $action = FALSE;
switch ($fo->type()) { switch ($this->fo->type()) {
// Login frame. // Login frame.
case Frame::FRAMETYPE_LOGIN: case Frame::FRAMETYPE_LOGIN:
switch ($read) { switch ($read) {
case HASH: case HASH:
// If we are the main login screen, see if it is a new user // If we are the main login screen, see if it is a new user
if ($fo->isCUG(0)) if ($this->fo->isCUG(0))
{ {
if ($current['field']->type == 't' AND array_get($fielddata,$current['fieldnum']) == 'NEW') if ($current['field']->type == 't' AND array_get($fielddata,$current['fieldnum']) == 'NEW')
{ {
$action = ACTION_GOTO; $action = ACTION_GOTO;
$page = ['frame'=>'981']; // @todo This should be in the DB. $next_page = ['frame'=>'981']; // @todo This should be in the DB.
break 2; break 2;
} }
@ -254,13 +279,13 @@ abstract class Server {
$current['fieldnum']++; $current['fieldnum']++;
$current['fieldpos'] = 0; $current['fieldpos'] = 0;
if ($current['fieldnum'] < $fo->fields->count()) { if ($current['fieldnum'] < $this->fo->fields()->count()) {
$current['fieldnum'] = $fo->getFieldId('edit',$current['fieldnum']); $current['fieldnum'] = $this->fo->getFieldId('edit',$current['fieldnum']);
if ($current['fieldnum'] !== FALSE) { if ($current['fieldnum'] !== FALSE) {
$current['field'] = $fo->getField($current['fieldnum']); $current['field'] = $this->fo->getField($current['fieldnum']);
$client->send($this->outputPosition($current['field']->x,$current['field']->y).CON); $client->send($this->moveCursor($current['field']->x,$current['field']->y).CON);
$mode = MODE_FIELD; $mode = MODE_FIELD;
// There were no (more) editable fields. // There were no (more) editable fields.
@ -288,7 +313,7 @@ abstract class Server {
if ($current['fieldpos']) if ($current['fieldpos'])
{ {
$current['fieldpos']--; $current['fieldpos']--;
$client->send(LEFT.$fo::$if_filler.LEFT); $client->send(LEFT.$this->fo::$if_filler.LEFT);
$fielddata[$current['fieldnum']] = substr($fielddata[$current['fieldnum']],0,-1); $fielddata[$current['fieldnum']] = substr($fielddata[$current['fieldnum']],0,-1);
$current['fielddata'][$current['fieldnum']] = substr($current['fielddata'][$current['fieldnum']],0,-1); $current['fielddata'][$current['fieldnum']] = substr($current['fielddata'][$current['fieldnum']],0,-1);
} }
@ -332,7 +357,7 @@ abstract class Server {
$current['fieldpos'] = (($current['fieldpos'] + $current['field']->x) % 40) * 40; $current['fieldpos'] = (($current['fieldpos'] + $current['field']->x) % 40) * 40;
} else { } else {
$client->send($this->outputPosition($current['field']->x,$current['field']->y).CON); $client->send($this->moveCursor($current['field']->x,$current['field']->y).CON);
$current['fieldpos'] = 0; $current['fieldpos'] = 0;
} }
@ -354,7 +379,7 @@ abstract class Server {
$current['fieldpos']++; $current['fieldpos']++;
$client->send($fo->isFieldMasked($current['field']->type) ?: $read); $client->send($this->fo->isFieldMasked($current['field']->type) ?: $read);
} }
} }
@ -364,7 +389,7 @@ abstract class Server {
default: default:
$client->close(); $client->close();
throw new \Exception('Shouldnt get here', 500); throw new \Exception('Shouldnt get here',500);
} }
break; break;
@ -372,29 +397,32 @@ abstract class Server {
// Form submission: 1 to send, 2 not to send. // Form submission: 1 to send, 2 not to send.
case MODE_SUBMITRF: case MODE_SUBMITRF:
switch ($read) { switch ($read) {
// @todo Input received, process it.
case '1': case '1':
$route = $fo->route(1);
// If we are in a control method, complete it // If we are in a control method, complete it
if ($control AND $method->count()) { if ($control AND $method->count()) {
$method->last()->process(); $method->last()->process();
} elseif ($route == '*' OR is_numeric($route)) { } elseif ($this->fo->route(1) == '*' OR is_numeric($this->fo->route(1))) {
$this->sendBaseline($client,RED.'NO ACTION PERFORMED'); $this->sendBaseline($client,RED.'NO ACTION PERFORMED');
$mode = MODE_RFSENT; $mode = MODE_RFSENT;
} elseif ($ao = FrameClass\Action::factory($fo->route(1),$this,$user,$action,$mode)) { } elseif ($ao = FrameClass\Action::factory($this->fo->route(1),$this,$user,$action,$mode)) {
$ao->handle($fielddata); $ao->handle($fielddata);
$mode = $ao->mode; $mode = $ao->mode;
$action = $ao->action; $action = $ao->action;
$user = $ao->uo;
// Is this a user logging in?
if ($ao->uo->exists AND $ao instanceof FrameClass\Action\Login)
{
$user = $ao->uo;
$history = collect();
}
if ($ao->page) if ($ao->page)
$page = $ao->page; $next_page = $ao->page;
} else { } else {
$this->sendBaseline($client, RED.'NO method exists...'); $this->sendBaseline($client,RED.'NO method exists...');
$mode = MODE_RFSENT; $mode = MODE_RFSENT;
} }
@ -434,18 +462,18 @@ abstract class Server {
$client->send(COFF); $client->send(COFF);
if ($read == HASH) { if ($read == HASH) {
if ($route = $fo->route(2) AND $route !== '*' AND is_numeric($route)) { if ($x = $this->fo->route(2) AND $x !== '*' AND is_numeric($x)) {
$page = ['frame'=>$route]; $next_page = ['frame'=>$x];
} elseif (FrameModel::where('frame',$fo->frame())->where('index',$fo->index_next())->exists()) { } elseif (FrameModel::where('frame',$this->fo->frame())->where('index',$this->fo->index_next())->exists()) {
$page = ['frame'=>$fo->frame(),'index'=>$fo->index_next()]; $next_page = ['frame'=>$this->fo->frame(),'index'=>$this->fo->index_next()];
} elseif ($route = $fo->route(0) AND $route !== '*' AND is_numeric($route)) { } elseif ($x = $this->fo->route(0) AND $x !== '*' AND is_numeric($x)) {
$page = ['frame'=>$route]; $next_page = ['frame'=>$x];
// No further routes defined, go home. // No further routes defined, go home.
} else { } else {
$page = ['frame'=>0]; $next_page = ['frame'=>0];
} }
$action = ACTION_GOTO; $action = ACTION_GOTO;
@ -461,23 +489,23 @@ abstract class Server {
// Response form after NOT sending // Response form after NOT sending
case MODE_RFNOTSENT: case MODE_RFNOTSENT:
// Response form ERROR // Response form ERROR
case MODE_RFERROR: case MODE_RFERROR:
$client->send(COFF); $client->send(COFF);
if ($read == HASH) { if ($read == HASH) {
if ($route = $fo->route(2) AND $route !== '*' AND is_numeric($route)) { if ($x = $this->fo->route(2) AND $x !== '*' AND is_numeric($x)) {
$page = ['frame'=>$route]; $next_page = ['frame'=>$x];
} elseif (FrameModel::where('frame',$fo->frame())->where('index',$fo->index_next())->exists()) { } elseif (FrameModel::where('frame',$this->fo->frame())->where('index',$this->fo->index_next())->exists()) {
$page = ['frame'=>$fo->frame(),'index'=>$fo->index_next()]; $next_page = ['frame'=>$this->fo->frame(),'index'=>$this->fo->index_next()];
} elseif ($route = $fo->route(0) AND $route !== '*' AND is_numeric($route)) { } elseif ($x = $this->fo->route(0) AND $x !== '*' AND is_numeric($x)) {
$page = ['frame'=>$route]; $next_page = ['frame'=>$x];
// No further routes defined, go home. // No further routes defined, go home.
} else { } else {
$page = ['frame'=>0]; $next_page = ['frame'=>0];
} }
$action = ACTION_GOTO; $action = ACTION_GOTO;
@ -528,8 +556,8 @@ abstract class Server {
case '7': case '7':
case '8': case '8':
case '9': case '9':
if (is_numeric($fo->route($read))) { if (is_numeric($this->fo->route($read))) {
$page = ['frame'=>$fo->route($read),'index'=>'a']; $next_page = ['frame'=>$this->fo->route($read)];
$action = ACTION_GOTO; $action = ACTION_GOTO;
@ -548,10 +576,18 @@ abstract class Server {
echo "- Waiting for Page Number\n"; echo "- Waiting for Page Number\n";
// if it's a number, continue entry // if it's a number, continue entry
if (strpos('0123456789', $read) !== FALSE) { if (strpos('0123456789',$read) !== FALSE) {
$cmd .= $read;
$client->send($read); $client->send($read);
$this->blp++; $this->blp++;
$cmd .= $read;
}
// If its a backspace, delete last input
if ($read === KEY_DELETE AND strlen($cmd))
{
$client->send(BS.' '.BS);
$this->blp--;
$cmd = substr($cmd,0,-1);
} }
// if we hit a special numeric command, deal with it. // if we hit a special numeric command, deal with it.
@ -569,7 +605,7 @@ abstract class Server {
if ($cmd === '01') { if ($cmd === '01') {
$client->send(COFF); $client->send(COFF);
$timewarp = !$timewarp; $timewarp = !$timewarp;
$this->sendBaseline($client, ($timewarp ? MSG_TIMEWARP_ON : MSG_TIMEWARP_OFF)); $this->sendBaseline($client,($timewarp ? MSG_TIMEWARP_ON : MSG_TIMEWARP_OFF));
$cmd = ''; $cmd = '';
$action = $mode = FALSE; $action = $mode = FALSE;
@ -586,9 +622,22 @@ abstract class Server {
break; break;
} }
// Edit frame
// Catch if we are going to edit a child frame
if (preg_match('/^04/',$cmd) AND preg_match('/^[a-z]$/',$read))
{
$client->send(COFF);
$next_page = ['frame'=>substr($cmd,2),'index'=>$read];
$cmd = '';
$action = ACTION_EDIT;
break;
}
// Bookmark page // Bookmark page
if ($cmd === '05') { if ($cmd === '05') {
$this->sendBaseline($client, RED.'NOT IMPLEMENTED YET?'); $this->sendBaseline($client,RED.'NOT IMPLEMENTED YET?');
$mode = FALSE; $mode = FALSE;
break; break;
@ -596,7 +645,7 @@ abstract class Server {
// Report a problem // Report a problem
if ($cmd === '08') { if ($cmd === '08') {
$this->sendBaseline($client, RED.'NOT IMPLEMENTED YET?'); $this->sendBaseline($client,RED.'NOT IMPLEMENTED YET?');
$mode = FALSE; $mode = FALSE;
break; break;
@ -607,6 +656,7 @@ abstract class Server {
$client->send(COFF); $client->send(COFF);
$action = ACTION_GOTO; $action = ACTION_GOTO;
$cmd = ''; $cmd = '';
$next_page = $this->fo->page(TRUE);
break; break;
} }
@ -622,8 +672,8 @@ abstract class Server {
$current['prevmode'] = FALSE; $current['prevmode'] = FALSE;
// @todo The cursor color could be wrong // @todo The cursor color could be wrong
$client->send($this->outputPosition($current['field']->x,$current['field']->y).CON); $client->send($this->moveCursor($current['field']->x,$current['field']->y).CON);
$client->send(str_repeat($fo::$if_filler, $current['field']->length)); $client->send(str_repeat($this->fo::$if_filler,$current['field']->length));
$current['fieldreset'] = TRUE; $current['fieldreset'] = TRUE;
} else { } else {
@ -638,18 +688,36 @@ abstract class Server {
$client->send(COFF); $client->send(COFF);
$timewarpalt = FALSE; $timewarpalt = FALSE;
// If input is in a control, terminate it
if ($control)
{
$method->pop();
$control = FALSE;
// Our method count should be zero
if ($method->count())
dd($method);
}
// Nothing typed between * and # // Nothing typed between * and #
// *# means go back // *# means go back
if ($cmd === '') { if ($cmd === '') {
$action = ACTION_BACKUP; $action = ACTION_BACKUP;
} elseif ($cmd === '0') { } elseif ($cmd === '0') {
$page = $user->exists ? ['frame'=>1,'index'=>'a'] : ['frame'=>980,'index'=>'a']; // @todo Get from DB. $next_page = ['frame'=>$user->exists ? 1 : 980]; // @todo Get from DB.
$action = ACTION_GOTO; $action = ACTION_GOTO;
// Edit Frame
} elseif (preg_match('/^04/',$cmd)) {
$client->send(COFF);
$action = ACTION_EDIT;
$next_page = [
'frame' => substr($cmd,2) ?: $this->fo->frame(),
];
} else { } else {
$page['frame'] = $cmd; $next_page = ['frame'=>$cmd];
$page['index'] = 'a';
$action = ACTION_GOTO; $action = ACTION_GOTO;
} }
@ -661,17 +729,24 @@ abstract class Server {
break; break;
// Control is taking input
case MODE_CONTROL:
break;
default: default:
$this->log('debug','Not sure what we were doing?'); $this->log('debug','Not sure what we were doing?');
} }
}
printf("- End Mode: Read %s (%s): Mode: [%s], Action: [%s], Control: [%s]\n",$read,ord($read),$mode,$action,$control); printf("- End MODE: Read %s (%s): Mode: [%s], Action: [%s], Control: [%s]\n",
(ord($read) < 32 ? '.' : $read),
ord($read),
serialize($mode),
serialize($action),
$control);
}
// This section performs some action if it is deemed necessary // This section performs some action if it is deemed necessary
if ($action) { printf("= Start ACTION: %s\n",serialize($action));
printf("+ Performing action: %s\n",$action);
}
switch ($action) { switch ($action) {
case ACTION_STAR: case ACTION_STAR:
@ -679,7 +754,10 @@ abstract class Server {
// If there is something on the baseline, lets preserve it // If there is something on the baseline, lets preserve it
if ($this->blp) if ($this->blp)
{
printf(". Preserving Baseline: %s\n",$this->baseline);
$current['baseline'] = $this->baseline; $current['baseline'] = $this->baseline;
}
$this->sendBaseline($client,GREEN.STAR,TRUE); $this->sendBaseline($client,GREEN.STAR,TRUE);
$client->send(CON); $client->send(CON);
@ -696,6 +774,30 @@ abstract class Server {
break; break;
// Edit Frame
case ACTION_EDIT:
$this->log('debug','Editing frame:',[$next_page]);
$next_fo = NULL;
// If we are editing a different frame, load it
try {
$next_fo = $this->mo->framePage($next_page['frame'],array_get($next_page,'index','a'),$this);
} catch (ModelNotFoundException $e) {
$next_fo = $this->mo->frameNew($this,$next_page['frame'],$next_page['index']);
}
$control = CONTROL_EDIT;
$method->push(Control::factory('editframe',$this,$next_fo));
$next_fo = NULL;
$method->last()->state['control'] = $control;
$method->last()->state['action'] = FALSE;
$method->last()->state['mode'] = MODE_FIELD;
$mode = MODE_CONTROL;
$action = FALSE;
break;
// GO Backwards // GO Backwards
case ACTION_BACKUP: case ACTION_BACKUP:
// Do we have anywhere to go, drop the current page from the history. // Do we have anywhere to go, drop the current page from the history.
@ -716,116 +818,126 @@ abstract class Server {
} }
} }
$page = $history->last(); $next_page = $history->last();
$this->log('debug','Backing up to:',$page); // If there is no next page, we'll refresh the current page.
if ($next_page)
$this->log('debug','Backing up to:',$next_page);
// Go to next index frame. // Go to next index frame.
case ACTION_NEXT: case ACTION_NEXT:
// We need this extra test in case we come from ACTION_BACKUP // We need this extra test in case we come from ACTION_BACKUP
if ($action == ACTION_NEXT) if ($action == ACTION_NEXT)
{ {
$current['page']['index'] = $fo->index(); $current['page']['index'] = $this->fo->index();
$page['index'] = $fo->index_next(); $next_page = ['frame'=>$this->fo->frame(),'index'=>$this->fo->index_next()];
} }
// Look for requested page // Look for requested page - charge for it to be loaded.
case ACTION_GOTO: case ACTION_GOTO:
$current['frame'] = $fo; if ($next_page OR $timewarpalt)
// If we wanted a "Searching..." message, this is where to put it.
try {
$fo = $timewarpalt
? $this->mo->frame(FrameModel::findOrFail($timewarpalt))
: $this->mo->frameLoad($page['frame'],array_get($page,'index','a'),$this);
$this->log('debug',sprintf('Fetched frame: %s (%s)',$fo->id(),$fo->page()));
} catch (ModelNotFoundException $e) {
$this->sendBaseline($client,ERR_PAGE);
$mode = $action = FALSE;
$fo = $current['frame'] ?: $this->mo->frame($this->testFrame());
break;
}
// Is there a user logged in
if ($user)
{ {
if ($fo->isFramePublic() AND $fo->isAccessible()) // If we wanted a "Searching..." message, this is where to put it.
{ try {
if ($fo->type() == Frame::FRAMETYPE_LOGIN AND $user->isMemberCUG($fo->getCUG())) // Store our next frame in a temporary var while we determine if it can be displayed
{ $fo = $timewarpalt
$this->sendBaseline($client,ERR_USER_ALREADYMEMBER); ? $this->mo->frameID($timewarpalt)
$fo = $current['frame']; : $this->mo->framePage($next_page['frame'],array_get($next_page,'index','a'),$this);
$page = $history->last();
$mode = $action = FALSE;
$this->log('debug',sprintf('Frame Denied - Already Member: %s (%s)',$fo->id(),$fo->page()));
break; $this->log('debug',sprintf('Fetched frame: %s (%s)',$fo->id(),$fo->page()));
}
// If this is a login frame and the user is already a member. } catch (ModelNotFoundException $e) {
} else { // @todo Make sure parent frame exists, or display error
if (! $fo->isOwner($user))
{
if (! $fo->isAccessible())
{
$this->sendBaseline($client,ERR_PAGE);
$fo = $current['frame'];
$page = $history->last();
$mode = $action = FALSE;
$this->log('debug',sprintf('Frame Denied - In Accessible: %s (%s)',$fo->id(),$fo->page()));
break;
}
if (! $user->isMemberCUG($fo->getCUG()))
{
$this->sendBaseline($client, ERR_PRIVATE);
$fo = $current['frame'];
$page = $history->last();
$mode = $action = FALSE;
$this->log('debug',sprintf('Frame Denied - Not in CUG [%s]: %s (%s)',$fo->getCUG()->id,$fo->id(),$fo->page()));
break;
}
}
}
} else {
// Is this a public frame in CUG 0?
if (! $fo->isCUG(0) OR ! $fo->isFramePublic())
{
$this->sendBaseline($client,ERR_PAGE); $this->sendBaseline($client,ERR_PAGE);
$mode = $action = FALSE; $mode = $action = FALSE;
if (! $fo)
$fo = $this->mo->frameTest($this);
break; break;
} }
// Is there a user logged in
if ($user)
{
if ($fo->isFramePublic() AND $fo->isAccessible())
{
if ($fo->type() == Frame::FRAMETYPE_LOGIN AND $user->isMemberCUG($fo->getCUG()))
{
$this->sendBaseline($client,ERR_USER_ALREADYMEMBER);
$next_page = $history->last();
$mode = $action = FALSE;
$this->log('debug',sprintf('Frame Denied - Already Member: %s (%s)',$fo->id(),$fo->page()));
break;
}
// If this is a login frame and the user is already a member.
} else {
if (! $fo->isOwner($user))
{
if (! $fo->isAccessible())
{
$this->sendBaseline($client,ERR_PAGE);
$next_page = $history->last();
$mode = $action = FALSE;
$this->log('debug',sprintf('Frame Denied - In Accessible: %s (%s)',$fo->id(),$fo->page()));
break;
}
if (! $user->isMemberCUG($fo->getCUG()))
{
$this->sendBaseline($client,ERR_PRIVATE);
$next_page = $history->last();
$mode = $action = FALSE;
$this->log('debug',sprintf('Frame Denied - Not in CUG [%s]: %s (%s)',$fo->getCUG()->id,$fo->id(),$fo->page()));
break;
}
}
}
} else {
// Is this a public frame in CUG 0?
if (! $fo->isCUG(0) OR ! $fo->isFramePublic())
{
$this->sendBaseline($client,ERR_PAGE);
$next_page = $history->last();
$mode = $action = FALSE;
break;
}
}
} }
$current['page'] = $fo->page(TRUE);
$current['fieldpos'] = 0;
// Only if new location, not going backwards // Only if new location, not going backwards
if (($history->last() != $page) AND ($action == ACTION_GOTO || $action == ACTION_NEXT)) { if (($history->last() != $next_page) AND ($action == ACTION_GOTO || $action == ACTION_NEXT)) {
$history->push($page); $history->push($next_page);
} }
$current['fieldpos'] = 0;
$this->fo = $fo;
$fo = NULL;
$next_page = NULL;
$timewarpalt = NULL;
printf("+ Mode is: %s\n",$mode); printf("+ Mode is: %s\n",$mode);
// drop into // drop into
case ACTION_RELOAD: case ACTION_RELOAD:
// Clear the baseline history
$this->sendBaseline($client,''); $this->sendBaseline($client,'');
$output = (string)$fo; $current['baseline'] = '';
$output = (string)$this->fo;
if ($timewarpalt) { if ($timewarpalt) {
$this->sendBaseline($client,sprintf(MSG_TIMEWARP_TO,$fo->created() ? $fo->created()->format('Y-m-d H:i:s') : 'UNKNOWN')); $this->sendBaseline($client,sprintf(MSG_TIMEWARP_TO,$this->fo->created() ? $this->fo->created()->format('Y-m-d H:i:s') : 'UNKNOWN'));
} }
switch ($fo->type()) { switch ($this->fo->type()) {
default: default:
// Standard Frame // Standard Frame
case Frame::FRAMETYPE_INFO: case Frame::FRAMETYPE_INFO:
@ -842,7 +954,7 @@ abstract class Server {
// If this is the registration page // If this is the registration page
// @todo Should be evaluated out of the DB // @todo Should be evaluated out of the DB
if ($fo->page() == '981a') { if ($this->fo->page() == '981a') {
$control = CONTROL_METHOD; $control = CONTROL_METHOD;
$method->push(Control::factory('register',$this)); $method->push(Control::factory('register',$this));
$method->last()->state['control'] = $control; $method->last()->state['control'] = $control;
@ -857,10 +969,10 @@ abstract class Server {
$fielddata = []; $fielddata = [];
$current['fielddata'] = []; $current['fielddata'] = [];
if (count($fo->fields)) { if ($this->fo->fields()->count()) {
// Get our first editable field. // Get our first editable field.
$current['fieldnum'] = $fo->getFieldId('edit',0); $current['fieldnum'] = $this->fo->getFieldId('edit',0);
$current['field'] = $fo->getField($current['fieldnum']); $current['field'] = $this->fo->getField($current['fieldnum']);
$current['fieldreset'] = TRUE; $current['fieldreset'] = TRUE;
if ($current['fieldnum'] !== FALSE) { if ($current['fieldnum'] !== FALSE) {
@ -896,17 +1008,17 @@ abstract class Server {
$cmd = ''; $cmd = '';
$y = 0; $y = 0;
$output = $this->outputPosition(0, $y++) . WHITE . NEWBG . RED . 'TIMEWARP INFO FOR Pg.' . BLUE . $fo->page(). WHITE; $output = $this->moveCursor(0,$y++).WHITE.NEWBG.RED.'TIMEWARP INFO FOR Pg.'.BLUE.$this->fo->page().WHITE;
//$output .= $this->outputPosition(0, $y++) . WHITE . NEWBG . BLUE . 'Service : ' . substr($service['service_name'] . str_repeat(' ', 27), 0, 27); //$output .= $this->moveCursor(0,$y++).WHITE.NEWBG.BLUE.'Service : '.substr($service['service_name'].str_repeat(' ',27),0,27);
//$output .= $this->outputPosition(0, $y++) . WHITE . NEWBG . BLUE . 'Varient : ' . substr($varient['varient_name'] . str_repeat(' ', 27), 0, 27); //$output .= $this->moveCursor(0,$y++).WHITE.NEWBG.BLUE.'Varient : '.substr($varient['varient_name'].str_repeat(' ',27),0,27);
$output .= $this->outputPosition(0, $y++) . WHITE . NEWBG . BLUE . 'Dated : ' .substr(($fo->created() ? $fo->created()->format('j F Y') : 'Unknown').str_repeat(' ', 27), 0, 27); $output .= $this->moveCursor(0,$y++).WHITE.NEWBG.BLUE.'Dated : ' .substr(($this->fo->created() ? $this->fo->created()->format('j F Y') : 'Unknown').str_repeat(' ',27),0,27);
$alts = $fo->alts($this->mo)->get(); $alts = $this->fo->alts($this->mo)->get();
if (count($alts)) { if (count($alts)) {
$n = 1; $n = 1;
$output .= $this->outputPosition(0, $y++) . WHITE . NEWBG . RED . 'ALTERNATIVE VERSIONS:' . str_repeat(' ', 16); $output .= $this->moveCursor(0,$y++).WHITE.NEWBG.RED.'ALTERNATIVE VERSIONS:'.str_repeat(' ',16);
foreach ($alts as $o) { foreach ($alts as $o) {
$date = $o->created_at->format('d M Y'); $date = $o->created_at->format('d M Y');
@ -919,7 +1031,7 @@ abstract class Server {
$line .= BLUE.$date.' '.$o->note; $line .= BLUE.$date.' '.$o->note;
$output .= $this->outputPosition(0,$y++).$line.str_repeat(' ',40-$this->strlenv($line)); // @todo should use frame::page_length $output .= $this->moveCursor(0,$y++).$line.str_repeat(' ',40-$this->fo->strlenv($line)); // @todo should use frame::page_length
} }
if ($timewarp) { if ($timewarp) {
@ -933,11 +1045,16 @@ abstract class Server {
break; break;
} }
printf("- End Action: Read %s (%s): Mode: [%s], Action: [%s], Control: [%s]\n",$read,ord($read),$mode,$action,$control); printf("- End ACTION: Read %s (%s): Mode: [%s], Action: [%s], Control: [%s]\n",
(ord($read) < 32 ? '.' : $read),
ord($read),
serialize($mode),
serialize($action),
$control);
// We need to reposition the cursor to the current field. // We need to reposition the cursor to the current field.
if ($current['fieldreset'] !== FALSE) { if ($current['fieldreset'] !== FALSE) {
$client->send($this->outputPosition($current['field']->x,$current['field']->y).CON); $client->send($this->moveCursor($current['field']->x,$current['field']->y).CON);
$current['fieldreset'] = FALSE; $current['fieldreset'] = FALSE;
} }
@ -962,7 +1079,7 @@ abstract class Server {
/** /**
* Move the cursor via the shortest path. * Move the cursor via the shortest path.
*/ */
abstract function outputPosition($x,$y); abstract function moveCursor($x,$y);
/** /**
* Send a message to the base line * Send a message to the base line
@ -973,20 +1090,4 @@ abstract class Server {
* @param bool $reposition * @param bool $reposition
*/ */
abstract function sendBaseline($client,$text,$reposition=FALSE); abstract function sendBaseline($client,$text,$reposition=FALSE);
/**
* Calculate the length of text
*
* ESC characters are two chars, and need to be counted as one.
*
* @param $text
* @return int
*/
abstract function strlenv($text):int;
/**
* Return a test frame appropriate for this server.
* @return mixed
*/
abstract public function testFrame();
} }

View File

@ -2,8 +2,6 @@
namespace App\Classes\Server; namespace App\Classes\Server;
use Illuminate\Support\Facades\Log;
use App\Classes\Server as AbstractServer; use App\Classes\Server as AbstractServer;
use App\Models\Mode; use App\Models\Mode;
@ -22,6 +20,7 @@ class Ansi extends AbstractServer {
define('UP', ESC.'[A'); // Move Cursor define('UP', ESC.'[A'); // Move Cursor
define('CR', chr(13)); define('CR', chr(13));
define('LF', chr(10)); define('LF', chr(10));
define('BS', chr(8));
define('CLS', ESC.'[2J'); define('CLS', ESC.'[2J');
define('HASH', '#'); // Enter define('HASH', '#'); // Enter
define('STAR', '*'); // Star Entry define('STAR', '*'); // Star Entry
@ -47,34 +46,32 @@ class Ansi extends AbstractServer {
define('R_WHITE', WHITE); define('R_WHITE', WHITE);
//define('FLASH',chr(8)); //define('FLASH',chr(8));
// Keyboard presses
// @todo Check where these are used vs the keys defined above?
define('KEY_DELETE', chr(8));
define('KEY_LEFT', chr(136));
define('KEY_RIGHT', chr(137));
define('KEY_DOWN', chr(138));
define('KEY_UP', chr(139));
parent::__construct($o); parent::__construct($o);
} }
function outputPosition($x,$y) { function moveCursor($x,$y) {
printf(". Move cursor %s,%s\n",$x,$y);
return ESC.'['.$y.';'.$x.'f'; return ESC.'['.$y.';'.$x.'f';
} }
// Abstract function // Abstract function
public function sendBaseline($client,$text,$reposition=FALSE) { public function sendBaseline($client,$text,$reposition=FALSE) {
$client->send(CSAVE.ESC.'[24;0f'.$text. $client->send(CSAVE.ESC.'[24;0f'.$text.
($this->blp > $this->strlenv($text) ($this->blp > $this->fo->strlenv($text)
? str_repeat(' ',$this->blp-$this->strlenv($text)). ? str_repeat(' ',$this->blp-$this->fo->strlenv($text)).
($reposition ? ESC.'[24;0f'.str_repeat(RIGHT,$this->strlenv($text)) : CRESTORE) ($reposition ? ESC.'[24;0f'.str_repeat(RIGHT,$this->fo->strlenv($text)) : CRESTORE)
: ($reposition ? '' : CRESTORE)) : ($reposition ? '' : CRESTORE))
); );
$this->blp = $this->strlenv($text); $this->blp = $this->fo->strlenv($text);
$this->baseline = $text; $this->baseline = $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

@ -48,7 +48,7 @@ class Videotex extends AbstractServer {
parent::__construct($o); parent::__construct($o);
} }
public function outputPosition($x,$y) { public function moveCursor($x,$y) {
// Take the shortest path. // Take the shortest path.
if ($y < 12) { if ($y < 12) {
return HOME. return HOME.
@ -74,15 +74,4 @@ class Videotex extends AbstractServer {
$this->blp = $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

@ -20,6 +20,11 @@ class Mode extends Model
return $this->hasMany(Frame::class); return $this->hasMany(Frame::class);
} }
public function frameId(int $id)
{
return $this->frameLoad(Frame::findOrFail($id));
}
/** /**
* Return a frame class for the Model * Return a frame class for the Model
* *
@ -27,7 +32,7 @@ class Mode extends Model
* @return FrameClass * @return FrameClass
* @throws \Exception * @throws \Exception
*/ */
public function frame(Model $o): FrameClass private function frameLoad(Model $o): FrameClass
{ {
switch (strtolower($this->name)) { switch (strtolower($this->name)) {
case 'ansi': case 'ansi':
@ -35,10 +40,28 @@ class Mode extends Model
case 'videotex': case 'videotex':
return new VideotexFrame($o); return new VideotexFrame($o);
default: default:
throw new \Exception('Unknown Frame type: '.$mo->name); throw new \Exception('Unknown Frame type: '.$this->name);
} }
} }
public function frameNew(Server $so,int $frame,string $index='a'): FrameClass
{
$o = new Frame;
$o->frame = $frame;
$o->index = $index;
$o->mode_id = $this->id;
// Make sure parent frame exists
// @todo make sure not trying to edit test frames
if ($o->index != 'a' AND ! FrameModel::where('frame',$fo->frame())->where('index',$fo->index_prev())->exists())
{
$so->sendBaseline($so->co,ERR_ROUTE);
return new Frame;
}
return $this->frameLoad($o);
}
/** /**
* Fetch a specific frame from the DB * Fetch a specific frame from the DB
* *
@ -48,17 +71,28 @@ class Mode extends Model
* @return FrameClass * @return FrameClass
* @throws \Exception * @throws \Exception
*/ */
public function frameLoad(int $frame,string $index,Server $so): FrameClass public function framePage(int $frame,string $index='a',Server $so): FrameClass
{ {
return $this->frame( return ($frame == '999' and $index == 'a')
// Return our internal test frame. // Return our internal test frame.
($frame == '999' and $index == 'a') ? $this->frameTest($so)
? $so->testFrame() : $this->frameLoad($this->frames()
: $this->frames() ->where('frame','=',$frame)
->where('frame','=',$frame) ->where('index','=',$index)
->where('index','=',$index) ->firstOrFail()
->firstOrFail() );
); }
public function frameTest(Server $so): FrameClass
{
switch (strtolower($this->name)) {
case 'ansi':
return AnsiFrame::testFrame($so);
case 'videotex':
return VideotexFrame::testFrame($so);
default:
throw new \Exception('Unknown Frame type: '.$this->name);
}
} }
/** /**

View File

@ -98,7 +98,7 @@ return [
// otherwise you can them out of the configuration array // otherwise you can them out of the configuration array
#'sslcert' => env('DB_SSLCERT', 'client.crt'), #'sslcert' => env('DB_SSLCERT', 'client.crt'),
#'sslkey' => env('DB_SSLKEY', 'client.key'), #'sslkey' => env('DB_SSLKEY', 'client.key'),
#'sslrootcert' => env('DB_SSLROOTCERT', 'ca.crt'), 'sslrootcert' => env('DB_SSLROOTCERT', 'ca.crt'),
], ],
], ],