/************************************************************************
*  One of many Terminal Programs for the Amiga
*	Features:  Ascii, Xmodem, and CompuServe 'B' protocol transfers
*		   Phone Library support
*		   Function Key support
*		   Limited direct DOS support
*
*
*  Originally derived from AmigaTerm 1.0 - written by Michael Mounier
*
*     Version 2.0 - May, 1986 --- Bob Rakosky
*     -  corrected buffer capture to use xon/xoff when flushing 
*        buffer to disk, to prevent lost characters
*     -  increased buffer size of capture buffer and allocated memory
*        dynamically
*     -  added Phone Library support
*     -  modularized code to speed up compiles for fixes/mods
*     -  added CRC option to Xmodem transfers
*
*     Version 2.1 - June, 1986 --- Bob Rakosky	
*     -  changed to a 'borderless' window, allowing full 80 char line
*     -  added DOS 'directory' and 'change current directory' gadgets 
*        to menu line border
*     -  Added function key support
*     -  Added CompuServe B-protocol
*     -  Restructured 'modularization' of code segments for a more 
*        logical breakdown of source components
*
*
*   Functions in this module:
*	InitFileItems() - initializes File sub-menu
*	InitRSItems() - initializes Baud Rate sub-menu
*	InitPHItems() - initializes Phone support sub-menu
*	InitMenu() - initializes Menu structures
*	init_window() - initializes/opens program window
*
*	main() - initialization, main process loop, termination
*
************************************************************************/
#include "term.h"

extern char *getmem();

char	*bufr = NULL;
int	fd,
capture = FALSE,
bufr_ptr = NULL,
cap_open = FALSE,
timeout = FALSE;
FILE	*tranr = NULL;
long	bytes_xferred;
ULONG	class;
USHORT	code,
qual,
menunum,
itemnum;
int	KeepGoing,
send;
char	c,
name[32];
FILE	*trans = NULL;

/*   Intuition always wants to see these declarations */
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

/*  structures for GADGETS for window structure */
struct IntuiText hlp_txt = {
	3,2,		/* front pen, back */
	JAM2,		/* draw mode */
	0,0,		/* relative start */
	NULL,		/* font */
	(UBYTE *) " Help ", /* text */
	NULL		/* chain */
};
struct IntuiText dir_txt = {
	3,2,		/* front pen, back */
	JAM2,		/* draw mode */
	0,0,		/* relative start */
	NULL,		/* font */
	(UBYTE *) " Dir  ", /* text */
	NULL		/* chain */
};
struct IntuiText cd_txt = {
	0,1,		/* front pen, back */
	JAM2,		/* draw mode */
	-26,0,		/* relative start */
	NULL,		/* font */
	(UBYTE *) "cd:", /* text */
	NULL		/* chain */
};

UBYTE cd_nam[128];
extern UBYTE undo_buf[];

struct StringInfo cd_nm_buf = {
	cd_nam,		/* buffer */
	undo_buf,	/* undo buffer */
	0,		/* buf pos */
	128,		/* Max chars */
	0,		/* first disp pos */
	0,		/* Undo pos */
	0,		/*  current char count */
	0,0,0,
	NULL,NULL
};


/*   Macros for identifying gadgets   */

#define HLP_GAD		210
#define DIR_GAD		211
#define CD_GAD		212

#define UP_HLP_GAD (gad->GadgetID == HLP_GAD)
#define UP_DIR_GAD (gad->GadgetID == DIR_GAD)
#define UP_CD_GAD (gad->GadgetID == CD_GAD)

struct Gadget cd_gad = {
	NULL,		/* chain to next */
	384,0,		/* left, top */
	192,9,		/* width, height */
	GADGHCOMP,	/* flags */
	RELVERIFY,
	STRGADGET,	/* gadget type */
	NULL, NULL,	/* render ptrs */
	&cd_txt,	/* gadget label */
	NULL,		/* exclude */
	(APTR)&cd_nm_buf,	/* string buffers */
	CD_GAD,		/* gadget id */
	NULL		/* user data */
};

struct Gadget dir_gad = {
	&cd_gad,	/* chain to next */
	240,0,		/* left, top */
	48,9,		/* width, height */
	GADGHCOMP,	/* flags */
	RELVERIFY,
	BOOLGADGET,	/* gadget type */
	NULL, NULL,	/* render ptrs */
	&dir_txt,	/* gadget label */
	NULL,		/* exclude */
	NULL,		/* string buffers */
	DIR_GAD,		/* gadget id */
	NULL		/* user data */
};

struct Gadget hlp_gad = {
	&dir_gad,	/* chain to next */
	160,0,		/* left, top */
	48,9,		/* width, height */
	GADGHCOMP,	/* flags */
	RELVERIFY,
	BOOLGADGET,	/* gadget type */
	NULL, NULL,	/* render ptrs */
	&hlp_txt,	/* gadget label */
	NULL,		/* exclude */
	NULL,		/* string buffers */
	HLP_GAD,	/* gadget id */
	NULL		/* user data */
};

/* my window structure */
struct NewWindow NewWindow = {
	0,
	0,
	640,
	200,
	0,
	1,
	CLOSEWINDOW | RAWKEY | MENUPICK | GADGETUP,
	WINDOWCLOSE | SMART_REFRESH | ACTIVATE | BORDERLESS
	   | WINDOWDEPTH | REPORTMOUSE,
	&hlp_gad,
	NULL,
	"Term Plus 2.1",
	NULL,
	NULL,
	100, 35,
	640, 200,
	WBENCHSCREEN,
};

struct Window *mywindow;             /* ptr to applications window */
struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */


/*****************************************************
*                     File Menu
*****************************************************/

/* define maximum number of menu items */
#define FILEMAX 6

/*   declare storage space for menu items and
 *   their associated IntuiText structures
 */
struct MenuItem FileItem[FILEMAX];
struct IntuiText FileText[FILEMAX+1];


/* define maximum number of sub-menu items for XMODEM options */
#define X_SUB_MAX 4

/*   declare storage space for menu items and
 *   their associated IntuiText structures
 */
struct MenuItem X_Sub_Item[X_SUB_MAX];
struct IntuiText X_Sub_Text[X_SUB_MAX];

/*****************************************************************/
/*    The following function initializes the structure arrays    */
/*   needed to provide the File menu topic.                      */
/*****************************************************************/
InitFileItems()
{
	short n;

	/* initialize each menu item and IntuiText with loop */
	for( n=0; n<FILEMAX; n++ )
	{
		FileItem[n].NextItem = &FileItem[n]+1;
		FileItem[n].LeftEdge = 0;
		FileItem[n].TopEdge = 11 * n;
		FileItem[n].Width = 150 + COMMWIDTH;
		FileItem[n].Height = 11;
		if (n == 1) FileItem[n].Flags = ITEMTEXT | HIGHBOX | COMMSEQ;
		else FileItem[n].Flags = ITEMTEXT
		   | ITEMENABLED
		   | HIGHBOX
		   | COMMSEQ;
		FileItem[n].MutualExclude = 0;
		FileItem[n].ItemFill = (APTR)&FileText[n];
		FileItem[n].SelectFill = NULL;
		FileItem[n].Command = 0;
		FileItem[n].SubItem = NULL;
		FileItem[n].NextSelect = 0;
	}
	FileItem[FILEMAX-1].NextItem = NULL;
	FileItem[0].Command = 'K';
	FileItem[1].Command = 'C';
	FileItem[3].Command = 'R';
	FileItem[4].Command = 'S';

	FileItem[2].Flags &= (0xffff - COMMSEQ);
	FileItem[5].Flags &= (0xffff - COMMSEQ);

	for( n=0; n<FILEMAX+1; n++ )
	{
		FileText[n].FrontPen = 0;
		FileText[n].BackPen = 1;
		FileText[n].DrawMode = JAM2;     /* render in fore and background */
		FileText[n].LeftEdge = 0;
		FileText[n].TopEdge = 1;
		FileText[n].ITextFont = NULL;
		FileText[n].NextText = NULL;
	}

	/* initialize text for specific menu items */
	FileText[0].IText = (UBYTE *)"Ascii Capture On";
	FileText[1].IText = (UBYTE *)"CLOSE Capture";
	FileText[2].IText = (UBYTE *)"Ascii Send";
	FileText[3].IText = (UBYTE *)"Xmodem Receive";
	FileText[4].IText = (UBYTE *)"Xmodem Send";
	FileText[5].IText = (UBYTE *)"Xmodem Options";
	FileText[6].IText = (UBYTE *)"Ascii Capture Off";

	/*  Point Xmodem Options menu item to sub-menu */
	FileItem[5].SubItem = &X_Sub_Item[0];

	/* initialize each menu item and IntuiText with loop */
	for( n=0; n<X_SUB_MAX; n++ )
	{
		X_Sub_Item[n].NextItem = &X_Sub_Item[n]+1;
		X_Sub_Item[n].LeftEdge = 130;
		X_Sub_Item[n].TopEdge = (11 * n);
		X_Sub_Item[n].Width = 140;
		X_Sub_Item[n].Height = 11;
		X_Sub_Item[n].Flags =	ITEMTEXT |
		   ITEMENABLED |
		   HIGHBOX |
		   CHECKIT;
		X_Sub_Item[n].MutualExclude = 0;
		X_Sub_Item[n].ItemFill = (APTR)&X_Sub_Text[n];
		X_Sub_Item[n].SelectFill = NULL;
		X_Sub_Item[n].Command = 0;
		X_Sub_Item[n].SubItem = NULL;
		X_Sub_Item[n].NextSelect = 0;
	}
	X_Sub_Item[X_SUB_MAX-1].NextItem = NULL;
	X_Sub_Item[0].MutualExclude = 1 << 1;
	X_Sub_Item[1].MutualExclude = 1 << 0;
	X_Sub_Item[2].MutualExclude = 1 << 3;
	X_Sub_Item[3].MutualExclude = 1 << 2;
	X_Sub_Item[0].Flags |= CHECKED;
	X_Sub_Item[2].Flags |= CHECKED;

	for( n=0; n<X_SUB_MAX+1; n++ )
	{
		X_Sub_Text[n].FrontPen = 0;
		X_Sub_Text[n].BackPen = 1;
		X_Sub_Text[n].DrawMode = JAM2;     /* render in fore and background */
		X_Sub_Text[n].LeftEdge = 0;
		X_Sub_Text[n].TopEdge = 1;
		X_Sub_Text[n].ITextFont = NULL;
		X_Sub_Text[n].NextText = NULL;
	}

	/* initialize text for specific menu items */
	X_Sub_Text[0].IText = (UBYTE *)"   CRC ";
	X_Sub_Text[1].IText = (UBYTE *)"   CheckSum ";
	X_Sub_Text[2].IText = (UBYTE *)"   Std. Timeout ";
	X_Sub_Text[3].IText = (UBYTE *)"   Long Timeout ";
	return( 0 );
}

/*****************************************************/
/*                BaudRate  Menu                     */
/*****************************************************/

/* define maximum number of menu items */
#define RSMAX 5

/*   declare storage space for menu items and
 *   their associated IntuiText structures
 */
struct MenuItem RSItem[RSMAX];
struct IntuiText RSText[RSMAX];

/*****************************************************************/
/*    The following function initializes the structure arrays    */
/*   needed to provide the BaudRate menu topic.                  */
/*****************************************************************/
InitRSItems()
{
	short n;

	/* initialize each menu item and IntuiText with loop */
	for( n=0; n<RSMAX; n++ )
	{
		RSItem[n].NextItem = &RSItem[n]+1;
		RSItem[n].LeftEdge = 0;
		RSItem[n].TopEdge = 11 * n;
		RSItem[n].Width = 85;
		RSItem[n].Height = 11;
		RSItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT;
		RSItem[n].MutualExclude = (~(1 << n));
		RSItem[n].ItemFill = (APTR)&RSText[n];
		RSItem[n].SelectFill = NULL;
		RSItem[n].Command = 0;
		RSItem[n].SubItem = NULL;
		RSItem[n].NextSelect = 0;

		RSText[n].FrontPen = 0;
		RSText[n].BackPen = 1;
		RSText[n].DrawMode = JAM2;     /* render in fore and background */
		RSText[n].LeftEdge = 0;
		RSText[n].TopEdge = 1;
		RSText[n].ITextFont = NULL;
		RSText[n].NextText = NULL;
	}
	RSItem[RSMAX-1].NextItem = NULL;
	/* 1200 baud item chekced */
	RSItem[1].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT | CHECKED;

	/* initialize text for specific menu items */
	RSText[0].IText = (UBYTE *)"   300";
	RSText[1].IText = (UBYTE *)"   1200";
	RSText[2].IText = (UBYTE *)"   2400";
	RSText[3].IText = (UBYTE *)"   4800";
	RSText[4].IText = (UBYTE *)"   9600";

	return( 0 );
}

/*****************************************************/
/*                PhoneLib  Menu                     */
/*****************************************************/

/* define maximum number of menu items */
#define PHMAX 2

/*   declare storage space for menu items and
 *   their associated IntuiText structures
 */
struct MenuItem PHItem[PHMAX];
struct IntuiText PHText[PHMAX];

extern struct MenuItem bbs_men[];
/*****************************************************************/
/*    The following function initializes the structure arrays    */
/*   needed to provide the PhoneLib menu topic.                  */
/*****************************************************************/
InitPHItems()
{

	short n;

	/* initialize each menu item and IntuiText with loop */
	for( n=0; n<PHMAX; n++ )
	{
		PHItem[n].NextItem = &PHItem[n]+1;
		PHItem[n].LeftEdge = 0;
		PHItem[n].TopEdge = 11 * n;
		PHItem[n].Width = 72;
		PHItem[n].Height = 11;
		PHItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX ;
		PHItem[n].MutualExclude = NULL;
		PHItem[n].ItemFill = (APTR)&PHText[n];
		PHItem[n].SelectFill = NULL;
		PHItem[n].Command = 0;
		PHItem[n].SubItem = NULL;
		PHItem[n].NextSelect = 0;

		PHText[n].FrontPen = 0;
		PHText[n].BackPen = 1;
		PHText[n].DrawMode = JAM2;     /* render in fore and background */
		PHText[n].LeftEdge = 0;
		PHText[n].TopEdge = 1;
		PHText[n].ITextFont = NULL;
		PHText[n].NextText = NULL;
	}
	/* initialize text for specific menu item */
	PHText[0].IText = (UBYTE *)" Library ";
	PHText[1].IText = (UBYTE *)" Dial ";
	PHItem[1].SubItem = &bbs_men[0];
	PHItem[PHMAX-1].NextItem = NULL;

	load_phlib(0);		/*  load default phone library  */
	return( 0 );
}

/*****************************************************/
/*                Function Key Menu Item             */
/*****************************************************/

struct IntuiText FK_txt = {
	0,1,		/* front pen, back */
	JAM2,		/* draw mode */
	0,0,		/* relative start */
	NULL,		/* font */
	(UBYTE *) "Set F-keys", /* text */
	NULL		/* chain */
};

struct MenuItem FKItem = {
	NULL,		/* next item */
	0,0,100,11,	/* left, top, width, height */
	ITEMTEXT | ITEMENABLED | HIGHCOMP,	/* flags */
	NULL,		/* mutual exclude */
	(APTR)&FK_txt,	/* Intuitext */
	NULL,		/* command key */
	NULL,		/* sub-menu */
	NULL		/* next select */
};


/***************************************************/
/*                Menu Definition                  */
/*                                                 */
/*      This section of code is where the simple   */
/*   menu definition goes.                         */
/***************************************************/

/* current number of available menu topics */
#define MAXMENU 4

/*   declaration of menu structure array for
 *   number of current topics.  Intuition
 *   will use the address of this array to
 *   set and clear the menus associated with
 *   the window.
 */
struct Menu menu[MAXMENU];

/**********************************************************************/
/*   The following function initializes the Menu structure array with */
/*  appropriate values for our simple menu strip.  Review the manual  */
/*  if you need to know what each value means.                        */
/**********************************************************************/
InitMenu()
{
	menu[0].NextMenu = &menu[1];
	menu[0].LeftEdge = 5;
	menu[0].TopEdge = 0;
	menu[0].Width = 50;
	menu[0].Height = 10;
	menu[0].Flags = MENUENABLED;
	menu[0].MenuName = "File";           /* text for menu-bar display */
	menu[0].FirstItem = &FileItem[0];    /* pointer to first item in list */

	menu[1].NextMenu = &menu[2];
	menu[1].LeftEdge = 65;
	menu[1].TopEdge = 0;
	menu[1].Width = 85;
	menu[1].Height = 10;
	menu[1].Flags = MENUENABLED;
	menu[1].MenuName = "BaudRate";        /* text for menu-bar display */
	menu[1].FirstItem = &RSItem[0];    /* pointer to first item in list */

	menu[2].NextMenu = &menu[3];
	menu[2].LeftEdge = 160;
	menu[2].TopEdge = 0;
	menu[2].Width = 60;
	menu[2].Height = 10;
	menu[2].Flags = MENUENABLED;
	menu[2].MenuName = " Phone ";        /* text for menu-bar display */
	menu[2].FirstItem = &PHItem[0];    /* pointer to first item in list */

	menu[3].NextMenu = NULL;
	menu[3].LeftEdge = 220;
	menu[3].TopEdge = 0;
	menu[3].Width = 70;
	menu[3].Height = 10;
	menu[3].Flags = MENUENABLED;
	menu[3].MenuName = " F-keys ";        /* text for menu-bar display */
	menu[3].FirstItem = &FKItem;

	return( 0 );
}


init_window()
{
	IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", INTUITION_REV);
	if( IntuitionBase == NULL )
	{
		puts("can't open intuition\n");
		exit(TRUE);
	}

	GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",GRAPHICS_REV);
	if( GfxBase == NULL )
	{
		puts("can't open graphics library\n");
		exit(TRUE);
	}

	cur_dir(); 	/* get name of current directory */

	if(( mywindow = (struct Window *)OpenWindow(&NewWindow) ) == NULL)
	{
		puts("cant open window\n");
		exit(TRUE);
	}
	return(0);
}

/*  area to save current directory lock  */
extern struct FileLock *save_dir;
extern struct IOExtSer *Read_Request;
extern char rs_in[2];
extern struct IOExtSer *Write_Request;
extern char rs_out[2];

/******************************************************/
/*                   Main Program                     */
/*                                                    */
/*      This is the main body of the program.         */
/******************************************************/
static char VIDTEX_Response[] = "#DTE,PB,DT\015";

main()
{
	int i;
	struct Gadget *gad;
	short ESC_Seq_State = 0;
	char *cp;

	init_window();
	load_fklib();
	init_ser();


	InitFileItems();
	InitRSItems();
	InitPHItems();
	InitMenu();
	SetMenuStrip(mywindow,&menu[0]);

	KeepGoing = TRUE;
	send=FALSE;
	SetAPen(mywindow->RPort,1);
	emit(12);
	BeginIO(Read_Request);

	while( KeepGoing )
	{
		/* wait for window message or serial port message */
		Wait((1 << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit) 
		   | ( 1 << mywindow->UserPort->mp_SigBit));

		if(CheckIO(Read_Request))
		{
			WaitIO(Read_Request);
			c=rs_in[0] & 0x7f;
			BeginIO(Read_Request);
			switch (ESC_Seq_State)
			{
			case 0:
				switch (c)
				{
				case ESC:
					ESC_Seq_State = 1;
					break;

				case ENQ:
					/* Enquiry -- send ACK for packet 0 */

					sendchar(DLE);
					sendchar('0');
					break;

				case DLE:
					ESC_Seq_State = 2;
					break;

				default:
					emit(c);
					if (capture)
						add_cap(c);
				}

				break;

			case 1:
				/* ESC -- process any escape sequences here */

				switch (c)
				{
				case 'I':
					/*
													     * Reply to the VIDTEX "ESC I" identify sequence
													     */			    	
					cp = VIDTEX_Response;
					while (*cp != 0) sendchar(*cp++);
					ESC_Seq_State = 0;
					break;

				default:
					emit(ESC);
					if (capture)
						add_cap(ESC);
					emit(c);
					if (capture)
						add_cap(c);
					ESC_Seq_State = 0;
				}

				break;

			case 2:
				/* DLE */

				if (c == 'B')
				{
					/* Start of "B" protocol packet. Go into protocol
													 * mode and transfer the file as requested.
													 */

					if (!B_prot_xfer()) emits("Transfer failed!");
				}
				else
				   {
					emit(DLE);
					if (capture)
						add_cap(DLE);
					emit(c);
					if (capture)
						add_cap(c);
				}

				ESC_Seq_State = 0;
			}  /*  end switch(ESC_Seq_State)  */
		}  /*  end if (CheckIO(Read_Request))   */

		while( NewMessage=(struct IntuiMessage *)GetMsg(mywindow->UserPort) )
		{
			class = NewMessage->Class;
			code = NewMessage->Code;
			qual = NewMessage->Qualifier;
			gad = (struct Gadget *)NewMessage->IAddress;
			ReplyMsg( NewMessage );
			switch( class )
			{
			case CLOSEWINDOW:
				/*   User is ready to quit, so indicate
										 *   that execution should terminate
										 *   with next iteration of the loop.
										 */
				KeepGoing = FALSE;
				break;

			case RAWKEY:
				/*  User has touched the keyboard */
				switch (i = toasc(code,qual)) {
				case -1: 
					do_fkey(code,qual);
				case 0: 
					break;
				default: 
					sendchar(i);
				}
				break;

			case MENUPICK:
				do_menu(MENUNUM(code),ITEMNUM(code),SUBNUM(code));
				break;
			case GADGETUP:
				if (UP_HLP_GAD) do_help();
				else if (UP_DIR_GAD) do_dir();
				else if (UP_CD_GAD) do_cd();
				break;
			}   /* end of switch (class) */
		}   /* end of while ( newmessage )*/
	}  /* end while ( keepgoing ) */

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

	if (cap_open) clos_cap();

	if (bufr)
		rlsmem(bufr,BufSize);

	reset_dir();
	clos_ser();
	ClearMenuStrip( mywindow );
	CloseWindow( mywindow );
	exit(FALSE);
} /* end of main */
