From aa6b2f324458f6abd0ffdfc64411e3228ee8bf0d Mon Sep 17 00:00:00 2001 From: Deon George Date: Sun, 14 Jul 2019 22:43:31 +1000 Subject: [PATCH] Moved registration processing into Frame/Action --- app/Classes/Control.php | 10 ++ app/Classes/Control/Register.php | 62 +++------ app/Classes/Frame.php | 166 +++++++++++++++++++--- app/Classes/Frame/Action.php | 2 +- app/Classes/Frame/Action/Login.php | 8 +- app/Classes/Frame/Action/Register.php | 47 +++++++ app/Classes/Parser.php | 14 +- app/Classes/Server.php | 192 +++++++++----------------- app/Classes/Server/Ansi.php | 32 ++--- 9 files changed, 316 insertions(+), 217 deletions(-) create mode 100644 app/Classes/Frame/Action/Register.php diff --git a/app/Classes/Control.php b/app/Classes/Control.php index 8bb3ed1..710eccb 100644 --- a/app/Classes/Control.php +++ b/app/Classes/Control.php @@ -66,4 +66,14 @@ abstract class Control } abstract public function handle(string $read); + + /** + * If completing an Action frame, this will be called to submit the data. + * + * Ideally this should be overridden in a child class. + */ + public function process() + { + $this->complete = TRUE; + } } \ No newline at end of file diff --git a/app/Classes/Control/Register.php b/app/Classes/Control/Register.php index 6ceb09c..9b38283 100644 --- a/app/Classes/Control/Register.php +++ b/app/Classes/Control/Register.php @@ -2,11 +2,12 @@ namespace App\Classes\Control; +use Illuminate\Support\Facades\Mail; +use Illuminate\Support\Facades\Validator; + use App\Classes\Control; use App\Mail\SendToken; use App\User; -use Illuminate\Support\Facades\Mail; -use Illuminate\Support\Facades\Validator; /** * Class Register handles registration @@ -36,35 +37,38 @@ class Register extends Control */ public function handle(string $read,array $current=[]) { + // Ignore LF (as a result of pressing ENTER) + if ($read == LF) + return ''; + // If we got a # we'll be completing field input. - if ($read == HASH OR $read == LF) { + if ($read == HASH OR $read == CR) { // Does our field have data... - if (array_get($current['fielddata'],$current['fieldnum'])) { - switch ($current['fieldnum']) { + if ($x=$this->so->fo->getFieldCurrentInput()) { + switch ($this->so->fo->getFieldId()) { // Username case 0: // See if the requested username already exists - if (User::where('login', $current['fielddata'][$current['fieldnum']])->exists()) { + if (User::where('login',$x)->exists()) { $this->so->sendBaseline($this->so->co,RED.'USER ALREADY EXISTS'.WHITE); return ''; } - $this->data['user'] = $current['fielddata'][$current['fieldnum']]; $this->so->sendBaseline($this->so->co,GREEN.'Enter Real Name'.WHITE); break; // Real Name case 1: - $this->data['name'] = $current['fielddata'][$current['fieldnum']]; + //$this->data['name'] = $x; $this->so->sendBaseline($this->so->co,GREEN.'Enter Email Address'.WHITE); break; // Email Address case 2: - if (Validator::make(['email'=>$current['fielddata'][$current['fieldnum']]],[ + if (Validator::make(['email'=>$x],[ 'email'=>'email', ])->fails()) { $this->so->sendBaseline($this->so->co,RED.'INVALID EMAIL ADDRESS'.WHITE); @@ -73,13 +77,13 @@ class Register extends Control }; // See if the requested email already exists - if (User::where('email', $current['fielddata'][$current['fieldnum']])->exists()) { + if (User::where('email',$x)->exists()) { $this->so->sendBaseline($this->so->co,RED.'USER ALREADY EXISTS'.WHITE); return ''; } - $this->data['email'] = $current['fielddata'][$current['fieldnum']]; + $this->data['email'] = $x; $this->data['token'] = sprintf('%06.0f',rand(0,999999)); $this->so->sendBaseline($this->so->co,YELLOW.'PROCESSING...'.WHITE); @@ -97,14 +101,14 @@ class Register extends Control // Enter Password case 3: - $this->data['password'] = $current['fielddata'][$current['fieldnum']]; + $this->data['password'] = $x; $this->so->sendBaseline($this->so->co,GREEN.'Confirm Password'.WHITE); break; // Confirm Password case 4: - if ($this->data['password'] !== $current['fielddata'][$current['fieldnum']]) { + if ($this->data['password'] !== $x) { $this->so->sendBaseline($this->so->co,RED.'PASSWORD DOESNT MATCH, *09 TO START AGAIN'.WHITE); return ''; @@ -116,19 +120,20 @@ class Register extends Control // 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; // Enter Token case 6: - if ($this->data['token'] !== $current['fielddata'][$current['fieldnum']]) { + if ($this->data['token'] !== $x) { $this->so->sendBaseline($this->so->co,RED.'TOKEN DOESNT MATCH, *09 TO START AGAIN'.WHITE); return ''; } + $this->complete = TRUE; + break; default: @@ -150,31 +155,4 @@ class Register extends Control return $read; } - - public function process() - { - $o = new User; - - try { - $o->login = $this->data['user']; - $o->email = $this->data['email']; - $o->password = $this->data['password']; - $o->name = $this->data['name']; - $o->location = $this->data['location']; - - $o->save(); - $this->so->sendBaseline($this->so->co,GREEN.'ACCOUNT CREATED, PRESS '.HASH.' TO CONTINUE...'.WHITE); - $this->state['action'] = ACTION_NEXT; - - // Add to CUG 0 - $o->cugs()->attach(0); - - } catch (\Exception $e) { - $this->so->sendBaseline($this->so->co,RED.'SOMETHING WENT WRONG...'.WHITE); - $this->so->log('error',$e->getMessage()); - $this->state['action'] = ACTION_RELOAD; - } - - $this->complete = TRUE; - } } \ No newline at end of file diff --git a/app/Classes/Frame.php b/app/Classes/Frame.php index 6d6acae..341c190 100644 --- a/app/Classes/Frame.php +++ b/app/Classes/Frame.php @@ -2,8 +2,7 @@ namespace App\Classes; -use Illuminate\Support\Collection; -use Illuminate\Support\Facades\Log; +use Illuminate\Support\Arr; use App\User; use App\Models\{CUG,Mode}; @@ -41,6 +40,12 @@ abstract class Frame // This holds the frame object as retrieved from the DB protected $fo = NULL; + // Current field being edited + private $field_active = FALSE; + + // Current input data for fields + private $field_data = []; + /* // All this vars should be overridden in the child class protected $frame_length = 22; @@ -65,7 +70,7 @@ abstract class Frame ]; // @todo Move this to the database - private $header = RED.'T'.BLUE.'E'.GREEN.'S'.YELLOW.'T'.MAGENTA.'!'; + private $header = RED.SPACE.'T'.BLUE.SPACE.'E'.GREEN.SPACE.'S'.YELLOW.SPACE.'T'.MAGENTA.SPACE.'!'; public function __construct(FrameModel $o) { @@ -83,6 +88,9 @@ abstract class Frame // Our parser object $this->po = $this->parser($startline); + + // Set our first editable field + $this->resetCurrentField(); } /** @@ -186,10 +194,44 @@ abstract class Frame /** * Return the current field configuration + * Will return false if no id specified and the current field is not active */ - public function getField(int $id) + public function getField(int $id=NULL) { - return $this->fields()->get($id); + if (is_null($id) AND $this->field_active === FALSE) + return FALSE; + + return $this->fields()->get(is_null($id) ? $this->field_active : $id); + } + + /** + * Get the input for the current field + * + * @return mixed + */ + public function getFieldCurrentInput() + { + return Arr::get($this->field_data,$this->field_active); + } + + public function getFieldData() + { + return $this->field_data; + } + + public function getFieldDataId(int $id) + { + return Arr::get($this->field_data,$id); + } + + /** + * Return the current field ID + * + * @return bool + */ + public function getFieldId() + { + return $this->field_active; } /** @@ -199,7 +241,7 @@ abstract class Frame * @param int $after * @return mixed */ - public function getFieldId($type='edit',$after=0) + public function getFieldNextId($type='edit',$after=0) { return $this->fields() ->search(function($item,$key) use ($type,$after) { @@ -207,9 +249,16 @@ abstract class Frame }); } - public function getFieldOptions(int $id) + public function getFieldPrevId($type='edit',$before=FALSE) { - return array_get($this->fieldoptions,$this->getField($id)->type); + if (! $before) + $before = $this->fields()->count(); + + return $this->fields() + ->reverse() + ->search(function($item,$key) use ($type,$before) { + return $key < $before AND $this->isFieldEditable($item->type); + }); } /** @@ -278,19 +327,28 @@ abstract class Frame } /** - * Determine if a field is editable + * Determine if the current field should be masked during input * * @param string $field * @return mixed */ - public function isFieldEditable(string $field) + public function isFieldCurrentMask(int $id=NULL): string { - return array_get(array_get($this->fieldoptions,$field),'edit',FALSE); + if (! $x=$this->getField($id)) + return FALSE; + + return array_get(array_get($this->fieldoptions,$x->type),'mask',''); } - public function isFieldMasked(string $field) + /** + * Determine if a field is editable + * + * @param string $field + * @return boolean + */ + public function isFieldEditable(string $field): bool { - return array_get(array_get($this->fieldoptions,$field),'mask',FALSE); + return array_get(array_get($this->fieldoptions,$field),'edit',FALSE); } /** @@ -349,11 +407,11 @@ abstract class Frame throw new \Exception('Price too high'); if ($cost > 100) - $color = RED; + $color = RED.SPACE; elseif ($cost > 0) - $color = YELLOW; + $color = YELLOW.SPACE; else - $color = GREEN; + $color = GREEN.SPACE; return sprintf($color.'% '.static::$cost_length.'.0f%s',$cost,static::$cost_unit); } @@ -387,7 +445,26 @@ abstract class Frame if (strlen($frame) !== 1) throw new \Exception('Frame invalid',500); - return WHITE.$num.$frame.(str_repeat(' ',static::$pagenum_length-strlen($num))); + return WHITE.SPACE.$num.$frame.(str_repeat(' ',static::$pagenum_length-strlen($num))); + } + + /** + * Reset the current active field to the first one + */ + public function resetCurrentField() + { + $this->field_active = $this->getFieldNextId('edit',0); + + $this->resetCurrentFieldData(); + } + + /** + * Clear the current field + */ + public function resetCurrentFieldData() + { + if ($this->field_active !== FALSE AND isset($this->field_data[$this->field_active])) + unset($this->field_data[$this->field_active]); } /** @@ -410,6 +487,61 @@ abstract class Frame return $this->fo->route->{$key}; } + /** + * Set the field that is current in focus for input + * + * @param int $num + */ + public function setFieldCurrent(int $num) + { + $this->po->field_active = $num; + } + + public function setFieldCurrentInput(string $read) + { + if ($this->field_active === FALSE) + throw new \Exception('No field active?',500); + + if (! array_key_exists($this->field_active,$this->field_data)) + $this->field_data[$this->field_active] = ''; + + $this->field_data[$this->field_active] .= $read; + } + + /** + * Delete the last character of the current Input field + * + * @return bool + */ + public function setFieldCurrentInputDelete(): bool + { + if (! $this->field_data[$this->field_active]) + return FALSE; + + $this->field_data[$this->field_active] = substr($this->field_data[$this->field_active],0,-1); + return TRUE; + } + + /** + * Set the next active field + */ + public function setFieldNext() + { + $this->field_active = $this->getFieldNextId('edit',$this->field_active+1); + + $this->resetCurrentFieldData(); + } + + /** + * Set the previous active field + */ + public function setFieldPrev() + { + $this->field_active = $this->getFieldPrevId('edit',$this->field_active); + + $this->resetCurrentFieldData(); + } + /** * Calculate the length of text * diff --git a/app/Classes/Frame/Action.php b/app/Classes/Frame/Action.php index 56f34ba..3827478 100644 --- a/app/Classes/Frame/Action.php +++ b/app/Classes/Frame/Action.php @@ -34,5 +34,5 @@ abstract class Action return $o; } - abstract public function handle(array $fielddata); + abstract public function handle(); } \ No newline at end of file diff --git a/app/Classes/Frame/Action/Login.php b/app/Classes/Frame/Action/Login.php index 92a137b..def4a63 100644 --- a/app/Classes/Frame/Action/Login.php +++ b/app/Classes/Frame/Action/Login.php @@ -16,10 +16,10 @@ class Login extends Action * @param array $fielddata * @return bool */ - public function handle(array $fielddata) + public function handle() { // First field data element is user, the second is the password - if (count($fielddata) != 2 OR ! array_get($fielddata,0) OR ! array_get($fielddata,1)) + if (count($this->so->fo->getFieldData()) != 2 OR ! $this->so->fo->getFieldDataId(0) OR ! $this->so->fo->getFieldDataId(1)) { $this->mode = 2; // MODE_FIELD // $this->action = 2; // ACTION_GOTO @@ -30,7 +30,7 @@ class Login extends Action } try { - $this->uo = User::where('login',array_get($fielddata,0))->firstOrFail(); + $this->uo = User::where('login',$this->so->fo->getFieldDataId(0))->firstOrFail(); } catch (ModelNotFoundException $e) { $this->so->sendBaseline($this->so->co,RED.'USER NOT FOUND, TRY AGAIN *00'); @@ -38,7 +38,7 @@ class Login extends Action return FALSE; } - if ($this->uo->password != array_get($fielddata,1)) + if ($this->uo->password != $this->so->fo->getFieldDataId(1)) { $this->uo = new User; $this->so->sendBaseline($this->so->co,RED.'INVALID PASSWORD, TRY AGAIN *00'); diff --git a/app/Classes/Frame/Action/Register.php b/app/Classes/Frame/Action/Register.php new file mode 100644 index 0000000..aa59130 --- /dev/null +++ b/app/Classes/Frame/Action/Register.php @@ -0,0 +1,47 @@ +login = $this->so->fo->getFieldDataId(0); + $o->name = $this->so->fo->getFieldDataId(1); + $o->email = $this->so->fo->getFieldDataId(2); + $o->password = $this->so->fo->getFieldDataId(3); + $o->location = $this->so->fo->getFieldDataId(5); + + $o->save(); + $this->so->sendBaseline($this->so->co,GREEN.'ACCOUNT CREATED, PRESS '.HASH.' TO CONTINUE...'.WHITE); + $this->state['action'] = ACTION_NEXT; + + // Add to CUG 0 + $o->cugs()->attach(0); + + } catch (\Exception $e) { + $this->so->sendBaseline($this->so->co,RED.'SOMETHING WENT WRONG...'.WHITE); + $this->so->log('error',$e->getMessage()); + $this->state['action'] = ACTION_RELOAD; + } + } +} \ No newline at end of file diff --git a/app/Classes/Parser.php b/app/Classes/Parser.php index edd6191..fc39e24 100644 --- a/app/Classes/Parser.php +++ b/app/Classes/Parser.php @@ -10,8 +10,11 @@ abstract class Parser // Fields in the frame public $fields = []; - // Parsed frame, ready to send to client - public $output = ''; + // Magic Fields that are pre-filled + protected $fieldmap = [ + 'a'=>'address#', + 'd'=>'%date', + ]; // Position array of frame control chars protected $frame_data = []; @@ -19,11 +22,8 @@ abstract class Parser // Position array of frame chars protected $frame_content = []; - // Magic Fields that are pre-filled - protected $fieldmap = [ - 'a'=>'address#', - 'd'=>'%date', - ]; + // Parsed frame, ready to send to client + public $output = ''; public function __construct(string $content,int $width,int $startline=1) { diff --git a/app/Classes/Server.php b/app/Classes/Server.php index 575f75c..398066d 100644 --- a/app/Classes/Server.php +++ b/app/Classes/Server.php @@ -76,21 +76,21 @@ abstract class Server { define('TCP_OPT_LINEMODE', chr(34)); // Status messages - define('MSG_SENDORNOT', GREEN.'KEY 1 TO SEND, 2 NOT TO SEND'); - define('MSG_SENT', GREEN.'MESSAGE SENT - KEY '.HASH.' TO CONTINUE'); - define('MSG_NOTSENT', GREEN.'MESSAGE NOT SENT - KEY '.HASH.' TO CONTINUE'); + define('MSG_SENDORNOT', GREEN.SPACE.'KEY 1 TO SEND, 2 NOT TO SEND'); + define('MSG_SENT', GREEN.SPACE.'MESSAGE SENT - KEY '.HASH.' TO CONTINUE'); + define('MSG_NOTSENT', GREEN.SPACE.'MESSAGE NOT SENT - KEY '.HASH.' TO CONTINUE'); - define('ERR_DATABASE', RED.'UNAVAILABLE AT PRESENT - PLS TRY LATER'); - define('ERR_NOTSENT', WHITE.'MESSAGE NOT SENT DUE TO AN ERROR'); - 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_DATABASE', RED.SPACE.'UNAVAILABLE AT PRESENT - PLS TRY LATER'); + define('ERR_NOTSENT', RED.SPACE.'MESSAGE NOT SENT DUE TO AN ERROR'); + define('ERR_PRIVATE', WHITE.SPACE.'PRIVATE PAGE'.GREEN.SPACE.'- FOR EXPLANATION *37'.HASH.'..'); + define('ERR_ROUTE', WHITE.SPACE.'MISTAKE?'.GREEN.SPACE.'TRY AGAIN OR TELL US ON *08'); define('ERR_PAGE',ERR_ROUTE); - define('ERR_USER_ALREADYMEMBER', RED.'ALREADY MEMBER OF CUG'); + define('ERR_USER_ALREADYMEMBER', RED.SPACE.'ALREADY MEMBER OF CUG'); - define('MSG_TIMEWARP_ON', WHITE.'TIMEWARP ON'.GREEN.'VIEW INFO WITH *02'); - define('MSG_TIMEWARP_OFF', WHITE.'TIMEWARP OFF'.GREEN.'VIEWING DATE IS FIXED'); - define('MSG_TIMEWARP_TO', GREEN.'TIMEWARP TO %s'); - define('MSG_TIMEWARP', WHITE.'OTHER VERSIONS EXIST'.GREEN.'KEY *02 TO VIEW'); + define('MSG_TIMEWARP_ON', WHITE.SPACE.'TIMEWARP ON'.GREEN.SPACE.'VIEW INFO WITH *02'); + define('MSG_TIMEWARP_OFF', WHITE.SPACE.'TIMEWARP OFF'.GREEN.SPACE.'VIEWING DATE IS FIXED'); + define('MSG_TIMEWARP_TO', GREEN.SPACE.'TIMEWARP TO %s'); + define('MSG_TIMEWARP', WHITE.SPACE.'OTHER VERSIONS EXIST'.GREEN.SPACE.'KEY *02 TO VIEW'); } /** @@ -154,13 +154,8 @@ abstract class Server { $method = collect(); // Method in control for CONTROL_METHOD $current = []; // Attributes about the current page - // field/fieldnum indexes are for fields on the active page - $current['fieldreset'] = FALSE; // Flag to reset position (used in fields) - $current['fieldpos'] = 0; // For current field, position within. $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. if (isset($config['loginpage'])) { $next_page = ['frame'=>$config['loginpage']]; @@ -202,7 +197,7 @@ abstract class Server { } } - if ($control AND $method->count()) { + if ($mode != MODE_BL AND $control AND $method->count()) { printf("= Start CONTROL: Going to method: %s\n",get_class($method->last())); // Capture our state when we enter this method. @@ -257,7 +252,7 @@ abstract class Server { // If we are the main login screen, see if it is a new user if ($this->fo->isCUG(0)) { - if ($current['field']->type == 't' AND array_get($fielddata,$current['fieldnum']) == 'NEW') + if ($this->fo->getField()->type == 't' AND $this->fo->getFieldCurrentInput() == 'NEW') { $action = ACTION_GOTO; $next_page = ['frame'=>'981']; // @todo This should be in the DB. @@ -273,28 +268,17 @@ abstract class Server { case Frame::FRAMETYPE_ACTION: switch ($read) { // End of field entry. - case LF: + case CR: case HASH: // Next Field - $current['fieldnum']++; - $current['fieldpos'] = 0; + $this->fo->setFieldNext(); - if ($current['fieldnum'] < $this->fo->fields()->count()) { - $current['fieldnum'] = $this->fo->getFieldId('edit',$current['fieldnum']); - - if ($current['fieldnum'] !== FALSE) { - $current['field'] = $this->fo->getField($current['fieldnum']); - - $client->send($this->moveCursor($current['field']->x,$current['field']->y).CON); - $mode = MODE_FIELD; - - // There were no (more) editable fields. - } else { - $action = ACTION_SUBMITRF; - } + if ($x=$this->fo->getField()) { + $client->send($this->moveCursor($x->x,$x->y).CON); + $mode = MODE_FIELD; + // Finished all editable fields. } else { - // Finished all editable fields. $action = ACTION_SUBMITRF; } @@ -303,63 +287,12 @@ abstract class Server { case STAR: $current['prevmode'] = MODE_FIELD; $action = ACTION_STAR; - $current['fieldpos'] = 0; - $fielddata[$current['fieldnum']] = ''; - $current['fielddata'][$current['fieldnum']] = ''; break; case KEY_DELETE: - if ($current['fieldpos']) - { - $current['fieldpos']--; + if ($this->fo->setFieldCurrentInputDelete()) $client->send(LEFT.$this->fo::$if_filler.LEFT); - $fielddata[$current['fieldnum']] = substr($fielddata[$current['fieldnum']],0,-1); - $current['fielddata'][$current['fieldnum']] = substr($current['fielddata'][$current['fieldnum']],0,-1); - } - - break; - - case KEY_LEFT: - if ($current['fieldpos']) { - $current['fieldpos']--; - $client->send(LEFT); - } - - break; - - case KEY_RIGHT: - if ($current['fieldpos']++ < $current['field']->length) - $client->send(RIGHT); - - break; - - case KEY_DOWN: - if ($current['fieldpos'] + 40 < $current['field']->length) { - $client->send(DOWN); - $current['fieldpos'] = $current['fieldpos'] + 40; - }; - - break; - - case KEY_UP: - if ($current['fieldpos'] - 40 >= 0) { - $client->send($read); - $current['fieldpos'] = $current['fieldpos'] - 40; - }; - - break; - - case CR: - // On second or later line of a field - if ($current['fieldpos'] + $current['field']->x > 40) { - $client->send($read); - $current['fieldpos'] = (($current['fieldpos'] + $current['field']->x) % 40) * 40; - - } else { - $client->send($this->moveCursor($current['field']->x,$current['field']->y).CON); - $current['fieldpos'] = 0; - } break; @@ -368,18 +301,10 @@ abstract class Server { // Record Data Entry default: - if (ord($read) > 31 && $current['fieldpos'] < $current['field']->length) { - if (! array_key_exists($current['fieldnum'],$current['fielddata'])) { - $current['fielddata'][$current['fieldnum']] = ''; - $fielddata[$current['fieldnum']] = ''; - } + if (ord($read) > 31 && strlen($this->fo->getFieldCurrentInput()) < $this->fo->getField()->length) { + $this->fo->setFieldCurrentInput($read); - $fielddata[$current['fieldnum']]{$current['fieldpos']} = $read; // @todo delete - $current['fielddata'][$current['fieldnum']]{$current['fieldpos']} = $read; - - $current['fieldpos']++; - - $client->send($this->fo->isFieldMasked($current['field']->type) ?: $read); + $client->send($this->fo->isFieldCurrentMask() ?: $read); } } @@ -407,7 +332,7 @@ abstract class Server { $mode = MODE_RFSENT; } elseif ($ao = FrameClass\Action::factory($this->fo->route(1),$this,$user,$action,$mode)) { - $ao->handle($fielddata); + $ao->handle(); $mode = $ao->mode; $action = $ao->action; @@ -430,6 +355,7 @@ abstract class Server { break; case '2': + // @todo Check if HASH is a valid next destination $this->sendBaseline($client,MSG_NOTSENT); $mode = MODE_RFNOTSENT; @@ -601,7 +527,6 @@ abstract class Server { } // Toggle Timewarp Mode - // @todo in forms, the cursor is in the wrong location for ANSI if ($cmd === '01') { $client->send(COFF); $timewarp = !$timewarp; @@ -609,11 +534,20 @@ abstract class Server { $cmd = ''; $action = $mode = FALSE; + if ($current['prevmode'] == MODE_FIELD) { + $mode = $current['prevmode']; + $current['prevmode'] = FALSE; + + if ($x=$this->fo->getField()) { + // @todo This WHITE should be removed, and the color set to whatever is in the frame + $client->send($this->moveCursor($x->x+strlen($this->fo->getFieldCurrentInput()),$x->y).CON.WHITE); + } + } + break; } // Present Timewarp Frames - // @todo in forms, the cursor is in the wrong location for ANSI if ($cmd === '02') { $client->send(COFF); $action = ACTION_INFO; @@ -671,10 +605,16 @@ abstract class Server { $mode = $current['prevmode']; $current['prevmode'] = FALSE; - // @todo The cursor color could be wrong - $client->send($this->moveCursor($current['field']->x,$current['field']->y).CON); - $client->send(str_repeat($this->fo::$if_filler,$current['field']->length)); - $current['fieldreset'] = TRUE; + if (! $this->fo->getField()) + $this->fo->setFieldPrev(); + + if ($x=$this->fo->getField()) { + // @todo This WHITE should be removed, and the color set to whatever is in the frame + $client->send($this->moveCursor($x->x,$x->y).CON.WHITE); + $client->send(str_repeat($this->fo::$if_filler,$x->length)); + $client->send($this->moveCursor($x->x,$x->y)); + $this->fo->resetCurrentFieldData(); + } } else { $mode = FALSE; @@ -696,7 +636,10 @@ abstract class Server { // Our method count should be zero if ($method->count()) - dd($method); + { + dump($method); + throw new \Exception('Method count should be zero, but its not...',500); + } } // Nothing typed between * and # @@ -829,8 +772,10 @@ abstract class Server { // We need this extra test in case we come from ACTION_BACKUP if ($action == ACTION_NEXT) { - $current['page']['index'] = $this->fo->index(); - $next_page = ['frame'=>$this->fo->frame(),'index'=>$this->fo->index_next()]; + $next_page = [ + 'frame'=>$this->fo->frame(), + 'index'=>$this->fo->index_next() + ]; } // Look for requested page - charge for it to be loaded. @@ -917,7 +862,6 @@ abstract class Server { $history->push($next_page); } - $current['fieldpos'] = 0; $this->fo = $fo; $fo = NULL; $next_page = NULL; @@ -965,27 +909,21 @@ abstract class Server { // Active Frame. Prestel uses this for a Response Frame. case Frame::FRAMETYPE_ACTION: $client->send($output); - // holds data entered by user. - $fielddata = []; - $current['fielddata'] = []; if ($this->fo->fields()->count()) { - // Get our first editable field. - $current['fieldnum'] = $this->fo->getFieldId('edit',0); - $current['field'] = $this->fo->getField($current['fieldnum']); - $current['fieldreset'] = TRUE; + $this->fo->resetCurrentField(); - if ($current['fieldnum'] !== FALSE) { + if ($x=$this->fo->getField()) { $mode = MODE_FIELD; + // @todo This WHITE should be removed, and the color set to whatever is in the frame + $client->send($this->moveCursor($x->x,$x->y).CON.WHITE); - // There were no editable fields. + // There were no editable fields. } else { $mode = MODE_COMPLETE; $client->send(COFF); } - $current['fieldpos'] = 0; - } else { $mode = FALSE; } @@ -1018,7 +956,7 @@ abstract class Server { if (count($alts)) { $n = 1; - $output .= $this->moveCursor(0,$y++).WHITE.NEWBG.RED.'ALTERNATIVE VERSIONS:'.str_repeat(' ',16); + $output .= $this->moveCursor(0,$y++).WHITE.SPACE.NEWBG.RED.'ALTERNATIVE VERSIONS:'.str_repeat(' ',16); foreach ($alts as $o) { $date = $o->created_at->format('d M Y'); @@ -1026,10 +964,10 @@ abstract class Server { $line = WHITE.NEWBG; if ($timewarp) { - $line .= RED.$n++; + $line .= RED.SPACE.$n++; } - $line .= BLUE.$date.' '.$o->note; + $line .= BLUE.SPACE.$date.' '.$o->note; $output .= $this->moveCursor(0,$y++).$line.str_repeat(' ',40-$this->fo->strlenv($line)); // @todo should use frame::page_length } @@ -1052,12 +990,6 @@ abstract class Server { serialize($action), $control); - // We need to reposition the cursor to the current field. - if ($current['fieldreset'] !== FALSE) { - $client->send($this->moveCursor($current['field']->x,$current['field']->y).CON); - $current['fieldreset'] = FALSE; - } - // Did the client disconnect if ($read === NULL || socket_last_error()) { $client->close(); diff --git a/app/Classes/Server/Ansi.php b/app/Classes/Server/Ansi.php index da84bb3..dcf8b2f 100644 --- a/app/Classes/Server/Ansi.php +++ b/app/Classes/Server/Ansi.php @@ -24,26 +24,26 @@ class Ansi extends AbstractServer { define('CLS', ESC.'[2J'); define('HASH', '#'); // Enter define('STAR', '*'); // Star Entry - define('SPACE', ' '); // Space + define('SPACE', ' '); // Space (for compatibility with Videotex) // 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('RED', ESC.'[0;31m'); + define('GREEN', ESC.'[0;32m'); + define('YELLOW', ESC.'[1;33m'); + define('BLUE', ESC.'[0;34m'); + define('MAGENTA', ESC.'[0;35m'); + define('CYAN', ESC.'[0;36m'); + define('WHITE', ESC.'[1;37m'); 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); + // Compatibility attributes (to Videotex). + define('R_RED', RED.SPACE); + define('R_GREEN', GREEN.SPACE); + define('R_YELLOW', YELLOW.SPACE); + define('R_BLUE', BLUE.SPACE); + define('R_MAGENTA', MAGENTA.SPACE); + define('R_CYAN', CYAN.SPACE); + define('R_WHITE', WHITE.SPACE); //define('FLASH',chr(8)); // Keyboard presses