2018-12-01 21:50:34 +00:00
< ? php
/**
* Viewdata / Videotex Server
*
* Inspired by Rob O ' Donnell at irrelevant . com
*/
namespace App\Console\Commands ;
use App\Classes\Frame ;
use Illuminate\Console\Command ;
use Illuminate\Database\Eloquent\ModelNotFoundException ;
use Illuminate\Support\Facades\Log ;
use Sock\ { SocketClient , SocketServer , SocketException };
class Server extends Command
{
/**
* The name and signature of the console command .
*
* @ var string
*/
protected $signature = 'server' ;
/**
* The console command description .
*
* @ var string
*/
protected $description = 'Start Videotex Server' ;
/**
* Create a new command instance .
*
* @ return void
*/
public function __construct ()
{
parent :: __construct ();
}
/**
* Execute the console command .
*
* @ return mixed
* @ throws \Sock\SocketException
*/
public function handle ()
{
/**
* Check dependencies
*/
if ( ! extension_loaded ( 'sockets' ) ) {
throw new SocketException ( SocketException :: CANT_ACCEPT , 'Missing sockets extension' );
}
if ( ! extension_loaded ( 'pcntl' ) ) {
throw new SocketException ( SocketException :: CANT_ACCEPT , 'Missing pcntl extension' );
}
// @todo Deprecate this function
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' );
// @todo Deprecate this
include_once ( 'classes/vvdatabase.class.php' );
$server = new SocketServer ( config ( 'app.port' ), config ( 'app.bind' ));
$server -> init ();
$server -> setConnectionHandler ([ $this , 'onConnect' ]);
$server -> listen ();
}
/**
* Connection handler
2018-12-03 12:59:22 +00:00
*
* @ todo : Pressing * three times gets " Shouldnt get here " .
2018-12-01 21:50:34 +00:00
*/
function onConnect ( SocketClient $client ) {
Log :: info ( 'Connection from: ' ,[ 'client' => $client -> getAddress ()]);
// @todo To Deprecate in favour of config()
global $config ;
include ( 'config/config.php' );
2018-12-05 10:50:38 +00:00
$pid = pcntl_fork ();
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
if ( $pid == - 1 )
2018-12-01 21:50:34 +00:00
throw new SocketException ( SocketException :: CANT_ACCEPT , 'Could not fork process' );
// Parent return ready for next connection
2018-12-05 10:50:38 +00:00
elseif ( $pid )
2018-12-01 21:50:34 +00:00
return ;
// We are now the child.
2018-12-03 12:59:22 +00:00
try {
$session_init = $session_option = FALSE ;
$session_note = '' ; // TCP Session Notice
$session_term = '' ; // TCP Terminal Type
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
$client -> send ( TCP_IAC . TCP_DO . TCP_OPT_SUP_GOAHEAD ); // DO SUPPRES GO AHEAD
$client -> send ( TCP_IAC . TCP_WONT . TCP_OPT_LINEMODE ); // WONT LINEMODE
$client -> send ( TCP_IAC . TCP_DO . TCP_OPT_ECHO ); // DO ECHO
// $client->send(TCP_IAC.TCP_AYT); // AYT
$client -> send ( TCP_IAC . TCP_DO . TCP_OPT_TERMTYPE . TCP_IAC . TCP_SB . TCP_OPT_TERMTYPE . TCP_OPT_ECHO . TCP_IAC . TCP_SE ); // Request Term Type
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
$client -> send ( CLS );
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// @todo Deprecate and have an exception handler handle this.
// like throw new FatalClientException(CLS.UP.ERR_DATABASE,500,NULL,$client);
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// @todo Get the login/start page, and if it is not available, throw the ERR_DATEBASE error.
$db = new \vvdb ();
// Connect to database. Returns error message if unable to connect.
$r = $db -> connect ( $config [ 'dbserver' ], $config [ 'database' ], $config [ 'dbuser' ], $config [ 'dbpass' ]);
/*
if ( ! empty ( $r )) {
http_response_code ( 500 );
$client -> send ( CLS . UP . ERR_DATABASE );
die ( $r );
}
*/
// $user will eventually contain validated user details.
$user = array ( 'systel' => '019990001' ,
'username' => 'DEMONSTRATION DATA USER' ,
'address1' => '8 HERBAL HILL' ,
'address2' => 'LONDON' ,
'address3' => 'EC1R 5EJ' ,
'address4' => '' ,
'address5' => '' ,
'CUGS' => array ( 7800 , 15500 ), // Closed User Groups this user has access to
);
2018-12-05 10:50:38 +00:00
// Setup VARS
$timewarp = FALSE ; // Is timewarp active.
$history = collect (); // Page history for going backwards
$action = ACTION_GOTO ; // Initial action.
$cmd = '' ; // Current *command being typed in
$mode = FALSE ; // Current mode.
$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)
2018-12-03 12:59:22 +00:00
$prevmode = false ; // previous mode
2018-12-05 10:50:38 +00:00
2018-12-03 12:59:22 +00:00
if ( isset ( $config [ 'loginpage' ])) {
2018-12-05 10:50:38 +00:00
$page = [ 'frame' => $config [ 'loginpage' ], 'index' => 'a' ];
2018-12-03 12:59:22 +00:00
} else if ( ! empty ( $service [ 'start_page' ])) {
2018-12-05 10:50:38 +00:00
$page = [ 'frame' => $service [ 'start_page' ], 'index' => 'a' ];
2018-12-03 12:59:22 +00:00
} else {
2018-12-05 10:50:38 +00:00
$page = [ 'frame' => '98' , 'index' => 'a' ]; // next page
2018-12-03 12:59:22 +00:00
}
2018-12-05 10:50:38 +00:00
2018-12-03 12:59:22 +00:00
$curfp = 0 ; // current field, position within.
$blp = 0 ; // botton line polluted (by this no. of characters)
if ( ! isset ( $config [ 'varient_id' ]))
$config [ 'varient_id' ] = NULL ;
$service = $db -> getServiceById ( $config [ 'service_id' ]);
//dd($service);
$varient = $db -> getAllVarients ( $config [ 'service_id' ], $config [ 'varient_id' ]);
if ( $varient === false ) {
die ( " no varient " );
}
$varient = reset ( $varient );
$matches = array ();
if ( preg_match ( '@' . $service [ 'page_format' ] . '@' , $service [ 'start_frame' ], $matches )) {
2018-12-05 10:50:38 +00:00
$page [ 'frame' ] = $matches [ 1 ];
$page [ 'index' ] = $matches [ 2 ];
echo " Using start page " . $page [ 'frame' ] . $page [ 'index' ] . " \n " ;
2018-12-03 12:59:22 +00:00
}
2018-12-01 21:50:34 +00:00
// $start = $service['start_frame'];
// where to start from
2018-12-03 12:59:22 +00:00
while ( $action != ACTION_TERMINATE ) {
// Read a character from the client session
$read = $client -> read ( 1 );
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
if ( $read != '' ) {
2018-12-05 10:50:38 +00:00
dump ( sprintf ( 'Mode: [%s] CMD: [%s] frame: [%s] Received [%s (%s)]' , $mode , $cmd , $page [ 'frame' ] . $page [ 'index' ], $read , ord ( $read )));
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// Client initiation input
// TELNET http://pcmicro.com/netfoss/telnet.html
if ( $read == TCP_IAC OR $session_init OR $session_option ) {
Log :: debug ( sprintf ( 'Session Char (%s)' , ord ( $read )), [ 'init' => $session_init , 'option' => $session_option ]);
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
switch ( $read ) {
// Command being sent.
case TCP_IAC :
$session_init = TRUE ;
$session_note = 'IAC ' ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
continue 2 ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case TCP_SB :
$session_option = TRUE ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
continue 2 ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case TCP_SE :
$session_option = $session_init = FALSE ;
Log :: debug ( 'Session Terminal: ' . $session_term );
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case TCP_DO :
$session_note .= 'DO ' ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
continue 2 ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case TCP_WILL :
$session_note .= 'WILL ' ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
continue 2 ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case TCP_WONT :
$session_note .= 'WONT ' ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
continue 2 ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case TCP_OPT_TERMTYPE :
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
continue 2 ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case TCP_OPT_ECHO :
$session_note .= 'ECHO' ;
$session_init = FALSE ;
$read = '' ;
Log :: debug ( $session_note );
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
continue ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case TCP_OPT_SUP_GOAHEAD :
$session_note .= 'SUPPRESS GO AHEAD' ;
$session_init = FALSE ;
$read = '' ;
Log :: debug ( $session_note );
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
continue ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
default :
if ( $session_option AND $read ) {
$session_term .= $read ;
$read = '' ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
} else {
Log :: debug ( sprintf ( 'Unhandled char in session_init :%s (%s)' , $read , ord ( $read )));
}
}
2018-12-01 21:50:34 +00:00
}
2018-12-03 12:59:22 +00:00
switch ( $mode ) {
// Key presses during field input.
case MODE_FIELD :
2018-12-05 10:50:38 +00:00
dump ( sprintf ( '** Processing Keypress in MODE_FIELD [%s (%s)]. Last POS [%s]' , $read , ord ( $read ), $curfp ));
2018-12-03 12:59:22 +00:00
$cmd = '' ;
$action = FALSE ;
switch ( $fo -> type ()) {
// Input frame.
case 'a' :
switch ( $read ) {
// End of field entry.
case HASH :
// Next Field
2018-12-05 10:50:38 +00:00
$current [ 'fieldnum' ] ++ ;
$curfp = 0 ;
2018-12-03 12:59:22 +00:00
2018-12-05 10:50:38 +00:00
if ( $current [ 'fieldnum' ] < $fo -> fields -> count ()) { // skip past non-editable fields
$current [ 'fieldnum' ] = $fo -> getFieldId ( 'edit' , $current [ 'fieldnum' ]);
2018-12-03 12:59:22 +00:00
2018-12-05 10:50:38 +00:00
if ( $current [ 'fieldnum' ] !== FALSE ) {
$current [ 'field' ] = $fo -> getField ( $current [ 'fieldnum' ]);
$fielddata [ $current [ 'fieldnum' ]] = '' ;
dump ([ 'Working field' => $current [ 'field' ]]);
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
dump ([ 'line' => __LINE__ , 'field' => $current [ 'field' ], 'x' => $current [ 'field' ] -> x ]);
$client -> send ( $this -> outputPosition ( $current [ 'field' ] -> x , $current [ 'field' ] -> y ) . CON );
2018-12-03 12:59:22 +00:00
$mode = MODE_FIELD ;
2018-12-05 10:50:38 +00:00
$fielddate [ $current [ 'fieldnum' ]] = '' ;
2018-12-03 12:59:22 +00:00
2018-12-05 10:50:38 +00:00
// There were no (more) editable fields.
2018-12-03 12:59:22 +00:00
} else {
$action = ACTION_SUBMITRF ;
}
2018-12-01 21:50:34 +00:00
} else {
2018-12-03 12:59:22 +00:00
// done them all editable fields.
2018-12-01 21:50:34 +00:00
$action = ACTION_SUBMITRF ;
}
2018-12-03 12:59:22 +00:00
break ;
case STAR :
$prevmode = MODE_FIELD ;
$action = ACTION_STAR ;
2018-12-05 10:50:38 +00:00
$curfp = 0 ;
$fielddata [ $current [ 'fieldnum' ]] = '' ;
2018-12-03 12:59:22 +00:00
break ;
case KEY_LEFT :
2018-12-05 10:50:38 +00:00
if ( $curfp -- ) {
2018-12-03 12:59:22 +00:00
$client -> send ( LEFT );
};
break ;
case KEY_RIGHT :
2018-12-05 10:50:38 +00:00
if ( $curfp ++ < $current [ 'field' ] -> length ) {
2018-12-03 12:59:22 +00:00
$client -> send ( RIGHT );
};
break ;
case KEY_DOWN :
2018-12-05 10:50:38 +00:00
if ( $curfp + 40 < $current [ 'field' ] -> length ) {
2018-12-03 12:59:22 +00:00
$client -> send ( DOWN );
$curfp = $curfp + 40 ;
};
break ;
case KEY_UP :
if ( $curfp - 40 >= 0 ) {
$client -> send ( $read );
$curfp = $curfp - 40 ;
};
break ;
case CR :
2018-12-05 10:50:38 +00:00
if ( $curfp + $current [ 'field' ] -> x > 40 ) { // on second or later line of a field
2018-12-03 12:59:22 +00:00
$client -> send ( $read );
2018-12-05 10:50:38 +00:00
$curfp = (( $curfp + $current [ 'field' ] -> x ) % 40 ) * 40 ;
2018-12-03 12:59:22 +00:00
} else {
2018-12-05 10:50:38 +00:00
dump ([ 'line' => __LINE__ , 'field' => $current [ 'field' ]]);
$client -> send ( $this -> outputPosition ( $current [ 'field' ] -> x , $current [ 'field' ] -> y ) . CON );
2018-12-03 12:59:22 +00:00
$curfp = 0 ;
}
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case ESC :
break ;;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// Record Data Entry
default :
2018-12-05 10:50:38 +00:00
if ( ord ( $read ) > 31 && $curfp < $current [ 'field' ] -> length ) {
$fielddata [ $current [ 'fieldnum' ]]{ $curfp } = $read ;
2018-12-03 12:59:22 +00:00
$curfp ++ ;
$client -> send ( $read );
}
}
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// Other Frame Types - Shouldnt get here.
default :
$client -> close ();
throw new \Exception ( 'Shouldnt get here' , 500 );
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
} // switch frame types
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// Form submission: 1 to send, 2 not to send.
case MODE_SUBMITRF :
switch ( $read ) {
// @todo Input received, process it.
case '1' :
2018-12-05 10:50:38 +00:00
dump ([ 'line' => __LINE__ , 's' => $service , 'f' => $fielddata ]);
// @todo if send successful or not
2018-12-03 12:59:22 +00:00
if ( TRUE ) {
sendBaseline ( $client , $blp , MSG_SENT );
$mode = MODE_RFSENT ;
} else {
sendBaseline ( $client , $blp , ERR_NOTSENT );
$mode = MODE_RFERROR ;
}
break ;
case '2' :
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
sendBaseline ( $client , $blp , MSG_NOTSENT );;
$mode = MODE_RFNOTSENT ;
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case STAR :
$action = ACTION_STAR ;
break ;
2018-12-01 21:50:34 +00:00
}
break ;
2018-12-03 12:59:22 +00:00
// Response form after Sent processing
// @todo To fix.
case MODE_RFSENT :
$client -> send ( COFF );
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
if ( $read == HASH ) {
if ( ! empty ( $pagedata [ 'route1' ])) {
$action = ACTION_GOTO ;
2018-12-05 10:50:38 +00:00
$page [ 'frame' ] = $pagedata [ 'route1' ];
$page [ 'index' ] = 'a' ;
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
} else if ( \App\Models\Frame :: where ( 'frame' , $fo -> frame ()) -> where ( 'index' , $fo -> index_next ()) -> exists ()) {
2018-12-03 12:59:22 +00:00
$action = ACTION_GOTO ;
2018-12-05 10:50:38 +00:00
$page [ 'frame' ] = array_get ( $current , 'page.frame' );
$page [ 'index' ] = chr ( 1 + ord ( $page [ 'index' ]));
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
} else if ( ! empty ( $pagedata [ 'route0' ])) {
$action = ACTION_GOTO ;
2018-12-05 10:50:38 +00:00
$page [ 'frame' ] = $pagedata [ 'route0' ];
$page [ 'index' ] = 'a' ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// No further routes defined, go home.
} else {
$action = ACTION_GOTO ;
2018-12-05 10:50:38 +00:00
$page [ 'frame' ] = '0' ;
$page [ 'index' ] = 'a' ;
2018-12-03 12:59:22 +00:00
}
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
} elseif ( $read == STAR ) {
$action = ACTION_STAR ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
break ;
2018-12-01 21:50:34 +00:00
}
break ;
2018-12-03 12:59:22 +00:00
// Response form after NOT sending
case MODE_RFNOTSENT :
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// Response form ERROR
// @todo To fix
case MODE_RFERROR :
$client -> send ( COFF );
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
if ( $read == HASH ) {
if ( ! empty ( $pagedata [ 'route2' ])) {
$action = ACTION_GOTO ;
2018-12-05 10:50:38 +00:00
$page [ 'frame' ] = $pagedata [ 'route2' ];
$page [ 'index' ] = 'a' ;
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
} else if ( \App\Models\Frame :: where ( 'frame' , $fo -> frame ()) -> where ( 'index' , $fo -> index_next ()) -> exists ()) {
2018-12-03 12:59:22 +00:00
$action = ACTION_GOTO ;
2018-12-05 10:50:38 +00:00
$page [ 'frame' ] = $fo -> frame ();
$page [ 'index' ] = $fo -> index_next ();
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
} else if ( ! empty ( $pagedata [ 'route0' ])) {
2018-12-01 21:50:34 +00:00
$action = ACTION_GOTO ;
2018-12-05 10:50:38 +00:00
$page [ 'frame' ] = $pagedata [ 'route0' ];
$page [ 'index' ] = 'a' ;
2018-12-03 12:59:22 +00:00
// No further routes defined, go home.
2018-12-01 21:50:34 +00:00
} else {
2018-12-03 12:59:22 +00:00
$action = ACTION_GOTO ;
2018-12-05 10:50:38 +00:00
$page [ 'frame' ] = '0' ;
$page [ 'index' ] = 'a' ;
2018-12-01 21:50:34 +00:00
}
2018-12-03 12:59:22 +00:00
} else if ( $read == STAR ) {
$action = ACTION_STAR ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
break ;
}
2018-12-01 21:50:34 +00:00
break ;
2018-12-03 12:59:22 +00:00
/*
List of alternate options has been presented
*/
case MODE_WARPTO : // expecting a timewarp selection
if ( isset ( $alts [ $read - 1 ])) {
$v = $db -> getAllVarients ( $config [ 'service_id' ], $alts [ $read - 1 ][ 'varient_id' ]);
if ( ! empty ( $v )) {
$varient = reset ( $v );
2018-12-05 10:50:38 +00:00
$page = array_get ( $current , 'page' );
2018-12-03 12:59:22 +00:00
$action = ACTION_GOTO ;
break ;
}
2018-12-01 21:50:34 +00:00
}
2018-12-03 12:59:22 +00:00
// if wasn't a valid warpto keypress,
//drop into
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// Not doing anything in particular.
2018-12-05 10:50:38 +00:00
case MODE_COMPLETE :
2018-12-03 12:59:22 +00:00
case FALSE :
2018-12-05 10:50:38 +00:00
Log :: debug ( 'Idle' , [ 'pid' => $pid ]);
2018-12-03 12:59:22 +00:00
$cmd = '' ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
switch ( $read ) {
case HASH :
$action = ACTION_NEXT ;
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case STAR :
$action = ACTION_STAR ;
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// Frame Routing
case '0' :
case '1' :
case '2' :
case '3' :
case '4' :
case '5' :
case '6' :
case '7' :
case '8' :
case '9' :
if ( $frame = $fo -> route ( $read )) {
$action = ACTION_GOTO ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
} else {
2018-12-05 10:50:38 +00:00
dump ([ 'line' => __LINE__ , 'blp was' => $blp ]);
2018-12-03 12:59:22 +00:00
sendBaseline ( $client , $blp , ERR_ROUTE );
$mode = $action = FALSE ;
}
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
break ;
}
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
/*
currently accepting baseline imput after a * was received
*/
case MODE_BL : // entering a baseline command
echo " was waiting for page number \n " ;
// if it's a number, continue entry
if ( strpos ( '0123456789' , $read ) !== false ) { // numeric
$cmd .= $read ;
$client -> send ( $read );
$blp ++ ;
2018-12-05 10:50:38 +00:00
dump ([ 'line' => __LINE__ , 'blp is now' => $blp ]);
2018-12-03 12:59:22 +00:00
}
// if we hit a special numeric command, deal with it.
if ( $cmd === '00' ) { // refresh page
$client -> send ( COFF );
$action = ACTION_RELOAD ;
$cmd = '' ;
break ;
}
if ( $cmd === '09' ) { // reload page
$client -> send ( COFF );
$action = ACTION_GOTO ;
$cmd = '' ;
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
}
if ( $cmd === '02' ) { // new for emulator
$client -> send ( COFF );
$action = ACTION_INFO ;
$cmd = '' ;
break ;
}
if (( $cmd === '01' )) { // new for emulator
$client -> send ( COFF );
$timewarp = ! $timewarp ;
sendBaseline ( $client , $blp ,
( $timewarp ? MSG_TIMEWARP_ON : MSG_TIMEWARP_OFF ));
$cmd = '' ;
$action = $mode = false ;
}
// another star aborts the command.
if ( $read === " * " ) { // abort command or reset input field.
$action = false ;
sendBaseline ( $client , $blp , '' );
2018-12-05 10:50:38 +00:00
dump ([ 'line' => __LINE__ , 'blp is now' => $blp ]);
2018-12-03 12:59:22 +00:00
$cmd = '' ;
if ( $prevmode == MODE_FIELD ) {
$mode = $prevmode ;
$prevmode = false ;
2018-12-05 10:50:38 +00:00
dump ([ 'line' => __LINE__ , 'field' => $current [ 'field' ]]);
$client -> send ( $this -> outputPosition ( $current [ 'field' ] -> x , $current [ 'field' ] -> y ) . CON );
$client -> send ( str_repeat ( '.' , $current [ 'field' ] -> length ));
2018-12-03 12:59:22 +00:00
// tood reset stored entered text
2018-12-05 10:50:38 +00:00
$current [ 'fieldreset' ] = TRUE ;
2018-12-03 12:59:22 +00:00
} else {
$mode = false ;
}
break ;
}
2018-12-05 10:50:38 +00:00
2018-12-03 12:59:22 +00:00
// user hit # to complete request
if ( $read === '_' ) { // really the # key,
$client -> send ( COFF );
if ( $cmd === '' ) { // nothing typed between * and #
$action = ACTION_BACKUP ;
} else { // *# means go back
2018-12-05 10:50:38 +00:00
$page [ 'frame' ] = $cmd ;
$page [ 'index' ] = 'a' ;
2018-12-03 12:59:22 +00:00
$action = ACTION_GOTO ;
}
$cmd = '' ; // finished with this now
break ;
}
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
default :
echo " not sure what we were doing \n " ;
} // switch $mode
} // something in $read
/*
This section performs some action if it is deemed necessary
*/
if ( $action ) {
echo " Performing action $action\n " ;
}
switch ( $action ) {
case ACTION_STAR :
echo " star command started \n " ;
sendBaseline ( $client , $blp , GREEN . '*' , true );
$client -> send ( CON );
$action = false ;
$mode = MODE_BL ;
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case ACTION_SUBMITRF :
$action = false ;
sendBaseline ( $client , $bpl , MSG_SENDORNOT );
$mode = MODE_SUBMITRF ;
2018-12-01 21:50:34 +00:00
break ;
2018-12-05 10:50:38 +00:00
// GO Backwards
2018-12-03 12:59:22 +00:00
case ACTION_BACKUP :
2018-12-05 10:50:38 +00:00
// Do we have anywhere to go, drop the current page from the history.
if ( $history -> count () > 1 )
$history -> pop ();
$page = $history -> last ();
Log :: debug ( 'Backing up to: ' . $page [ 'frame' ] . $page [ 'index' ]);
// Go to next index frame.
2018-12-03 12:59:22 +00:00
case ACTION_NEXT :
2018-12-05 10:50:38 +00:00
// We need this extra test in case we come from ACTION_BACKUP
if ( $action == ACTION_NEXT )
{
dump ([ 'current.page.index' => $current [ 'page' ][ 'index' ], 'fo' => $fo -> index ()]);
$current [ 'page' ][ 'index' ] = $fo -> index ();
$page [ 'index' ] = $fo -> index_next ();
2018-12-03 12:59:22 +00:00
}
2018-12-05 10:50:38 +00:00
2018-12-03 12:59:22 +00:00
case ACTION_GOTO :
2018-12-05 10:50:38 +00:00
// $client->send(HOME . UP . GREEN . "Searching for page $page['frame']");
// $blp = 20 + strlenv($page['frame']);
2018-12-03 12:59:22 +00:00
// look for requested page
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
try {
2018-12-05 10:50:38 +00:00
$fo = ( new \App\Models\Frame ) -> fetch ( $page [ 'frame' ], $page [ 'index' ]);
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
} catch ( ModelNotFoundException $e ) {
sendBaseline ( $client , $blp , ERR_PAGE );
$mode = $action = FALSE ;
2018-12-05 10:50:38 +00:00
2018-12-01 21:50:34 +00:00
break ;
2018-12-03 12:59:22 +00:00
}
2018-12-05 10:50:38 +00:00
dump ([ 'm' => __METHOD__ , 'fo' => $fo -> id (), 'service' => $service [ 'service_id' ], 'varient' => $varient [ 'varient_id' ], 'frame' => $fo -> page (), 'type' => $fo -> type ()]);
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// validate if we have access top it
/* if ( isset ( $m [ 'access' ]) && $m [ 'access' ] == 'n' ) {
sendBaseline ( $client , $blp , ERR_PAGE );
$mode = $action = false ;
break ;
}
if ( isset ( $m [ 'cug' ]) && is_numeric ( $m [ 'cug' ]) && $m [ 'cug' ] && ! in_array ( $m [ 'cug' ], $usercugs )) {
sendBaseline ( $client , $blp , ERR_PRIVATE );
$mode = $action = false ;
break ;
}
*/
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// we have access...
if ( $r [ 'varient_id' ] != $varient [ 'varient_id' ]) {
if ( empty ( $v [ 'varient_date' ])) {
sendBaseline ( $client , $blp , sprintf ( MSG_TIMEWARP_TO , 'unknown date' ));
2018-12-01 21:50:34 +00:00
} else {
2018-12-03 12:59:22 +00:00
sendBaseline ( $client , $blp , sprintf ( MSG_TIMEWARP_TO , date ( 'j f Y' , strtotime ( $v [ 'varient_date' ]))));
2018-12-01 21:50:34 +00:00
}
2018-12-03 12:59:22 +00:00
$varient = array_merge ( $varient , array_intersect_key ( $r , $varient ));
}
//var_dump(['B','r'=>$r,'m'=>$m]);
//$pagedata = array_merge($r, $m);
//$varient = $v;
2018-12-05 10:50:38 +00:00
$current [ 'page' ] = $fo -> page ( TRUE );
2018-12-03 12:59:22 +00:00
$curfp = 0 ;
//$pageflags = $db->getFrameTypeFlags($pagedata['type']); // method missing.
$pageflags = [];
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
// Only if new location, not going backwards
if (( $history -> last () != $page ) AND ( $action == ACTION_GOTO || $action == ACTION_NEXT )) {
$history -> push ( $page );
2018-12-03 12:59:22 +00:00
}
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
// drop into
case ACTION_RELOAD :
2018-12-05 10:50:38 +00:00
// @todo Move the $output into the object.
if ( $fo -> hasFlag ( 'clear' ))
{
$blp = 0 ;
$output = CLS ;
} else {
$output = HOME ;
// Clear the baseline.
$blp = sendBaseline ( $client , $blp , '' );
}
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
$output .= ( string ) $fo ;
2018-12-03 12:59:22 +00:00
switch ( $fo -> type ()) {
default :
case 'i' : // standard frame
if ( $timewarp && 1 < count (
2018-12-05 10:50:38 +00:00
$alts = $db -> getAlternateFrames ( $service [ 'service_id' ], $varient [ 'varient_id' ], array_get ( $current , 'page.frame' ), array_get ( $current , 'page.index' ))
2018-12-03 12:59:22 +00:00
)) {
$msg = MSG_TIMEWARP ;
2018-12-01 21:50:34 +00:00
} else {
2018-12-03 12:59:22 +00:00
$msg = '' ;
2018-12-01 21:50:34 +00:00
}
2018-12-05 10:50:38 +00:00
dump ([ 'line' => __LINE__ , 'blp was' => $blp , 'will be' => strlenv ( $msg )]);
2018-12-03 12:59:22 +00:00
$blp = strlenv ( $msg );
$client -> send ( $output );
$mode = $action = false ;
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case 'a' : // active frame. Prestel uses this for Response Framea.
/*
if ( $timewarp && 1 < count (
2018-12-05 10:50:38 +00:00
$alts = $db -> getAlternateFrames ( $service [ 'service_id' ], $varient [ 'varient_id' ], array_get ( $current , 'page.frame' ), array_get ( $current , 'page.index' ))
2018-12-03 12:59:22 +00:00
)) {
$msg = MSG_TIMEWARP ;
} else {
$msg = '' ;
}
*/
// this is a glorious hack to fix three out of 30,000 pages but might
// break lots more.
//$pagedata = str_replace(chr(12),chr(27),$pagedata);
// holds data entered by user.
2018-12-05 10:50:38 +00:00
$fielddata = [];
2018-12-03 12:59:22 +00:00
2018-12-05 10:50:38 +00:00
//$msg = '';
2018-12-03 12:59:22 +00:00
2018-12-05 10:50:38 +00:00
//dump(['line'=>__LINE__,'blp was'=>$blp,'will be'=>strlenv($msg)]);
//$blp = strlenv($msg);
$client -> send ( $output );
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
// dump($fo->fields,count($fo->fields));
// @todo If there are no editable fields, it seems the frame is hung.
if ( count ( $fo -> fields )) {
// Get our first editable field.
$current [ 'fieldnum' ] = $fo -> getFieldId ( 'edit' , 0 );
$current [ 'field' ] = $fo -> getField ( $current [ 'fieldnum' ]);
$current [ 'fieldreset' ] = TRUE ;
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
if ( $current [ 'fieldnum' ] !== FALSE ) {
2018-12-03 12:59:22 +00:00
$mode = MODE_FIELD ;
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
// There were no editable fields.
2018-12-03 12:59:22 +00:00
} else {
$mode = MODE_COMPLETE ;
2018-12-05 10:50:38 +00:00
$client -> send ( COFF );
2018-12-03 12:59:22 +00:00
}
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
$curfp = 0 ;
}
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case 't' : // terminate
2018-12-05 10:50:38 +00:00
//$output = getOutputx(array_get($current,'page.frame'), array_get($current,'page.index'), [], $pageflags);
2018-12-03 12:59:22 +00:00
$client -> send ( $output );
$action = ACTION_TERMINATE ;
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
} // switch
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
case ACTION_INFO : // special emulator command
$mode = false ;
$cmd = '' ;
$action = false ;
2018-12-05 10:50:38 +00:00
// @todo Can we use $fo->page() where?
$output = $this -> outputPosition ( 0 , 0 ) . WHITE . NEWBG . RED . 'TIMEWARP INFO FOR Pg.' . BLUE . array_get ( $current , 'page.frame' ) . array_get ( $current , 'page.index' ) . WHITE ;
$output .= $this -> outputPosition ( 0 , 1 ) . WHITE . NEWBG . BLUE . 'Service : ' . substr ( $service [ 'service_name' ] . str_repeat ( ' ' , 27 ), 0 , 27 );
$output .= $this -> outputPosition ( 0 , 2 ) . WHITE . NEWBG . BLUE . 'Varient : ' . substr ( $varient [ 'varient_name' ] . str_repeat ( ' ' , 27 ), 0 , 27 );
$output .= $this -> outputPosition ( 0 , 3 ) . WHITE . NEWBG . BLUE . 'Dated : ' . substr ( date ( 'j F Y' , strtotime ( $varient [ 'varient_date' ])) . str_repeat ( ' ' , 27 ), 0 , 27 );
2018-12-03 12:59:22 +00:00
2018-12-05 10:50:38 +00:00
$alts = $db -> getAlternateFrames ( $service [ 'service_id' ], $varient [ 'varient_id' ], array_get ( $current , 'page.frame' ), array_get ( $current , 'page.index' ));
2018-12-03 12:59:22 +00:00
if ( count ( $alts ) > 1 ) {
$n = 1 ;
2018-12-05 10:50:38 +00:00
$output .= $this -> outputPosition ( 0 , 4 ) . WHITE . NEWBG . RED . 'ALTERNATIVE VERSIONS:' . str_repeat ( ' ' , 16 );
2018-12-03 12:59:22 +00:00
$y = 5 ;
foreach ( $alts as $ss ) {
2018-12-01 21:50:34 +00:00
// if (is_numeric($ss['varient_date'])) {
2018-12-03 12:59:22 +00:00
$date = date ( 'd M Y' , strtotime ( $ss [ 'varient_date' ]));
2018-12-01 21:50:34 +00:00
// } else {
// $date = 'unknown';
// }
2018-12-03 12:59:22 +00:00
$line = WHITE . NEWBG ;
if ( $timewarp ) {
$line .= RED . $n ;
}
$line .= BLUE . $date . ' ' . $ss [ 'varient_name' ];
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
$output .= $this -> outputPosition ( 0 , $y ) . $line . str_repeat ( ' ' , 40 - strlenv ( $line ));
2018-12-03 12:59:22 +00:00
$y ++ ;
$n ++ ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
}
if ( $timewarp ) {
$mode = MODE_WARPTO ;
}
2018-12-01 21:50:34 +00:00
}
2018-12-03 12:59:22 +00:00
$client -> send ( $output );
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
break ;
2018-12-01 21:50:34 +00:00
2018-12-03 12:59:22 +00:00
default :
;
} // switch $action
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
// We need to reposition the cursor to the current field.
if ( $current [ 'fieldreset' ] !== FALSE ) {
$client -> send ( $this -> outputPosition ( $current [ 'field' ] -> x , $current [ 'field' ] -> y ) . CON );
$current [ 'fieldreset' ] = FALSE ;
2018-12-03 12:59:22 +00:00
}
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
// Did the client disconnect
if ( $read === NULL || socket_last_error ()) {
Log :: debug ( 'Disconnected: ' . $client -> getaddress ());
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
return FALSE ;
2018-12-03 12:59:22 +00:00
}
2018-12-01 21:50:34 +00:00
}
2018-12-03 12:59:22 +00:00
// Something bad happened. We'll log it and then disconnect.
} catch ( \Exception $e ) {
Log :: emergency ( $e -> getMessage ());
2018-12-05 10:50:38 +00:00
//@todo TEMP
throw new \Exception ( $e );
2018-12-01 21:50:34 +00:00
}
$client -> close ();
2018-12-05 10:50:38 +00:00
Log :: debug ( 'Disconnected: ' . $client -> getaddress ());
}
/**
* Move the cursor via the shortest path .
*/
function outputPosition ( $x , $y ) {
// Take the shortest path.
if ( $y < 12 ) {
return HOME .
(( $x < 21 )
? str_repeat ( DOWN , $y ) . str_repeat ( RIGHT , $x )
: str_repeat ( DOWN , $y + 1 ) . str_repeat ( LEFT , 40 - $x ));
} else {
return HOME . str_repeat ( UP , 24 - $y ) .
(( $x < 21 )
? str_repeat ( RIGHT , $x )
: str_repeat ( LEFT , 40 - $x ));
}
2018-12-01 21:50:34 +00:00
}
}
function strlenv ( $text ){
return strlen ( $text ) - substr_count ( $text , ESC );
}
2018-12-03 12:59:22 +00:00
// @todo Not clearing to end of line.
2018-12-05 10:50:38 +00:00
// @todo Remove blp by reference, change return to return blp
function sendBaseline ( $client , & $blp , $text , $reposition = FALSE ) {
dump ([ 'method' => __METHOD__ , 'blp' => $blp , 'text' => $text , 're' => $reposition ]);
$client -> send ( HOME . UP . $text .
( $blp > strlenv ( $text )
? str_repeat ( ' ' , $blp - strlenv ( $text )) .
( $reposition ? HOME . UP . str_repeat ( RIGHT , strlenv ( $text )) : '' )
2018-12-01 21:50:34 +00:00
: '' )
);
2018-12-05 10:50:38 +00:00
$blp = strlenv ( $text );
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
dump ([ 'metho' => __METHOD__ , 'blp is now' => $blp ]);
2018-12-01 21:50:34 +00:00
2018-12-05 10:50:38 +00:00
return $blp ;
2018-12-01 21:50:34 +00:00
}