2020-06-08 17:53:38 +01:00
/*
* ssheven
*
* Copyright ( c ) 2020 by cy384 < cy384 @ cy384 . com >
* See LICENSE file for details
*/
2020-07-20 05:14:27 +01:00
# include "ssheven.h"
# include "ssheven-console.h"
2021-01-09 22:22:40 +00:00
# include "ssheven-net.h"
# include "ssheven-debug.h"
# include <Threads.h>
# include <MacMemory.h>
# include <Quickdraw.h>
# include <Fonts.h>
# include <Windows.h>
# include <Sound.h>
# include <Gestalt.h>
# include <Devices.h>
# include <Scrap.h>
# include <Controls.h>
# include <ControlDefinitions.h>
# include <stdio.h>
2020-07-17 02:32:31 +01:00
// sinful globals
2021-01-23 00:47:48 +00:00
struct ssheven_console con = { NULL , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , CLICK_SELECT , NULL , NULL } ;
2020-07-20 05:14:27 +01:00
struct ssheven_ssh_connection ssh_con = { NULL , NULL , kOTInvalidEndpointRef , NULL , NULL } ;
2020-10-04 03:30:48 +01:00
struct preferences prefs ;
2020-07-17 02:32:31 +01:00
2021-01-09 22:22:40 +00:00
enum THREAD_COMMAND read_thread_command = WAIT ;
enum THREAD_STATE read_thread_state = UNINTIALIZED ;
2020-07-17 02:32:31 +01:00
2020-12-12 22:55:52 +00:00
// contains a mapping of apple virtual keycode to ascii control code
// currently only for A-Z
2021-01-09 22:22:40 +00:00
// probably only works for US english keyboard layouts?
2020-12-12 22:55:52 +00:00
const uint8_t virtual_keycode_to_control_ascii [ 255 ] = { 1 , 19 , 4 , 6 , 8 , 7 , 26 , 24 , 3 , 22 , 255 , 2 , 17 , 23 , 5 , 18 , 25 , 20 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 15 , 21 , 255 , 9 , 16 , 255 , 12 , 10 , 255 , 11 , 255 , 255 , 255 , 255 , 14 , 13 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } ;
2021-01-09 22:22:40 +00:00
void set_window_title ( WindowPtr w , const char * c_name )
{
Str255 pascal_name ;
strncpy ( ( char * ) & pascal_name [ 1 ] , c_name , 254 ) ;
pascal_name [ 0 ] = strlen ( c_name ) ;
SetWTitle ( w , pascal_name ) ;
}
2020-10-04 18:41:36 +01:00
void set_terminal_string ( void )
{
/*
* terminal type to send over ssh , determines features etc . some good options :
* " vanilla " supports basically nothing
* " vt100 " just the basics
* " xterm " everything
* " xterm-mono " everything except color
* " xterm-16color " classic 16 ANSI colors only
*/
switch ( prefs . display_mode )
{
case FASTEST :
prefs . terminal_string = " xterm-mono " ;
break ;
case COLOR :
prefs . terminal_string = " xterm-16color " ;
break ;
default :
prefs . terminal_string = SSHEVEN_DEFAULT_TERM_STRING ;
break ;
}
}
2020-10-04 03:30:48 +01:00
int save_prefs ( void )
{
int ok = 1 ;
short foundVRefNum = 0 ;
long foundDirID = 0 ;
FSSpec pref_file ;
short prefRefNum = 0 ;
OSType pref_type = ' SH7p ' ;
OSType creator_type = ' SSH7 ' ;
// find the preferences folder on the system disk, create folder if needed
OSErr e = FindFolder ( kOnSystemDisk , kPreferencesFolderType , kCreateFolder , & foundVRefNum , & foundDirID ) ;
if ( e ! = noErr ) ok = 0 ;
// make an FSSpec for the new file we want to make
if ( ok )
{
e = FSMakeFSSpec ( foundVRefNum , foundDirID , PREFERENCES_FILENAME , & pref_file ) ;
2020-10-04 18:40:19 +01:00
// if the file exists, delete it
if ( e = = noErr ) FSpDelete ( & pref_file ) ;
// and then make it
e = FSpCreate ( & pref_file , creator_type , pref_type , smSystemScript ) ;
if ( e ! = noErr ) ok = 0 ;
2020-10-04 03:30:48 +01:00
}
// open the file
if ( ok )
{
e = FSpOpenDF ( & pref_file , fsRdWrPerm , & prefRefNum ) ;
if ( e ! = noErr ) ok = 0 ;
}
// write prefs to the file
if ( ok )
{
// TODO: choose buffer size more effectively
size_t write_length = 8192 ;
char * output_buffer = malloc ( write_length ) ;
memset ( output_buffer , 0 , write_length ) ;
long int i = snprintf ( output_buffer , write_length , " %d \n %d \n " , prefs . major_version , prefs . minor_version ) ;
2021-01-11 22:21:47 +00:00
i + = snprintf ( output_buffer + i , write_length - i , " %d \n %d \n %d \n %d \n " , ( int ) prefs . auth_type , ( int ) prefs . display_mode , ( int ) prefs . fg_color , ( int ) prefs . bg_color ) ;
2020-09-16 02:33:00 +01:00
2020-10-04 03:30:48 +01:00
snprintf ( output_buffer + i , prefs . hostname [ 0 ] + 1 , " %s " , prefs . hostname + 1 ) ; i + = prefs . hostname [ 0 ] ;
i + = snprintf ( output_buffer + i , write_length - i , " \n " ) ;
snprintf ( output_buffer + i , prefs . username [ 0 ] + 1 , " %s " , prefs . username + 1 ) ; i + = prefs . username [ 0 ] ;
i + = snprintf ( output_buffer + i , write_length - i , " \n " ) ;
snprintf ( output_buffer + i , prefs . port [ 0 ] + 1 , " %s " , prefs . port + 1 ) ; i + = prefs . port [ 0 ] ;
i + = snprintf ( output_buffer + i , write_length - i , " \n " ) ;
2020-10-04 18:40:19 +01:00
if ( prefs . privkey_path & & prefs . privkey_path [ 0 ] ! = ' \0 ' )
{
i + = snprintf ( output_buffer + i , write_length - i , " %s \n %s \n " , prefs . privkey_path , prefs . pubkey_path ) ;
}
else
{
i + = snprintf ( output_buffer + i , write_length - i , " \n \n " ) ;
}
2020-10-04 03:30:48 +01:00
// tell it to write all bytes
long int bytes = i ;
e = FSWrite ( prefRefNum , & bytes , output_buffer ) ;
// FSWrite sets bytes to the actual number of bytes written
if ( e ! = noErr | | ( bytes ! = i ) ) ok = 0 ;
}
// close the file
if ( prefRefNum ! = 0 )
{
e = FSClose ( prefRefNum ) ;
if ( e ! = noErr ) ok = 0 ;
}
return ok ;
}
void init_prefs ( void )
{
// initialize everything to a safe default
prefs . major_version = SSHEVEN_VERSION_MAJOR ;
prefs . minor_version = SSHEVEN_VERSION_MINOR ;
memset ( & ( prefs . hostname ) , 0 , 512 ) ;
memset ( & ( prefs . username ) , 0 , 256 ) ;
memset ( & ( prefs . password ) , 0 , 256 ) ;
memset ( & ( prefs . port ) , 0 , 256 ) ;
// default port: 22
prefs . port [ 0 ] = 2 ;
prefs . port [ 1 ] = ' 2 ' ;
prefs . port [ 2 ] = ' 2 ' ;
prefs . pubkey_path = " " ;
prefs . privkey_path = " " ;
2020-10-04 18:41:36 +01:00
prefs . terminal_string = SSHEVEN_DEFAULT_TERM_STRING ;
2020-10-04 03:30:48 +01:00
prefs . auth_type = USE_PASSWORD ;
prefs . display_mode = COLOR ;
prefs . fg_color = blackColor ;
prefs . bg_color = whiteColor ;
prefs . loaded_from_file = 0 ;
}
void load_prefs ( void )
{
// now try to load preferences from the file
short foundVRefNum = 0 ;
long foundDirID = 0 ;
FSSpec pref_file ;
short prefRefNum = 0 ;
// find the preferences folder on the system disk
OSErr e = FindFolder ( kOnSystemDisk , kPreferencesFolderType , kDontCreateFolder , & foundVRefNum , & foundDirID ) ;
if ( e ! = noErr ) return ;
// make an FSSpec for the preferences file location and check if it exists
// TODO: if I just put PREFERENCES_FILENAME it doesn't work, wtf
e = FSMakeFSSpec ( foundVRefNum , foundDirID , " \ pssheven Preferences " , & pref_file ) ;
if ( e = = fnfErr ) // file not found, nothing to load
{
return ;
}
else if ( e ! = noErr ) return ;
e = FSpOpenDF ( & pref_file , fsCurPerm , & prefRefNum ) ;
if ( e ! = noErr ) return ;
// actually read and parse the file
long int buffer_size = 8192 ;
char * buffer = NULL ;
buffer = malloc ( buffer_size ) ;
prefs . privkey_path = malloc ( 2048 ) ;
prefs . pubkey_path = malloc ( 2048 ) ;
prefs . pubkey_path [ 0 ] = ' \0 ' ;
prefs . privkey_path [ 0 ] = ' \0 ' ;
e = FSRead ( prefRefNum , & buffer_size , buffer ) ;
e = FSClose ( prefRefNum ) ;
// check the version (first two numbers)
int items_got = sscanf ( buffer , " %d \n %d " , & prefs . major_version , & prefs . minor_version ) ;
if ( items_got ! = 2 ) return ;
// only load a prefs file if the saved version number matches ours
if ( ( prefs . major_version = = SSHEVEN_VERSION_MAJOR ) & & ( prefs . minor_version = = SSHEVEN_VERSION_MINOR ) )
{
prefs . loaded_from_file = 1 ;
2021-01-11 22:21:47 +00:00
items_got = sscanf ( buffer , " %d \n %d \n %d \n %d \n %d \n %d \n %255[^ \n ] \n %255[^ \n ] \n %255[^ \n ] \n %[^ \n ] \n %[^ \n ] " , & prefs . major_version , & prefs . minor_version , ( int * ) & prefs . auth_type , ( int * ) & prefs . display_mode , & prefs . fg_color , & prefs . bg_color , prefs . hostname + 1 , prefs . username + 1 , prefs . port + 1 , prefs . privkey_path , prefs . pubkey_path ) ;
2020-10-04 03:30:48 +01:00
// add the size for the pascal strings
prefs . hostname [ 0 ] = ( unsigned char ) strlen ( prefs . hostname + 1 ) ;
prefs . username [ 0 ] = ( unsigned char ) strlen ( prefs . username + 1 ) ;
prefs . port [ 0 ] = ( unsigned char ) strlen ( prefs . port + 1 ) ;
2020-10-04 18:41:36 +01:00
set_terminal_string ( ) ;
2020-10-04 03:30:48 +01:00
}
2020-10-05 19:57:13 +01:00
else
{
prefs . major_version = SSHEVEN_VERSION_MAJOR ;
prefs . minor_version = SSHEVEN_VERSION_MINOR ;
}
2020-10-04 03:30:48 +01:00
if ( buffer ) free ( buffer ) ;
}
2020-07-17 02:32:31 +01:00
// borrowed from Retro68 sample code
// draws the "default" indicator around a button
pascal void ButtonFrameProc ( DialogRef dlg , DialogItemIndex itemNo )
{
DialogItemType type ;
Handle itemH ;
Rect box ;
GetDialogItem ( dlg , 1 , & type , & itemH , & box ) ;
InsetRect ( & box , - 4 , - 4 ) ;
PenSize ( 3 , 3 ) ;
FrameRoundRect ( & box , 16 , 16 ) ;
}
2020-08-06 01:59:49 +01:00
void display_about_box ( void )
{
DialogRef about = GetNewDialog ( DLOG_ABOUT , 0 , ( WindowPtr ) - 1 ) ;
UpdateDialog ( about , about - > visRgn ) ;
while ( ! Button ( ) ) YieldToAnyThread ( ) ;
while ( Button ( ) ) YieldToAnyThread ( ) ;
FlushEvents ( everyEvent , 0 ) ;
DisposeWindow ( about ) ;
}
2020-08-20 20:31:26 +01:00
void ssh_paste ( void )
{
// GetScrap requires a handle, not a raw buffer
// it will increase the size of the handle if needed
Handle buf = NewHandle ( 256 ) ;
int r = GetScrap ( buf , ' TEXT ' , 0 ) ;
if ( r > 0 )
{
ssh_write ( * buf , r ) ;
}
DisposeHandle ( buf ) ;
}
2021-01-23 00:47:48 +00:00
void ssh_copy ( void )
{
char * selection = NULL ;
size_t len = get_selection ( & selection ) ;
if ( selection = = NULL | | len = = 0 ) return ;
2021-01-23 17:33:40 +00:00
OSErr e = ZeroScrap ( ) ;
if ( e ! = noErr ) printf_i ( " Failed to ZeroScrap! " ) ;
2021-01-23 00:47:48 +00:00
e = PutScrap ( len , ' TEXT ' , selection ) ;
if ( e ! = noErr ) printf_i ( " Failed to PutScrap! " ) ;
}
2020-10-04 17:19:49 +01:00
int qd_color_to_menu_item ( int qd_color )
{
switch ( qd_color )
{
case blackColor : return 1 ;
case redColor : return 2 ;
case greenColor : return 3 ;
case yellowColor : return 4 ;
case blueColor : return 5 ;
case magentaColor : return 6 ;
case cyanColor : return 7 ;
case whiteColor : return 8 ;
default : return 1 ;
}
}
int menu_item_to_qd_color ( int menu_item )
{
switch ( menu_item )
{
case 1 : return blackColor ;
case 2 : return redColor ;
case 3 : return greenColor ;
case 4 : return yellowColor ;
case 5 : return blueColor ;
case 6 : return magentaColor ;
case 7 : return cyanColor ;
case 8 : return whiteColor ;
default : return 1 ;
}
}
void preferences_window ( void )
{
// modal dialog setup
TEInit ( ) ;
InitDialogs ( NULL ) ;
DialogPtr dlg = GetNewDialog ( DLOG_PREFERENCES , 0 , ( WindowPtr ) - 1 ) ;
InitCursor ( ) ;
// select all text in dialog item 4 (the hostname one)
//SelectDialogItemText(dlg, 4, 0, 32767);
DialogItemType type ;
Handle itemH ;
Rect box ;
// draw default button indicator around the connect button
GetDialogItem ( dlg , 2 , & type , & itemH , & box ) ;
SetDialogItem ( dlg , 2 , type , ( Handle ) NewUserItemUPP ( & ButtonFrameProc ) , & box ) ;
// get the handles for each menu, set to current prefs value
ControlHandle term_type_menu ;
GetDialogItem ( dlg , 6 , & type , & itemH , & box ) ;
term_type_menu = ( ControlHandle ) itemH ;
SetControlValue ( term_type_menu , prefs . display_mode + 1 ) ;
ControlHandle bg_color_menu ;
GetDialogItem ( dlg , 7 , & type , & itemH , & box ) ;
bg_color_menu = ( ControlHandle ) itemH ;
SetControlValue ( bg_color_menu , qd_color_to_menu_item ( prefs . bg_color ) ) ;
ControlHandle fg_color_menu ;
GetDialogItem ( dlg , 8 , & type , & itemH , & box ) ;
fg_color_menu = ( ControlHandle ) itemH ;
SetControlValue ( fg_color_menu , qd_color_to_menu_item ( prefs . fg_color ) ) ;
// let the modalmanager do everything
// stop on ok or cancel
short item ;
do {
ModalDialog ( NULL , & item ) ;
2021-01-11 22:21:47 +00:00
} while ( item ! = 1 & & item ! = 9 ) ;
2020-10-04 17:19:49 +01:00
// save if OK'd
if ( item = = 1 )
{
// read menu values into prefs
prefs . display_mode = GetControlValue ( term_type_menu ) - 1 ;
// TODO: don't save colors, make it take effect immediately
int save_bg = prefs . bg_color ;
int save_fg = prefs . fg_color ;
prefs . bg_color = menu_item_to_qd_color ( GetControlValue ( bg_color_menu ) ) ;
prefs . fg_color = menu_item_to_qd_color ( GetControlValue ( fg_color_menu ) ) ;
save_prefs ( ) ;
prefs . bg_color = save_bg ;
prefs . fg_color = save_fg ;
// TODO: make this actually fix all colors in vterm
update_console_colors ( ) ;
}
// clean it up
DisposeDialog ( dlg ) ;
FlushEvents ( everyEvent , - 1 ) ;
}
2020-09-13 01:16:51 +01:00
// returns 1 if quit selected, else 0
2020-08-06 01:59:49 +01:00
int process_menu_select ( int32_t result )
{
int exit = 0 ;
int16_t menu = ( result & 0xFFFF0000 ) > > 16 ;
int16_t item = ( result & 0x0000FFFF ) ;
Str255 name ;
switch ( menu )
{
case MENU_APPLE :
if ( item = = 1 )
{
display_about_box ( ) ;
}
else
{
GetMenuItemText ( GetMenuHandle ( menu ) , item , name ) ;
OpenDeskAcc ( name ) ;
}
break ;
case MENU_FILE :
2020-10-04 17:19:49 +01:00
if ( item = = 1 ) preferences_window ( ) ;
2020-10-05 19:44:33 +01:00
if ( item = = 3 ) exit = 1 ;
2020-08-06 01:59:49 +01:00
break ;
2020-08-20 20:31:26 +01:00
case MENU_EDIT :
2021-01-23 00:47:48 +00:00
if ( item = = 4 ) ssh_copy ( ) ;
2020-08-20 20:31:26 +01:00
if ( item = = 5 ) ssh_paste ( ) ;
break ;
2020-08-06 01:59:49 +01:00
default :
break ;
}
HiliteMenu ( 0 ) ;
return exit ;
}
2020-09-01 03:53:06 +01:00
void resize_con_window ( WindowPtr eventWin , EventRecord event )
{
2021-01-23 17:45:51 +00:00
clear_selection ( ) ;
2020-09-01 03:53:06 +01:00
// TODO: put this somewhere else
// limits on window size
// top = min vertical
// bottom = max vertical
// left = min horizontal
// right = max horizontal
2020-09-13 01:16:51 +01:00
Rect window_limits = { . top = con . cell_height * 2 + 2 ,
. bottom = con . cell_height * 100 + 2 ,
. left = con . cell_width * 10 + 4 ,
. right = con . cell_width * 200 + 4 } ;
2020-09-01 03:53:06 +01:00
long growResult = GrowWindow ( eventWin , event . where , & window_limits ) ;
2020-09-01 17:11:04 +01:00
2020-09-01 03:53:06 +01:00
if ( growResult ! = 0 )
{
int height = growResult > > 16 ;
int width = growResult & 0xFFFF ;
// 'snap' to a size that won't have extra pixels not in a cell
int next_height = height - ( ( height - 2 ) % con . cell_height ) ;
int next_width = width - ( ( width - 4 ) % con . cell_width ) ;
SizeWindow ( eventWin , next_width , next_height , true ) ;
2020-09-01 17:11:04 +01:00
EraseRect ( & ( con . win - > portRect ) ) ;
InvalRect ( & ( con . win - > portRect ) ) ;
2020-09-01 03:53:06 +01:00
con . size_x = ( next_width - 4 ) / con . cell_width ;
con . size_y = ( next_height - 2 ) / con . cell_height ;
vterm_set_size ( con . vterm , con . size_y , con . size_x ) ;
libssh2_channel_request_pty_size ( ssh_con . channel , con . size_x , con . size_y ) ;
}
}
2020-10-11 00:46:50 +01:00
int handle_keypress ( EventRecord * event )
{
unsigned char c = event - > message & charCodeMask ;
2020-12-12 22:55:52 +00:00
// if we have a key and command, and it's not autorepeating
if ( c & & event - > what ! = autoKey & & event - > modifiers & cmdKey )
2020-10-11 00:46:50 +01:00
{
switch ( c )
{
case ' q ' :
return 1 ;
break ;
case ' v ' :
ssh_paste ( ) ;
break ;
2021-01-23 00:47:48 +00:00
case ' c ' :
ssh_copy ( ) ;
break ;
2020-10-11 00:46:50 +01:00
default :
break ;
}
}
2020-12-12 22:55:52 +00:00
// if we have a key and control, and it's not autorepeating
else if ( c & & event - > what ! = autoKey & & event - > modifiers & controlKey )
{
// check if we know a control code translation for that key
uint8_t control_code = virtual_keycode_to_control_ascii [ ( ( event - > message & keyCodeMask ) > > 8 ) ] ;
if ( control_code ! = 255 )
{
ssh_con . send_buffer [ 0 ] = control_code ;
ssh_write ( ssh_con . send_buffer , 1 ) ;
}
}
2020-10-11 00:46:50 +01:00
// if it's just a normal key
2020-12-12 22:55:52 +00:00
// note that this is after translation, e.g. shift-f -> 'F'
2020-10-11 00:46:50 +01:00
else if ( c )
{
if ( key_to_vterm [ c ] ! = VTERM_KEY_NONE )
{
vterm_keyboard_key ( con . vterm , key_to_vterm [ c ] , VTERM_MOD_NONE ) ;
}
else
{
ssh_con . send_buffer [ 0 ] = c ;
ssh_write ( ssh_con . send_buffer , 1 ) ;
}
}
return 0 ;
}
2020-07-20 05:14:27 +01:00
void event_loop ( void )
{
int exit_event_loop = 0 ;
EventRecord event ;
WindowPtr eventWin ;
2020-12-22 00:38:12 +00:00
Point local_mouse_position ;
2020-07-20 05:14:27 +01:00
// maximum length of time to sleep (in ticks)
2020-09-13 01:16:51 +01:00
// GetCaretTime gets the number of ticks between system caret on/off time
2020-07-24 19:47:07 +01:00
long int sleep_time = GetCaretTime ( ) / 4 ;
2020-07-20 05:14:27 +01:00
do
{
// wait to get a GUI event
while ( ! WaitNextEvent ( everyEvent , & event , sleep_time , NULL ) )
{
// timed out without any GUI events
2020-08-22 02:29:34 +01:00
// toggle our cursor if needed
check_cursor ( ) ;
// then let any other threads run before we wait for events again
2020-07-17 02:32:31 +01:00
YieldToAnyThread ( ) ;
}
2020-08-22 02:29:34 +01:00
// might need to toggle our cursor even if we got an event
check_cursor ( ) ;
2020-09-13 01:16:51 +01:00
// handle any GUI events
2020-10-10 19:46:07 +01:00
switch ( event . what )
2020-07-17 02:32:31 +01:00
{
case updateEvt :
eventWin = ( WindowPtr ) event . message ;
BeginUpdate ( eventWin ) ;
draw_screen ( & ( eventWin - > portRect ) ) ;
EndUpdate ( eventWin ) ;
break ;
case keyDown :
case autoKey : // autokey means we're repeating a held down key event
2020-10-11 00:46:50 +01:00
exit_event_loop = handle_keypress ( & event ) ;
2020-09-06 19:34:42 +01:00
break ;
2020-07-17 02:32:31 +01:00
case mouseDown :
switch ( FindWindow ( event . where , & eventWin ) )
{
case inDrag :
// allow the window to be dragged anywhere on any monitor
// hmmm... which of these is better???
DragWindow ( eventWin , event . where , & ( * ( GetGrayRgn ( ) ) ) - > rgnBBox ) ;
// DragWindow(eventWin, event.where, &(*qd.thePort->visRgn)->rgnBBox);
break ;
case inGrow :
2020-09-01 03:53:06 +01:00
resize_con_window ( eventWin , event ) ;
2020-07-17 02:32:31 +01:00
break ;
case inGoAway :
{
if ( TrackGoAway ( eventWin , event . where ) )
exit_event_loop = 1 ;
}
break ;
case inMenuBar :
2020-08-06 01:59:49 +01:00
exit_event_loop = process_menu_select ( MenuSelect ( event . where ) ) ;
2020-07-17 02:32:31 +01:00
break ;
case inSysWindow :
// is this system6 relevant only???
SystemClick ( & event , eventWin ) ;
break ;
case inContent :
2020-12-22 00:38:12 +00:00
GetMouse ( & local_mouse_position ) ;
mouse_click ( local_mouse_position , true ) ;
2020-07-17 02:32:31 +01:00
break ;
}
break ;
2020-12-22 00:38:12 +00:00
case mouseUp :
2021-01-23 01:37:18 +00:00
// only tell the console to lift the mouse if we clicked through it
if ( con . mouse_state )
{
GetMouse ( & local_mouse_position ) ;
mouse_click ( local_mouse_position , false ) ;
}
2020-12-22 00:38:12 +00:00
break ;
2020-07-17 02:32:31 +01:00
}
2020-10-10 19:46:07 +01:00
YieldToAnyThread ( ) ;
2020-07-17 02:32:31 +01:00
} while ( ! exit_event_loop ) ;
}
2020-09-06 01:04:55 +01:00
// from the ATS password sample code
pascal Boolean TwoItemFilter ( DialogPtr dlog , EventRecord * event , short * itemHit )
{
DialogPtr evtDlog ;
short selStart , selEnd ;
2020-09-13 01:16:51 +01:00
long unsigned ticks ;
2020-09-06 01:04:55 +01:00
Handle itemH ;
DialogItemType type ;
Rect box ;
// TODO: this should be declared somewhere? include it?
int kVisualDelay = 8 ;
if ( event - > what = = keyDown | | event - > what = = autoKey )
{
char c = event - > message & charCodeMask ;
switch ( c )
{
case kEnterCharCode : // select the ok button
case kReturnCharCode : // we have to manually blink it...
case kLineFeedCharCode :
GetDialogItem ( dlog , 1 , & type , & itemH , & box ) ;
HiliteControl ( ( ControlHandle ) ( itemH ) , kControlButtonPart ) ;
Delay ( kVisualDelay , & ticks ) ;
HiliteControl ( ( ControlHandle ) ( itemH ) , 1 ) ;
* itemHit = 1 ;
return true ;
case kTabCharCode : // cancel out tab events
event - > what = nullEvent ;
return false ;
case kEscapeCharCode : // hit cancel on esc or cmd-period
case ' . ' :
if ( ( event - > modifiers & cmdKey ) | | c = = kEscapeCharCode )
{
GetDialogItem ( dlog , 6 , & type , & itemH , & box ) ;
HiliteControl ( ( ControlHandle ) ( itemH ) , kControlButtonPart ) ;
Delay ( kVisualDelay , & ticks ) ;
HiliteControl ( ( ControlHandle ) ( itemH ) , 6 ) ;
* itemHit = 6 ;
return true ;
}
2020-12-27 21:37:07 +00:00
__attribute__ ( ( fallthrough ) ) ; // fall through in case of a plain '.'
2020-09-06 01:04:55 +01:00
default : // TODO: this is dumb and assumes everything else is a valid text character
selStart = ( * * ( ( DialogPeek ) dlog ) - > textH ) . selStart ; // Get the selection in the visible item
selEnd = ( * * ( ( DialogPeek ) dlog ) - > textH ) . selEnd ;
SelectDialogItemText ( dlog , 5 , selStart , selEnd ) ; // Select text in invisible item
DialogSelect ( event , & evtDlog , itemHit ) ; // Input key
SelectDialogItemText ( dlog , 4 , selStart , selEnd ) ; // Select same area in visible item
if ( ( event - > message & charCodeMask ) ! = kBackspaceCharCode ) // If it's not a backspace (backspace is the only key that can affect both the text and the selection- thus we need to process it in both fields, but not change it for the hidden field.
event - > message = 0xa5 ; // Replace with character to use (the bullet)
DialogSelect ( event , & evtDlog , itemHit ) ; // Put in fake character
return true ;
2020-11-10 22:42:14 +00:00
case kLeftArrowCharCode :
case kRightArrowCharCode :
case kUpArrowCharCode :
case kDownArrowCharCode :
case kHomeCharCode :
case kEndCharCode :
return false ; // don't handle them
2020-09-06 01:04:55 +01:00
}
}
return false ; // pass on other (non-keypress) events
}
// from the ATS password sample code
// 1 for ok, 0 for cancel
2020-09-16 02:17:02 +01:00
int password_dialog ( int dialog_resource )
2020-07-17 02:32:31 +01:00
{
2020-09-13 01:16:51 +01:00
int ret = 1 ;
2021-01-09 22:22:40 +00:00
2020-09-06 01:04:55 +01:00
DialogPtr dlog ;
Handle itemH ;
short item ;
Rect box ;
DialogItemType type ;
2020-09-16 02:17:02 +01:00
dlog = GetNewDialog ( dialog_resource , 0 , ( WindowPtr ) - 1 ) ;
2020-09-06 01:04:55 +01:00
// draw default button indicator around the connect button
GetDialogItem ( dlog , 2 , & type , & itemH , & box ) ;
SetDialogItem ( dlog , 2 , type , ( Handle ) NewUserItemUPP ( & ButtonFrameProc ) , & box ) ;
do {
ModalDialog ( NewModalFilterUPP ( TwoItemFilter ) , & item ) ;
} while ( item ! = 1 & & item ! = 6 ) ; // until OK or cancel
2020-09-13 01:16:51 +01:00
if ( 6 = = item ) ret = 0 ;
2020-07-17 02:32:31 +01:00
2020-09-06 01:04:55 +01:00
// read out of the hidden text box
GetDialogItem ( dlog , 5 , & type , & itemH , & box ) ;
2020-10-04 03:30:48 +01:00
GetDialogItemText ( itemH , ( unsigned char * ) prefs . password ) ;
prefs . auth_type = USE_PASSWORD ;
2020-09-06 01:04:55 +01:00
DisposeDialog ( dlog ) ;
2020-09-13 01:16:51 +01:00
return ret ;
2020-09-06 01:04:55 +01:00
}
2020-09-16 02:17:02 +01:00
// derived from More Files sample code
OSErr
FSpPathFromLocation (
FSSpec * spec , /* The location we want a path for. */
int * length , /* Length of the resulting path. */
Handle * fullPath ) /* Handle to path. */
{
OSErr err ;
FSSpec tempSpec ;
CInfoPBRec pb ;
* fullPath = NULL ;
/*
* Make a copy of the input FSSpec that can be modified .
*/
BlockMoveData ( spec , & tempSpec , sizeof ( FSSpec ) ) ;
if ( tempSpec . parID = = fsRtParID ) {
/*
* The object is a volume . Add a colon to make it a full
* pathname . Allocate a handle for it and we are done .
*/
tempSpec . name [ 0 ] + = 2 ;
tempSpec . name [ tempSpec . name [ 0 ] - 1 ] = ' : ' ;
tempSpec . name [ tempSpec . name [ 0 ] ] = ' \0 ' ;
err = PtrToHand ( & tempSpec . name [ 1 ] , fullPath , tempSpec . name [ 0 ] ) ;
} else {
/*
* The object isn ' t a volume . Is the object a file or a directory ?
*/
pb . dirInfo . ioNamePtr = tempSpec . name ;
pb . dirInfo . ioVRefNum = tempSpec . vRefNum ;
pb . dirInfo . ioDrDirID = tempSpec . parID ;
pb . dirInfo . ioFDirIndex = 0 ;
err = PBGetCatInfoSync ( & pb ) ;
if ( ( err = = noErr ) | | ( err = = fnfErr ) ) {
/*
* If the file doesn ' t currently exist we start over . If the
* directory exists everything will work just fine . Otherwise we
* will just fail later . If the object is a directory , append a
* colon so full pathname ends with colon .
*/
if ( err = = fnfErr ) {
BlockMoveData ( spec , & tempSpec , sizeof ( FSSpec ) ) ;
} else if ( ( pb . hFileInfo . ioFlAttrib & ioDirMask ) ! = 0 ) {
tempSpec . name [ 0 ] + = 1 ;
tempSpec . name [ tempSpec . name [ 0 ] ] = ' : ' ;
}
/*
* Create a new Handle for the object - make it a C string
*/
tempSpec . name [ 0 ] + = 1 ;
tempSpec . name [ tempSpec . name [ 0 ] ] = ' \0 ' ;
err = PtrToHand ( & tempSpec . name [ 1 ] , fullPath , tempSpec . name [ 0 ] ) ;
if ( err = = noErr ) {
/*
* Get the ancestor directory names - loop until we have an
* error or find the root directory .
*/
pb . dirInfo . ioNamePtr = tempSpec . name ;
pb . dirInfo . ioVRefNum = tempSpec . vRefNum ;
pb . dirInfo . ioDrParID = tempSpec . parID ;
do {
pb . dirInfo . ioFDirIndex = - 1 ;
pb . dirInfo . ioDrDirID = pb . dirInfo . ioDrParID ;
err = PBGetCatInfoSync ( & pb ) ;
if ( err = = noErr ) {
/*
* Append colon to directory name and add
* directory name to beginning of fullPath
*/
+ + tempSpec . name [ 0 ] ;
tempSpec . name [ tempSpec . name [ 0 ] ] = ' : ' ;
( void ) Munger ( * fullPath , 0 , NULL , 0 , & tempSpec . name [ 1 ] ,
tempSpec . name [ 0 ] ) ;
err = MemError ( ) ;
}
} while ( ( err = = noErr ) & & ( pb . dirInfo . ioDrDirID ! = fsRtDirID ) ) ;
}
}
}
/*
* On error Dispose the handle , set it to NULL & return the err .
* Otherwise , set the length & return .
*/
if ( err = = noErr ) {
* length = GetHandleSize ( * fullPath ) - 1 ;
} else {
if ( * fullPath ! = NULL ) {
DisposeHandle ( * fullPath ) ;
}
* fullPath = NULL ;
* length = 0 ;
}
return err ;
}
2020-09-14 23:51:29 +01:00
int key_dialog ( void )
{
2020-09-16 02:17:02 +01:00
Handle full_path = NULL ;
int path_length = 0 ;
2020-10-04 03:30:48 +01:00
// if we don't have a saved pubkey path, ask for one
if ( prefs . pubkey_path = = NULL | | prefs . pubkey_path [ 0 ] = = ' \0 ' )
{
NoteAlert ( ALRT_PUBKEY , nil ) ;
StandardFileReply pubkey ;
StandardGetFile ( NULL , 0 , NULL , & pubkey ) ;
FSpPathFromLocation ( & pubkey . sfFile , & path_length , & full_path ) ;
prefs . pubkey_path = malloc ( path_length + 1 ) ;
strncpy ( prefs . pubkey_path , ( char * ) ( * full_path ) , path_length + 1 ) ;
DisposeHandle ( full_path ) ;
// if the user hit cancel, 0
if ( ! pubkey . sfGood ) return 0 ;
}
2020-09-16 02:17:02 +01:00
path_length = 0 ;
full_path = NULL ;
2020-10-04 03:30:48 +01:00
// if we don't have a saved privkey path, ask for one
if ( prefs . privkey_path = = NULL | | prefs . privkey_path [ 0 ] = = ' \0 ' )
{
NoteAlert ( ALRT_PRIVKEY , nil ) ;
StandardFileReply privkey ;
StandardGetFile ( NULL , 0 , NULL , & privkey ) ;
FSpPathFromLocation ( & privkey . sfFile , & path_length , & full_path ) ;
prefs . privkey_path = malloc ( path_length + 1 ) ;
strncpy ( prefs . privkey_path , ( char * ) ( * full_path ) , path_length + 1 ) ;
DisposeHandle ( full_path ) ;
// if the user hit cancel, 0
if ( ! privkey . sfGood ) return 0 ;
}
2020-09-16 02:17:02 +01:00
// get the key decryption password
if ( ! password_dialog ( DLOG_KEY_PASSWORD ) ) return 0 ;
2020-10-04 03:30:48 +01:00
prefs . auth_type = USE_KEY ;
2020-09-16 02:17:02 +01:00
return 1 ;
2020-09-14 23:51:29 +01:00
}
2020-10-04 03:30:48 +01:00
int intro_dialog ( void )
2020-09-06 01:04:55 +01:00
{
2020-07-17 02:32:31 +01:00
// modal dialog setup
TEInit ( ) ;
InitDialogs ( NULL ) ;
2020-08-06 01:59:49 +01:00
DialogPtr dlg = GetNewDialog ( DLOG_CONNECT , 0 , ( WindowPtr ) - 1 ) ;
2020-07-17 02:32:31 +01:00
InitCursor ( ) ;
DialogItemType type ;
Handle itemH ;
Rect box ;
// draw default button indicator around the connect button
GetDialogItem ( dlg , 2 , & type , & itemH , & box ) ;
2020-09-13 01:16:51 +01:00
SetDialogItem ( dlg , 2 , type , ( Handle ) NewUserItemUPP ( & ButtonFrameProc ) , & box ) ;
2020-07-17 02:32:31 +01:00
2020-10-04 03:30:48 +01:00
// get the handles for each of the text boxes, and load preference data in
2020-07-17 02:32:31 +01:00
ControlHandle address_text_box ;
GetDialogItem ( dlg , 4 , & type , & itemH , & box ) ;
address_text_box = ( ControlHandle ) itemH ;
2020-10-04 03:30:48 +01:00
SetDialogItemText ( ( Handle ) address_text_box , ( ConstStr255Param ) prefs . hostname ) ;
2020-07-17 02:32:31 +01:00
2020-10-22 02:25:31 +01:00
// select all text in hostname dialog item
SelectDialogItemText ( dlg , 4 , 0 , 32767 ) ;
2020-09-06 20:35:13 +01:00
ControlHandle port_text_box ;
GetDialogItem ( dlg , 5 , & type , & itemH , & box ) ;
port_text_box = ( ControlHandle ) itemH ;
2020-10-04 03:30:48 +01:00
SetDialogItemText ( ( Handle ) port_text_box , ( ConstStr255Param ) prefs . port ) ;
2020-09-06 20:35:13 +01:00
2020-07-17 02:32:31 +01:00
ControlHandle username_text_box ;
2020-09-06 20:35:13 +01:00
GetDialogItem ( dlg , 7 , & type , & itemH , & box ) ;
2020-07-17 02:32:31 +01:00
username_text_box = ( ControlHandle ) itemH ;
2020-10-04 03:30:48 +01:00
SetDialogItemText ( ( Handle ) username_text_box , ( ConstStr255Param ) prefs . username ) ;
2020-07-17 02:32:31 +01:00
2020-09-14 23:51:29 +01:00
ControlHandle password_radio ;
GetDialogItem ( dlg , 9 , & type , & itemH , & box ) ;
password_radio = ( ControlHandle ) itemH ;
2020-10-04 03:30:48 +01:00
SetControlValue ( password_radio , 0 ) ;
2020-09-14 23:51:29 +01:00
ControlHandle key_radio ;
GetDialogItem ( dlg , 10 , & type , & itemH , & box ) ;
key_radio = ( ControlHandle ) itemH ;
SetControlValue ( key_radio , 0 ) ;
2020-10-04 03:30:48 +01:00
// recall last-used connection type
if ( prefs . auth_type = = USE_PASSWORD )
{
SetControlValue ( password_radio , 1 ) ;
}
else
{
SetControlValue ( key_radio , 1 ) ;
}
2020-07-17 02:32:31 +01:00
// let the modalmanager do everything
// stop when the connect button is hit
short item ;
do {
ModalDialog ( NULL , & item ) ;
2020-09-14 23:51:29 +01:00
if ( item = = 9 )
{
SetControlValue ( key_radio , 0 ) ;
SetControlValue ( password_radio , 1 ) ;
}
else if ( item = = 10 )
{
SetControlValue ( key_radio , 1 ) ;
SetControlValue ( password_radio , 0 ) ;
}
2020-09-06 20:35:13 +01:00
} while ( item ! = 1 & & item ! = 8 ) ;
2020-07-17 02:32:31 +01:00
// copy the text out of the boxes
2020-10-04 03:30:48 +01:00
GetDialogItemText ( ( Handle ) address_text_box , ( unsigned char * ) prefs . hostname ) ;
GetDialogItemText ( ( Handle ) username_text_box , ( unsigned char * ) prefs . username ) ;
GetDialogItemText ( ( Handle ) port_text_box , ( unsigned char * ) prefs . hostname + prefs . hostname [ 0 ] + 1 ) ;
prefs . hostname [ prefs . hostname [ 0 ] + 1 ] = ' : ' ;
2020-07-17 02:32:31 +01:00
2020-10-04 03:30:48 +01:00
char * port_start = prefs . hostname + prefs . hostname [ 0 ] + 2 ;
prefs . port [ 0 ] = strlen ( port_start ) ;
strncpy ( prefs . port + 1 , port_start , 255 ) ;
2020-09-06 20:35:13 +01:00
2020-09-15 00:55:00 +01:00
int use_password = GetControlValue ( password_radio ) ;
2020-07-17 02:32:31 +01:00
// clean it up
2020-09-06 01:04:55 +01:00
DisposeDialog ( dlg ) ;
2020-07-17 02:32:31 +01:00
FlushEvents ( everyEvent , - 1 ) ;
2020-07-20 20:30:56 +01:00
2020-09-15 01:01:19 +01:00
// if we hit cancel, 0
if ( item = = 8 ) return 0 ;
2020-09-15 00:55:00 +01:00
if ( use_password )
2020-09-14 23:51:29 +01:00
{
2020-09-16 02:17:02 +01:00
return password_dialog ( DLOG_PASSWORD ) ;
2020-09-14 23:51:29 +01:00
}
else
{
return key_dialog ( ) ;
}
2020-07-17 02:32:31 +01:00
}
2020-07-24 00:46:29 +01:00
int safety_checks ( void )
{
2020-08-29 03:14:43 +01:00
OSStatus err = noErr ;
2020-07-24 00:46:29 +01:00
// check for thread manager
2020-07-25 23:57:03 +01:00
long int thread_manager_gestalt = 0 ;
2020-07-24 00:46:29 +01:00
err = Gestalt ( gestaltThreadMgrAttr , & thread_manager_gestalt ) ;
// bit one is prescence of thread manager
if ( err ! = noErr | | ( thread_manager_gestalt & ( 1 < < gestaltThreadMgrPresent ) ) = = 0 )
{
2020-07-24 00:51:33 +01:00
StopAlert ( ALRT_TM , nil ) ;
2020-08-29 03:14:43 +01:00
printf_i ( " Thread Manager not available! \r \n " ) ;
2020-07-24 00:46:29 +01:00
return 0 ;
}
// check for Open Transport
// for some reason, the docs say you shouldn't check for OT via the gestalt
// in an application, and should just try to init, but checking seems more
// user-friendly, so...
long int open_transport_any_version = 0 ;
long int open_transport_new_version = 0 ;
err = Gestalt ( gestaltOpenTpt , & open_transport_any_version ) ;
if ( err ! = noErr )
{
2020-08-29 03:14:43 +01:00
printf_i ( " Failed to check for Open Transport! \r \n " ) ;
2020-07-24 00:46:29 +01:00
return 0 ;
}
err = Gestalt ( gestaltOpenTptVersions , & open_transport_new_version ) ;
if ( err ! = noErr )
{
2020-08-29 03:14:43 +01:00
printf_i ( " Failed to check for Open Transport! \r \n " ) ;
2020-07-24 00:46:29 +01:00
return 0 ;
}
if ( open_transport_any_version = = 0 & & open_transport_new_version = = 0 )
{
2020-08-29 03:14:43 +01:00
printf_i ( " Open Transport required but not found! \r \n " ) ;
2020-07-24 00:46:29 +01:00
StopAlert ( ALRT_OT , nil ) ;
return 0 ;
}
if ( open_transport_any_version ! = 0 & & open_transport_new_version = = 0 )
{
2020-07-26 15:13:51 +01:00
printf_i ( " Early version of Open Transport detected! " ) ;
2020-08-29 03:14:43 +01:00
printf_i ( " Attempting to continue anyway. \r \n " ) ;
2020-07-24 00:46:29 +01:00
}
2021-01-09 22:22:40 +00:00
/*NumVersion* ot_version = (NumVersion*) &open_transport_new_version;
2020-07-24 00:46:29 +01:00
2020-08-29 03:14:43 +01:00
printf_i ( " Detected Open Transport version: %d.%d.%d \r \n " ,
2020-07-26 15:13:51 +01:00
( int ) ot_version - > majorRev ,
( int ) ( ( ot_version - > minorAndBugRev & 0xF0 ) > > 4 ) ,
2021-01-09 22:22:40 +00:00
( int ) ( ot_version - > minorAndBugRev & 0x0F ) ) ; */
2020-07-24 00:46:29 +01:00
2020-07-25 23:57:03 +01:00
// check for CPU type and display warning if it's going to be too slow
long int cpu_type = 0 ;
int cpu_slow = 0 ;
int cpu_bad = 0 ;
err = Gestalt ( gestaltNativeCPUtype , & cpu_type ) ;
if ( err ! = noErr | | cpu_type = = 0 )
{
// earlier than 7.5, need to use other gestalt
err = Gestalt ( gestaltProcessorType , & cpu_type ) ;
if ( err ! = noErr | | cpu_type = = 0 )
{
2020-07-26 15:13:51 +01:00
cpu_slow = 1 ;
2020-08-29 03:14:43 +01:00
printf_i ( " Failed to detect CPU type, continuing anyway. \r \n " ) ;
2020-07-25 23:57:03 +01:00
}
else
{
if ( cpu_type < = gestalt68010 ) cpu_bad = 1 ;
if ( cpu_type < = gestalt68030 ) cpu_slow = 1 ;
}
}
else
{
if ( cpu_type < = gestaltCPU68010 ) cpu_bad = 1 ;
if ( cpu_type < = gestaltCPU68030 ) cpu_slow = 1 ;
}
2020-07-26 15:13:51 +01:00
// if we don't have at least a 68020, stop
2020-07-25 23:57:03 +01:00
if ( cpu_bad )
{
StopAlert ( ALRT_CPU_BAD , nil ) ;
return 0 ;
}
2020-07-26 15:13:51 +01:00
// if we don't have at least a 68040, warn
2020-07-25 23:57:03 +01:00
if ( cpu_slow )
{
CautionAlert ( ALRT_CPU_SLOW , nil ) ;
}
2020-07-24 00:46:29 +01:00
return 1 ;
}
2020-07-20 05:14:27 +01:00
int main ( int argc , char * * argv )
{
2020-07-17 02:32:31 +01:00
OSStatus err = noErr ;
2020-06-19 23:58:20 +01:00
2020-07-17 02:32:31 +01:00
// expands the application heap to its maximum requested size
// supposedly good for performance
// also required before creating threads!
MaxApplZone ( ) ;
2020-06-19 23:58:20 +01:00
2020-08-20 20:31:26 +01:00
// "Call the MoreMasters procedure several times at the beginning of your program"
MoreMasters ( ) ;
MoreMasters ( ) ;
2020-10-04 03:30:48 +01:00
// set default preferences, then load from preferences file if possible
init_prefs ( ) ;
load_prefs ( ) ;
2020-09-20 04:48:41 +01:00
2020-07-17 02:32:31 +01:00
// general gui setup
InitGraf ( & qd . thePort ) ;
InitFonts ( ) ;
InitWindows ( ) ;
InitMenus ( ) ;
2020-06-19 23:58:20 +01:00
2020-08-20 19:53:01 +01:00
void * menu = GetNewMBar ( MBAR_SSHEVEN ) ;
2020-08-06 01:59:49 +01:00
SetMenuBar ( menu ) ;
AppendResMenu ( GetMenuHandle ( MENU_APPLE ) , ' DRVR ' ) ;
2020-08-13 16:21:05 +01:00
2020-08-20 20:31:26 +01:00
// disable stuff in edit menu until we implement it
2020-08-13 16:21:05 +01:00
menu = GetMenuHandle ( MENU_EDIT ) ;
2020-08-20 20:31:26 +01:00
DisableItem ( menu , 1 ) ;
DisableItem ( menu , 3 ) ;
2021-01-23 00:47:48 +00:00
//DisableItem(menu, 4);
2020-08-22 21:23:42 +01:00
DisableItem ( menu , 5 ) ;
2020-08-20 20:31:26 +01:00
DisableItem ( menu , 6 ) ;
DisableItem ( menu , 7 ) ;
DisableItem ( menu , 9 ) ;
2020-08-13 16:21:05 +01:00
2020-08-06 01:59:49 +01:00
DrawMenuBar ( ) ;
2020-07-17 02:32:31 +01:00
console_setup ( ) ;
2020-06-19 23:58:20 +01:00
2020-08-29 03:14:43 +01:00
char * logo = " _____ _____ _ _ \r \n "
" / ____/ ____| | | | \r \n "
" | (___| (___ | |__| | _____ _____ _ __ \r \n "
" \\ ___ \\ \\ ___ \\ | __ |/ _ \\ \\ / / _ \\ '_ \\ \r \n "
" ____) |___) | | | | __/ \\ V / __/ | | | \r \n "
2020-09-06 01:06:01 +01:00
" |_____/_____/|_| |_| \\ ___| \\ _/ \\ ___|_| |_| \r \n " ;
2020-06-19 23:58:20 +01:00
2020-07-26 15:13:51 +01:00
printf_i ( logo ) ;
2021-01-09 22:26:16 +00:00
printf_i ( " by cy384, version " SSHEVEN_VERSION " , running in " ) ;
2020-08-29 03:14:43 +01:00
# if defined(__ppc__)
2021-01-09 22:26:16 +00:00
printf_i ( " PPC mode. \r \n " ) ;
2020-08-29 03:14:43 +01:00
# else
2021-01-09 22:26:16 +00:00
printf_i ( " 68k mode. \r \n " ) ;
2020-08-29 03:14:43 +01:00
# endif
2020-07-17 02:32:31 +01:00
2020-07-20 05:14:27 +01:00
BeginUpdate ( con . win ) ;
draw_screen ( & ( con . win - > portRect ) ) ;
EndUpdate ( con . win ) ;
2020-07-17 02:32:31 +01:00
int ok = 1 ;
2020-06-14 04:33:25 +01:00
2021-01-09 22:22:40 +00:00
ok = safety_checks ( ) ;
2020-07-24 00:46:29 +01:00
2020-07-24 00:51:33 +01:00
BeginUpdate ( con . win ) ;
draw_screen ( & ( con . win - > portRect ) ) ;
EndUpdate ( con . win ) ;
2020-10-04 03:30:48 +01:00
ok = intro_dialog ( ) ;
2020-09-20 04:48:41 +01:00
2020-08-29 03:14:43 +01:00
if ( ! ok ) printf_i ( " Cancelled, not connecting. \r \n " ) ;
2020-07-24 00:46:29 +01:00
if ( ok )
2020-06-16 01:51:36 +01:00
{
2020-07-24 00:46:29 +01:00
if ( InitOpenTransport ( ) ! = noErr )
{
2020-09-13 01:16:51 +01:00
printf_i ( " Failed to initialize Open Transport. \r \n " ) ;
2020-07-24 00:46:29 +01:00
ok = 0 ;
}
2020-06-16 01:51:36 +01:00
}
2020-07-17 02:32:31 +01:00
if ( ok )
{
2020-07-20 23:14:57 +01:00
ssh_con . recv_buffer = OTAllocMem ( SSHEVEN_BUFFER_SIZE ) ;
ssh_con . send_buffer = OTAllocMem ( SSHEVEN_BUFFER_SIZE ) ;
2020-07-17 02:32:31 +01:00
if ( ssh_con . recv_buffer = = NULL | | ssh_con . send_buffer = = NULL )
{
2020-09-13 01:16:51 +01:00
printf_i ( " Failed to allocate network data buffers. \r \n " ) ;
2020-07-17 02:32:31 +01:00
ok = 0 ;
}
}
2020-06-08 17:53:38 +01:00
2020-07-20 05:14:27 +01:00
// create the network read/print thread
read_thread_command = WAIT ;
2020-07-17 02:32:31 +01:00
ThreadID read_thread_id = 0 ;
2020-07-20 05:14:27 +01:00
2020-07-17 02:32:31 +01:00
if ( ok )
{
2020-07-24 00:46:29 +01:00
err = NewThread ( kCooperativeThread , read_thread , NULL , 100000 , kCreateIfNeeded , NULL , & read_thread_id ) ;
2020-06-16 01:51:36 +01:00
2020-07-17 02:32:31 +01:00
if ( err < 0 )
{
2020-09-13 01:16:51 +01:00
printf_i ( " Failed to create network read thread. \r \n " ) ;
2020-07-17 02:32:31 +01:00
ok = 0 ;
}
}
2020-07-20 05:14:27 +01:00
// if we got the thread, tell it to begin operation
if ( ok ) read_thread_command = READ ;
2020-07-17 02:32:31 +01:00
2020-07-20 05:14:27 +01:00
// procede into our main event loop
2020-09-13 01:16:51 +01:00
event_loop ( ) ;
2020-06-08 17:53:38 +01:00
2020-09-13 01:16:51 +01:00
// tell the read thread to finish, then let it run to actually do so
2020-07-20 05:14:27 +01:00
read_thread_command = EXIT ;
2020-09-13 01:16:51 +01:00
2020-09-06 01:05:35 +01:00
if ( read_thread_state ! = UNINTIALIZED )
2020-09-13 01:16:51 +01:00
{
2020-09-06 01:05:35 +01:00
while ( read_thread_state ! = DONE )
2020-09-13 01:16:51 +01:00
{
BeginUpdate ( con . win ) ;
draw_screen ( & ( con . win - > portRect ) ) ;
EndUpdate ( con . win ) ;
2020-09-06 01:05:35 +01:00
YieldToAnyThread ( ) ;
2020-09-13 01:16:51 +01:00
}
2020-09-06 01:05:35 +01:00
}
2020-07-17 02:32:31 +01:00
if ( ssh_con . recv_buffer ! = NULL ) OTFreeMem ( ssh_con . recv_buffer ) ;
if ( ssh_con . send_buffer ! = NULL ) OTFreeMem ( ssh_con . send_buffer ) ;
2020-10-04 03:30:48 +01:00
if ( prefs . pubkey_path ! = NULL & & prefs . pubkey_path [ 0 ] ! = ' \0 ' ) free ( prefs . pubkey_path ) ;
if ( prefs . privkey_path ! = NULL & & prefs . privkey_path [ 0 ] ! = ' \0 ' ) free ( prefs . privkey_path ) ;
2020-09-16 02:17:02 +01:00
2020-08-29 03:14:43 +01:00
if ( con . vterm ! = NULL ) vterm_free ( con . vterm ) ;
2020-09-13 01:16:51 +01:00
if ( ssh_con . endpoint ! = kOTInvalidEndpointRef )
2020-07-24 00:46:29 +01:00
{
err = OTCancelSynchronousCalls ( ssh_con . endpoint , kOTCanceledErr ) ;
CloseOpenTransport ( ) ;
}
2020-07-17 02:32:31 +01:00
}