/********************************************************************
 *  vt100 terminal emulator with xmodem transfer capability
 *		:ts=8
 *
 *	v2.9 ACS - Only strip parity if parity is enabled; handle external xfer
 *		   items in handle_menupick(); new p_interlace value (2).
 *	v2.8a 880331 ACS - Don't ReplyMsg too soon.
 *	v2.7 870825 ACS - Provide handling of the msgs from the
 *			  info/status window.
 *	v2.6 870227 DBW - bug fixes for all the stuff in v2.5
 *	v2.5 870214 DBW - more additions (see readme file)
 *	v2.4 861214 DBW - lots of fixes/additions (see readme file)
 *	v2.3 861101 DBW - minor bug fixes
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860901 ACS - Added Parity and Word Length and support code
 *	     860823 DBW - Integrated and rewrote lots of code
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 *  use <esc> to abort xmodem or kermit transfers
 *
 *  written by Michael Mounier
 *  new version by Dave Wecker
 *******************************************************************/

/*  all includes defines and globals */
#include "vt100.h"

APTR OrigWindowPtr;	/* Used by init.c when opening a new screen */

/**************************************************************/
/* here are all the global definitions that appear in vt100.h */
/**************************************************************/

int	CmdFromRexx = 0;

#if AREXX
struct MsgPort *FromRexxPort = NULL;
char	*HostName;
extern int	RexxReplies;
#endif /* AREXX */

char    *bufr;
int     fd, timeout = FALSE, ttime;
int	multi = FALSE, server;

long    bytes_xferred;
char	MyDir[60];
BPTR	StartLock = 0;
struct	IntuitionBase *IntuitionBase;
struct	GfxBase *GfxBase;
struct	Library *DiskfontBase;

#if AREXX
struct	RxsLib  *RexxSysBase;
#endif	/* AREXX */

struct	TextAttr myattr = {
    (STRPTR)(&(myfontname[0])),
    8,
    0,
    0};
struct	TextFont *myfont = NULL;
struct NewScreen NewScreen = {
   0,0,640,200,1,		/* left, top, width, height, depth */
   0,1,HIRES,			/* DetailPen, BlockPen, ViewModes */
   CUSTOMSCREEN,&myattr,	/* Type, Font */
   (UBYTE *)"VT100",		/* Title */
   NULL,NULL };			/* Gadgets, Bitmap */
struct NewWindow NewWindow = {
   0,0,640,200,			/* left, top, width, height */
   0,1,				/* detailpen, blockpen */
   MENUPICK | CLOSEWINDOW | RAWKEY | ACTIVEWINDOW | INACTIVEWINDOW | MOUSEBUTTONS,
   SMART_REFRESH | ACTIVATE | BORDERLESS | WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG,
   NULL,NULL,			/* FirstGadget, CheckMark */
   (UBYTE *)NULL,
   NULL,			/* set screen after open screen */
   NULL,			/* bitmap */
   640, 200, 640, 200,		/* minw, minh, maxw, maxh */
   CUSTOMSCREEN			/* Type */
   };

/*   LeftEdge, TopEdge, Width and Height are in CHARACTERS.  They are
** converted to pixels in OpenReqWindow() in window.c based on the current
** font's characteristics. */
struct NewWindow NewReqWindow = {
   0, 1, 54, 4,			/* left (set in window.c), top, width, height */
   0, 1,			/* detailpen, blockpen */
	/* IDCMP Flags... */
   CLOSEWINDOW | ACTIVEWINDOW | REQCLEAR | REQSET | NEWSIZE,
	/* Flags... */
   SMART_REFRESH | NOCAREREFRESH | ACTIVATE | WINDOWSIZING | SIZEBRIGHT |
   WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG,

   NULL,			/* First gadget */
   NULL,			/* CheckMark */
   (UBYTE *)"VT100 Info & Xfer Status",	/* Title */
   NULL,			/* set screen after open screen */
   NULL,			/* bitmap */
   ((5*8)+4+18), ((1*8)+11+2), 640, 200,	/* minw, minh, maxw, maxh */
   CUSTOMSCREEN			/* Type */
   };
struct IntuiText MyTitle = {
    0,1,JAM2,26,0,		/* front pen, back pen, mode, left, top */
    &myattr,			/* font */
    (UBYTE *)VERSION,		/* title */
    NULL};			/* next text */

struct Screen *myscreen = NULL;		/* ptr to applications screen */
struct Window *mywindow = NULL;		/* ptr to applications window */
struct Window *reqwindow = NULL;	/* ptr to requester's window */
struct ViewPort *myviewport;
struct RastPort *myrastport;
struct IntuiMessage *NewMessage;	/* msg structure for GetMsg() */
struct Preferences  *Prefs;		/* preferences from GetPrefs() */

/**** String requester support ******/
/*   The Top, Left, Width and Height are all in CHARACTERS.  This is converted
** to pixels in OpenReqWindow() in window.c.  Things which contain strings of
** known length are initialized from their string length */

char    InpBuf[MAXGADSTR],UndoBuf[MAXGADSTR],Prompt[MAXGADSTR];
struct IntuiText donetxt = {
    1,0,JAM2,0,0,	/* front pen, back pen, mode, left, top */
    &myattr,		/* font */
    (UBYTE *)"DONE",	/* question to ask */
    NULL};		/* next text */
struct Gadget mydonegad = {
    &mystrgad,36,0,0,1,	/* next,left,top,width,height */
    GADGHCOMP|REQGADGET,	/* flags */
    RELVERIFY|ENDGADGET,	/* activation */
    BOOLGADGET,			/* gadget type */
    NULL,NULL,&donetxt,		/* gad render, sel render, gad text */
    0L,NULL,2,NULL};		/* mutual exclude, special, ID, user data */
struct	StringInfo mystrinfo = {
    (UBYTE *)InpBuf,
    (UBYTE *)UndoBuf,
    0,MAXGADSTR-1,0,0,0,0,	/* initial, max, disp, undo, #chrs, dsp chrs */
    0,0,NULL,0L,NULL};	/* left,top,layer,longint,keymap */
struct Gadget mystrgad = {
    NULL,1,1,40,1,	/* next,left,top,width,height */
    GADGHCOMP|REQGADGET,/* flags */
    ENDGADGET,STRGADGET,/* activation, type */
    NULL,NULL,NULL,	/* gad render, sel render, gad text */
    0L,			/* mutual exclude */
    (APTR)&mystrinfo,	/* special info */
    1,NULL};		/* gadget ID, user data */
struct IntuiText mystrtxt= {
    0,1,JAM2,1,0,	/* front pen, back pen, mode, left, top */
    &myattr,		/* font */
    (UBYTE *)Prompt,	/* question to ask */
    NULL};		/* next text */
struct Requester myrequest = {
    NULL,0,1,42,2,	/* older requester, left, top, width, height */
    0,0,&mydonegad,	/* relleft reltop, gadgets */
    NULL,		/* border */
    &mystrtxt,		/* text */
    NULL,1,NULL,	/* flags, back fill pen, layer */
    {0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0},	/* pad1 */
    NULL,NULL,		/* image bit map, rquest window */
    {0,0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,0} /* pad2 */
    };

int numreqs = 0;		/* number of outstanding requestors */
int reqwinup = 0;		/* Requester window is NOT displayed */
extern int reqmaxx, reqmaxy, reqmaxlen;	/* Defined in window.c */
extern void ReqNewSize();	/* New req window size -- window.c */
extern void KillReq();		/* Kill requester window in window.c */	

struct ExternalXfer *(ExtXfer[EXTMAX]);	/* Possible external protocol routines */
int NumExts = 0;			/* Number of ExtXfers */

/***** menu structures *****/
struct MenuItem FileItem[FILEMAX];
struct IntuiText FileText[FILEMAX];
struct MenuItem ModeItem[MODEMAX+EXTMAX];
struct IntuiText ModeText[MODEMAX+EXTMAX];
struct MenuItem CommItem[COMMAX];
struct IntuiText CommText[COMMAX];
struct MenuItem RSItem[RSMAX];
struct IntuiText RSText[RSMAX];
struct MenuItem ParItem[PARMAX];
struct IntuiText ParText[PARMAX];
struct MenuItem XFItem[XFMAX];
struct IntuiText XFText[XFMAX];
struct MenuItem ScriptItem[SCRIPTMAX];
struct IntuiText ScriptText[SCRIPTMAX];
struct MenuItem UtilItem[UTILMAX];
struct IntuiText UtilText[UTILMAX];
struct Menu menu[MAXMENU];
struct IOExtSer *Read_Request;
char *rs_in;
struct IOExtSer *Write_Request;
char rs_out[2];
struct timerequest Timer;
struct MsgPort *Timer_Port = NULL;
struct timerequest Script_Timer;
struct MsgPort *Script_Timer_Port = NULL;
struct IOAudio Audio_Request;
struct MsgPort *Audio_Port = NULL;
UBYTE  *BeepWave;
UBYTE  Audio_AllocMap[4] = { 1, 8, 2, 4 };
int x,y,curmode;
int Xsize	= 0;	/* From struct TextFont for user's font */
int MINX	= 0;
int MAXX	= 632;
int Ysize	= 0;	/* From struct TextFont for user's font */
int MINY	= 14;
int MAXY	= 198;
int BaseLine	= 0;	/* From struct TextFont for user's font */
int top		= 14;
int bot		= 198;
int savx	= 0;
int savy	= 14;
int savmode	= 0;
int nlmode	= 0;
int alt		= 0;
int savalt	= 0;
int a[2]	= { 0, 0 };
int sa[2]	= { 0, 0 };
int  inesc	= -1;
int  inctrl	= -1;
int  private	= 0;
int  badseq	= 0;
int  maxcol	= 79;

/*************************** defaults *******************************/
char	*p_font		= "topaz";	/* Default font. Name must be < 34 chars */
char	*p_device	= SERIALNAME;	/* Default serial device name to use */
int	p_fontsize	= 8;	/* Default vertical font size		*/
int	p_baud		= 1200;	/* baud rate				*/
int	p_shared	= 1;	/* Open serial device in shared mode	*/
int	p_screen	= 0;	/* 0 = WORKBENCH, 1 = CUSTOM		*/
int	p_wbcolors	= 1;	/* 0 = Custom, 1 = Workbench colors	*/
int	p_interlace	= 2;	/* 0 = no interlace, 1 = interlace, 2 = ASIS */
int	p_depth		= 2;	/* number of bit planes (1 or 2)	*/
int	p_foreground	= 0x840;	/* default foreground RGB color */
int	p_background	= 0x000;	/* default background RGB color */
int	p_bold		= 0x000;	/* default BOLD       RGB color */
int	p_cursor	= 0x00d;	/* default Cursor	  RGB color */
int	p_mouse_up	= 0;	/* 1 = send mouse UP events		*/
int	p_mouse_down	= 0;	/* 1 = send mouse DOWN events		*/
int	p_lines		= 0;	/* 0 == use all available (MoreRows)	*/
int	p_mode		= 0;	/* 0 = image, 1 = CRLF (for kermit)	*/
int	p_unit		= 0;	/* unit of serial.device to open	*/
int	p_xproto	= 3;	/* 0=ASCII, 1=Xmodem, 2=XmodemCRC, 3 = Kermit */
int	p_buffer	= 512;	/* read buffer size (>= 512 bytes)	*/
int     p_parity	= 0;	/* 0=none,1=mark,2=space,3=even,4=odd	*/
long	p_break		= 750000;	/* break time (in micro seconds)*/
int	p_volume	= 64;	/* beep volume (0 = DisplayBeep)	*/
int	p_wrap		= 1;	/* 0 = truncate, 1 = wrap long lines	*/
int	p_keyapp	= 0;	/* 0 = numeric, 1 = application keypad	*/
int	p_curapp	= 0;	/* 0 = cursor, 1 = application cursor	*/
int	p_echo		= 0;	/* 0 = full duplex, 1 = half duplex	*/
int	p_bs_del	= 0;	/* 0 = normal, 1 = swap bs and delete	*/
int	p_convert	= 0;	/* 1 = convert filenames to lower case	*/
int	p_autochop	= 1;	/* 1 = enable xmodem autochop		*/
int	p_kmaxpack	= 1000;	/* Max packet size for Kermit xfers	*/
/*	Must be <= 1000.  <= 94 is standard, > 94 requires a kermit capable
**	of long packet support. */
int	p_xbeep		= 1;	/* 1 = beep at end of xfer		*/
char	p_keyscript	= 0x7E;	/* function key script introducer = ~	*/
char	*p_f[11]	= {	/* function key defaults and mouse prefix */
    "\033OP","\033OQ","\033OR","\033OS",
    "f5","f6","f7","f8","f9","f10",
    "\033M" /* Mouse prefix here */ };

char	*p_F[10]     = {	    /* shifted function key defaults	*/
    "F1","F2","F3","F4","F5",
    "F6","F7","F8","F9","F10"};

char myfontname[FONTNAMESIZE];
char mysername[SERNAMESIZE];

/* for script file */
extern char on_string[], wait_string[];
int script_on, script_wait;
int doing_init = 0;

/******************************************************/
/*                   Main Program                     */
/*                                                    */
/*      This is the main body of the program.         */
/******************************************************/

char lookahead[80];
FILE *tranr = NULL;
FILE *trans = NULL;
int capture,send;
char XferredFileName[MAXGADSTR];/* Name of last transferred file	*/
char ScriptFileName[MAXGADSTR];	/* Name of last script file		*/
char DirName[MAXGADSTR];	/* Name of last directory		*/
struct MsgPort *mySerPort;

#if AREXX
int forwarding = 0;		/* Forwarding received data to AREXX	*/
char *ForwardPortName;		/* Port name to which we forward data	*/
struct RexxMsg *FwdMsg;		/* Message to send			*/
char *extension = "vt100";	/* extension of VT100 AREXX macros	*/
#endif /* AREXX */

void
main(argc,argv)
int	argc;
char	**argv;
    {
    ULONG class, waitmask, redo = 0;
    unsigned int code, qual;
    SHORT mouse_x, mouse_y, mouse_qual;
    APTR iaddr;
#if AREXX
    struct RexxMsg *RexxMsg;
    char	fwdchars[256];
#endif /* AREXX */
    int KeepGoing,i,la,dola,actual, len;
    char c,*ptr;
    char ascstr[100];	/* Area for string returned by toasc() */

    XferredFileName[0] = ScriptFileName[0] = '\0';

    ptr = InitDefaults(argc,argv);
    InitDevs();
    InitFileItems();
    InitCommItems();
    InitScriptItems();
    InitUtilItems();
    InitMenu();
    SetMenuStrip(mywindow,&menu[0]);
    PrintIText(mywindow->RPort,&MyTitle,0L,0L);

    MyDir[0]  =	    '\0';
    StartLock = ((struct Process *) FindTask(NULL))->pr_CurrentDir;
    CurrentDir(DupLock(StartLock));
    KeepGoing =	    TRUE;
    capture   =	    FALSE;
    send      =	    FALSE;
    maxcol    =	    MAXX / Xsize;
    la	      =	    0;
    x	      =	    MINX ;
    y	      =	    MINY;
    curmode   =	    FS_NORMAL;
    script_on =     FALSE;
    script_wait=    TRUE;
    on_string[0] = wait_string[0] = '\0';
    SetAPen(mywindow->RPort,1L);
    cursorflip();
    cursorflip();
    emit(12);
    mySerPort = Read_Request->IOSer.io_Message.mn_ReplyPort;
    SendIO((struct IORequest *)Read_Request);

    /* see if we had a startup script */
    if (ptr != NULL) script_start(ptr);

    while( KeepGoing ) {
	/* wait for window message or serial port message */
	cursorflip();
	waitmask = (1L << mySerPort->mp_SigBit) |
		   (1L << mywindow->UserPort->mp_SigBit) |
		   (1L << Script_Timer_Port->mp_SigBit);

	if(reqwinup)
	    waitmask |= (1L << reqwindow->UserPort->mp_SigBit);

#if AREXX
	if(FromRexxPort)
	    waitmask |= (1L << FromRexxPort->mp_SigBit);
#endif /* AREXX */

	if (script_wait)	/* if script ready dont wait here */
	    Wait(waitmask);
	cursorflip();

	/* do ascii file send */
	if (send) {
	    if ((c=getc(trans)) != EOF) {
		if (c == '\n')
		    c = '\r';
		sendchar(c);
	    } else {
		    fclose(trans);
		    InfoMsg1Line("File Sent");
		    send=FALSE;
	    }
	}

	/* see if there are any characters from the host */
	if (CheckIO((struct IORequest *)Read_Request)) {
	    register int fwdndx = 0;
	    struct MsgPort *FwdPort;

	    WaitIO((struct IORequest *)Read_Request);
	    c = rs_in[0] & (p_parity ? 0x7F : 0xFF);
#if AREXX
	    fwdchars[fwdndx++] = c;
#endif
	    doremote(c);
	    if (*on_string || *wait_string)
		chk_script(c);
	    if (capture && c != 10) {
		if (c == 13) c = 10;
		putc(c , tranr);
	    }
	    Read_Request->IOSer.io_Command = SDCMD_QUERY;
	    DoIO((struct IORequest *)Read_Request);
	    Read_Request->IOSer.io_Command = CMD_READ;
	    actual = (int)Read_Request->IOSer.io_Actual;
	    if (actual > 0) {
		if (inesc   <  0 &&
		    inctrl  <  0 &&
		    a[alt]  == 0 &&
		    capture == FALSE)
		    	dola = 1;
		else
			dola = 0;
		Read_Request->IOSer.io_Length =
		Read_Request->IOSer.io_Actual;
		DoIO((struct IORequest *)Read_Request);
		Read_Request->IOSer.io_Length = 1;

		for (i = 0; i < actual; i++) {
		    c=rs_in[i] & (p_parity ? 0x7f : 0xff);
#if AREXX
		    if(fwdndx < 255)
			fwdchars[fwdndx++] = c;
#endif
		    if (*on_string || *wait_string)
			chk_script(c);

		    if (dola == 1) {
			if (c >= ' ' && c <= '~' && la < 80)
			    lookahead[la++] = c;
			else {
			    if (la > 0) {
				emitbatch(la,lookahead);
				la = 0;
			    }
			    doremote(c);
			    dola = 0;
			}
		    } else {
			doremote(c);
			if (inesc   <  0 &&
			    inctrl  <  0 &&
			    a[alt]  == 0 &&
			    capture == FALSE)
				dola = 1;
			if (capture && c != 10) {
			    if (c == 13) c = 10;
			    putc(c , tranr);
			}
		    }
		}

		/* dump anything left in the lookahead buffer */
		if (la > 0) {
		    emitbatch(la,lookahead);
		    la = 0;
		}
	    }
#if AREXX
	    if(forwarding && fwdndx) {
		fwdchars[fwdndx] = '\0';
		Forbid();
		/*   Since forwarding is set we can assume that the AREXX
		** library is available.  This is assured in cmd_fwd() in
		** script.c
		**/
		if( ((FwdPort = FindPort(ForwardPortName)) != NULL)
		 && (FwdMsg = CreateRexxMsg(FromRexxPort, extension, HostName))
		 && (ARG0(FwdMsg) = (STRPTR)CreateArgstring(fwdchars, (LONG)fwdndx)) ) {
		    ARG1(FwdMsg) = (STRPTR)1;
		    FwdMsg->rm_Action = RXCOMM;
		    PutMsg(FwdPort, (struct Message *)FwdMsg);
		    RexxReplies++;
		}
		Permit();
	    }
#endif /* AREXX */
	    SendIO((struct IORequest *)Read_Request);
 	}

	while((NewMessage =
		(struct IntuiMessage *)GetMsg(mywindow->UserPort))
			!= FALSE) {

	    class = NewMessage->Class;
	    code = NewMessage->Code;
	    qual = NewMessage->Qualifier;
	    mouse_x = NewMessage->MouseX;
	    mouse_y = NewMessage->MouseY;
	    if(class == RAWKEY)
		iaddr = *((APTR *)NewMessage->IAddress);
	    else
		ReplyMsg((struct Message *)NewMessage);
	    switch( class ) {
	    case CLOSEWINDOW:
		KeepGoing = FALSE;
		break;

	    case RAWKEY:
		len = toasc(&(ascstr[0]), code,qual, 100, iaddr, 0);
		ReplyMsg((struct Msg *)NewMessage);
		if (p_echo) {
		    ptr = &(ascstr[0]);
		    for(i = 0; i < len; i++)
			doremote(*(ptr++));
		}
		break;

	    case NEWSIZE:
		emit(12);
		break;

	    case MENUPICK:
		while(code != MENUNULL) {
		    struct MenuItem *Item =
			ItemAddress(mywindow->MenuStrip, (long)code);
		    unsigned int newcode =
			(Item ? Item->NextSelect : code);

		    redo |= handle_menupick(class,code);
		    if(code == newcode)
			code = MENUNULL;
		    else
			code = newcode;
		}
		if(redo & REDOFILE)
		    redofile();
		if(redo & REDOCOMM)
		    redocomm();
		if(redo & REDOUTIL)
		    redoutil();
		redo = 0;
		break;

	    case MOUSEBUTTONS:
		if((p_mouse_down && (code == SELECTDOWN))
		|| (p_mouse_up   && (code == SELECTUP)) ) {
		    mouse_qual = 0;
		    if (qual & IEQUALIFIER_CONTROL)
			mouse_qual |= 1;
		    if (qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
			mouse_qual |= 2;
		    if (qual & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
			mouse_qual |= 4;
		    if (qual & (IEQUALIFIER_CAPSLOCK))
			mouse_qual |= 8;
		    mouse_qual |= (code == SELECTDOWN) ? 16 : 32;

		    sendstring(p_f[10]);
		    sendchar(mouse_qual + '@');
		    sendchar(' ' + ((mouse_x - MINX) / 8),10);  /* column */
		    sendchar(' ' + ((mouse_y - MINY + 6 ) / 8),10);/* row */
		}
		break;

	    default:
		PrintIText(mywindow->RPort,&MyTitle,0L,0L);
		break;
	    }   /* end of switch (class) */
	}   /* end of while ( newmessage )*/

	if (!script_wait ||
	   (CheckIO((struct IORequest *)&Script_Timer) &&
	    script_wait == WAIT_TIMER))
		do_script_cmd(NEXTCOMMAND);

	while( reqwinup && ((NewMessage = (struct IntuiMessage *)
				  GetMsg(reqwindow->UserPort)) != FALSE)
	     ) {
	    class = NewMessage->Class;
	    ReplyMsg((struct Msg *)NewMessage);
	    switch( class ) {
	    case REQCLEAR:
		numreqs = 0;
		break;

	    case CLOSEWINDOW:
		KillReq(); /* Kills requester window, set reqwinup = 0 */
		break;

	    case NEWSIZE:
		ReqNewSize(reqwindow->Height, reqwindow->Width);
		break;
	    }   /* end of switch (class) */
	} /* end while reqwinup */
#if AREXX
	while(FromRexxPort && (RexxMsg = (struct RexxMsg *)GetMsg(FromRexxPort)) != NULL) {
	    processrexxmsg(RexxMsg);
	}
#endif /* AREXX */
    }  /* end while ( keepgoing ) */

    /*   It must be time to quit, so we have to clean
    **   up and exit.
    */

    if(!CheckIO((struct IORequest *)Read_Request))
	AbortIO((struct IORequest *)Read_Request);
    Wait (1L <<mySerPort->mp_SigBit);
    WaitIO((struct IORequest *)Read_Request);
    cleanup("",0);

} /* end of main */

/* cleanup code */
void
cleanup(reason, fault)
char *reason;
int fault;
{
    extern struct Device *ConsoleDevice;	/* In init.c */
    extern struct IOStdReq ConReq;		/* In init.c */
    int i;

    switch(fault) {
    case 0:		/* quitting close everything */
	KillReq();	/* Kill the requester and its window */
	ClearMenuStrip( mywindow );
	CloseDevice((struct IORequest *)&Audio_Request);
	UnLock(CurrentDir(StartLock));	/* back to original directory */

    case 8:		/* error opening audio */
	DeletePort(Audio_Port);
	FreeMem(BeepWave,BEEPSIZE);
	CloseDevice((struct IORequest *)&Timer);

    case 7:		/* error opening timer */
	DeletePort(Timer_Port);
	CloseDevice((struct IORequest *)&Script_Timer);
	DeletePort(Script_Timer_Port);

/*	case 6: */	/* error opening write device is unused */
	DeletePort(Write_Request->IOSer.io_Message.mn_ReplyPort);
	FreeMem(Write_Request,(long)sizeof(*Write_Request));
	CloseDevice((struct IORequest *)Read_Request);

    case 5:		/* error opening read device */
	DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort);
	FreeMem(Read_Request,(long)sizeof(*Read_Request));

    case 4:		/* error opening window */
	if (ConsoleDevice != NULL)
	    CloseDevice(&ConReq);
	if (myfont   != NULL)
	    CloseFont( myfont );
	if (mywindow != NULL)
	    CloseWindow( mywindow );
	if (p_screen && myscreen) {
	    struct Process *mproc;

	    mproc = (struct Process *)FindTask(0L);
	    mproc->pr_WindowPtr = OrigWindowPtr;
	    CloseScreen( myscreen );
	}
	for(i = 0; i < NumExts; i++) {
	    struct ExternalXfer *xfer = ExtXfer[i];

	    FreeMem(xfer->dispname, (long)(strlen(xfer->dispname)+1));
	    FreeMem(xfer->downname, (long)(strlen(xfer->downname)+1));
	    FreeMem(xfer->send, (long)(strlen(xfer->send)+1));
	    FreeMem(xfer->receive, (long)(strlen(xfer->receive)+1));
	    FreeMem(xfer, (long)sizeof(struct ExternalXfer));
	}	    

    case 3:		/* error opening screen */
    case 2:		/* error opening graphics library */
	if(GfxBase)
	    CloseLibrary((struct Library *)GfxBase);
	if(DiskfontBase)
	    CloseLibrary(DiskfontBase);
    case 1:		/* error opening intuition */
	if(IntuitionBase)
	    CloseLibrary((struct Library *)IntuitionBase);
    default:
	if (*reason) puts (reason);
    }

#if AREXX
    if(HostName)
	FreeMem(HostName, (LONG)(strlen(HostName)+1));

    if(FromRexxPort) {
	RemPort(FromRexxPort);
	FreePort(FromRexxPort);
	FreeMem(FromRexxPort, (LONG)sizeof(struct MsgPort));
    }
    if(RexxSysBase)
	CloseLibrary((struct Library *)RexxSysBase);
#endif /* AREXX */
    exit(fault);
}

do_capture(file)
char *file;
{
    if (capture == TRUE) {
	capture=FALSE;
	fclose(tranr);
	InfoMsg1Line("End File Capture");
    } else {
	if (file == NULL || *file == '\0') {
	    req("Ascii Capture:",XferredFileName,1);
	} else
	    strcpy(XferredFileName, file);
	if ((tranr=fopen(XferredFileName,"w")) == 0) {
	    capture=FALSE;
	    InfoMsg2Line("Error Opening File:", XferredFileName);
	    return(FALSE);
	}
	capture=TRUE;
    }
    redofile();
}

do_send(file)
char *file;
{
    if (send == TRUE) {
	send=FALSE;
	fclose(trans);
	InfoMsg1Line("File Send Cancelled");
    } else {
	if (file == NULL || *file == '\0') {
	    req("Ascii Send:", XferredFileName, 1);
	} else
	    strcpy(XferredFileName, file);
	if ((trans=fopen(XferredFileName, "r")) == 0) {
	    send=FALSE;
	    InfoMsg2Line("Error Opening File:", XferredFileName);
	    return(FALSE);
	}
	send=TRUE;
    }
}

void setparams()
{
    Read_Request->IOSer.io_Command =
	Write_Request->IOSer.io_Command =
	    SDCMD_SETPARAMS;
    DoIO((struct IORequest *)Read_Request);
    DoIO((struct IORequest *)Write_Request);
    Read_Request->IOSer.io_Command = CMD_READ;
    SendIO((struct IORequest *)Read_Request);
    Write_Request->IOSer.io_Command = CMD_WRITE;
}

void hangup ()
    {
    if(!CheckIO((struct IORequest *)Read_Request))
	AbortIO((struct IORequest *)Read_Request);
    Wait (1L <<mySerPort->mp_SigBit);
    WaitIO((struct IORequest *)Read_Request);
    CloseDevice((struct IORequest *)Read_Request);
    Timer.tr_time.tv_secs=0L;
    Timer.tr_time.tv_micro=750000L;
    DoIO((struct IORequest *)&Timer.tr_node);
    OpenDevice(mysername, (LONG)p_unit, (struct IORequest *)Read_Request, NULL);
    setparams();
}

void redocomm() {
    ClearMenuStrip( mywindow );         /* Remove old menu */
    InitCommItems();                    /* Re-do comm menu   */
    SetMenuStrip(mywindow,&menu[0]);    /* Re-display the menu */
}

void redofile() {
    ClearMenuStrip( mywindow );         /* Remove old menu */
    InitFileItems();                    /* Re-do file menu   */
    SetMenuStrip(mywindow,&menu[0]);    /* Re-display the menu */
}

void setserbaud(baud, redomenu)
int baud;
LONG redomenu;
{
    if(!CheckIO((struct IORequest *)Read_Request))
	AbortIO((struct IORequest *)Read_Request);
    Wait (1L <<mySerPort->mp_SigBit);
    WaitIO((struct IORequest *)Read_Request);
    Write_Request->io_Baud = Read_Request->io_Baud = baud;
    setparams();
    p_baud = baud;
    if (redomenu)
	redocomm();
}

void redoutil() {
    ClearMenuStrip(mywindow);
    InitUtilItems();
    SetMenuStrip(mywindow,&menu[0]);
}

ULONG handle_menupick(class, code)
ULONG class;
unsigned int code;
{
    unsigned int menunum, itemnum, subnum, i;
    int nxfer;
    unsigned long retval = 0;

    if (code == MENUNULL)
	return retval;

    menunum = MENUNUM( code );
    itemnum = ITEMNUM( code );
    subnum  = SUBNUM( code );
    switch( menunum ) {
    case 0:
	switch( itemnum ) {
	case 0:	/* menunum case 0 itemnum case 0 -- Set xfer mode */
	    switch( subnum ) {
	    case 0:	/* Ascii */
	    case 1:	/* Xmodem */
	    case 2:	/* XmodemCRC */
	    case 3:	/* Kermit */
		i = subnum;
		break;
	    default:
		nxfer = MODEMAX + NumExts - 1;
		if(subnum > nxfer)
		    i = MODEMAX-1;
		else
		    i = subnum;
	    }
	    p_xproto = i;
	    retval |= REDOFILE;
	    break;

	case 1:	/* menunum case 0 itemnum case 1 -- Send a file */
	    cmd_sendf(XferredFileName);
	    break;

	case 2:	/* menunum case 0 itemnum case 2 -- Receive a file */
	    cmd_recf(XferredFileName);
	    break;

	case 3:	/* menunum case 0 itemnum case 3 -- Kermit GET */
	    cmd_kg(XferredFileName);
	    break;

	case 4:	/* menunum case 0 itemnum case 4 -- Kermit BYE */
	    saybye();
	    break;
	case 5: /* menunum case 0 itemnum case 5 -- ASCII capture */
	    do_capture(XferredFileName);
	    break;
	} /* End of itemnum switch for menunum case 0 */
	break;

    case 1:		/* menunum case 1 - Comm Setup */
	switch( itemnum ) {
	case 0:	/* Baud */
	    switch( subnum ) {
	    case 0:
		setserbaud(300, FALSE);
		break;

	    case 1:
		setserbaud(1200, FALSE);
		break;

	    case 2:
		setserbaud(2400, FALSE);
		break;

	    case 3:
		setserbaud(4800, FALSE);
		break;

	    case 4:
		setserbaud(9600, FALSE);
		break;
	    } /* End of subnum switch for itemnum 0 of menunum 1 */
	    break;

	case 1:    /* menunum case 1 itemnum 1 -- Set  Parity */
	    p_parity = subnum;
	    break;

	case 2:    /* menunum case 1 itemnum 2 -- set transfer mode */
	    switch(subnum) {
	    case 0:
	    case 1:
		p_mode = subnum;
		break;
	    case 2:
		if (p_convert)
		    p_convert = 0;
		else
		    p_convert = 1;
		break;
	    case 3:
		if(p_autochop)
		    p_autochop = 0;
		else
		    p_autochop = 1;
		break;
	    }
	    retval |= REDOCOMM;
	    break;
	case 3:   /* menunum case 1 itemnum 3 -- Shared */
	    {
		char onoff[4];

		if(p_shared)
		    strcpy(onoff, "off");
		else
		    strcpy(onoff, "on");
		cmd_share(onoff);
	    }
	    break;
	}
	break;	/* End of menunum case 1 */

    case 2:	/* menunum case 2 - Script */
	switch( itemnum ) {
	case 0:			/* Execute macro	*/
	case 1:			/* Abort macro		*/
	    if (!itemnum && !script_on) {
		req("Script file name:", ScriptFileName, 1);
		script_start(ScriptFileName);
	    }
	    if (itemnum && script_on)
		exit_script();
	    break;
	case 2: {			/* AREXX macro		*/

		req("AREXX macro and args:", ScriptFileName, 1);
		cmd_rx(ScriptFileName);
		break;
	    }
	}
	break;

    case 3:	/* menunum case 3 -- Utility */
	switch( itemnum ) {
	case 0:
	    sendbreak();
	    break;

	case 1:	/* menunum case 3 itemnum case 1 -- Hang Up */
	    hangup();
	    break;

	case 2:	/* menunum case 3 itemnum case 2 -- Cd */
	    strcpy(DirName, MyDir);
	    req("Directory:", DirName, 1);
	    set_dir(DirName);
	    break;

	case 3:	/* menunum case 3 itemnum case 3 -- Clear Screen */
	    top = MINY; bot = MAXY; savx = MINX; savy = MINY;
	    curmode = FS_NORMAL; inesc = -1;
	    a[0] = 0; a[1] = 0; sa[0] = 0; sa[1] = 0;
	    retval |= REDOUTIL;
	    emit(12);
	    break;

	case 4:	/* menunum case 3 itemnum case 4 -- Echo mode */
	    if (p_echo)
		p_echo = 0;
	    else
		p_echo = 1;
	    retval |= REDOUTIL;
	    break;

	case 5:	/* menunum case 3 itemnum case 5 -- Wrap mode */
	    if (p_wrap)
		p_wrap = 0;
	    else
		p_wrap = 1;
	    retval |= REDOUTIL;
	    break;

	case 6:	/* menunum case 3 itemnum case 6 -- NumKey */
	    if (p_keyapp)
		p_keyapp = 0;
	    else
		p_keyapp = 1;
	    retval |= REDOUTIL;
	    break;

	case 7:	/* menunum case 3 itemnum case 7 -- App Cur */
	    if (p_curapp)
		p_curapp = 0;
	    else
		p_curapp = 1;
	    retval |= REDOUTIL;
	    break;

	case 8:	/* menunum case 3 itemnum case 8 -- BS <-> DEL */
	    swap_bs_del();
	    retval |= REDOUTIL;
	    break;

	case 9:	/* menunum case 3 itemnum case 9 -- Xfer Beep */
	    if(p_xbeep)
		p_xbeep = 0;
	    else
		p_xbeep = 1;
	    retval |= REDOUTIL;
	    break;

	case 10: /* menunum case 3 itemnum case 10 - Mouse Up */
	    if(p_mouse_up)
		p_mouse_up = 0;
	    else
		p_mouse_up = 1;
	    retval |= REDOUTIL;
	    break;

	case 11: /* menunum case 3 itemnum case 11 - Mouse Down */
	    if(p_mouse_down)
		p_mouse_down = 0;
	    else
		p_mouse_down = 1;
	    retval |= REDOUTIL;
	    break;
	}

    break;
    } /* end of switch ( menunum ) */
    return retval;
}
