/* Edit by Bill, Jeff, and Howie on Jun 13 */
/* Add select window, drag */
/* Edit by WBC3 on Apr 29 */
/* Don't supply a second name for send as, otherwise file name translation */
/* will not occur.  Let user type it if they want. */
/* Edit by WBC3 on Apr 23 */
/* Make typein to the emulator only take effect when it's the "front window" */
/* Edit by WBC3 on Apr 23 */
/* Make only Command-. stop protocol rather then anything but Command-. */
/* Edit by WBC3 on Apr 22 */
/* Make debug and tlog only show up if DEBUG is defined */
/* Edit by Bill on Apr 21 17:51 */
/* In Screen depelete event queue instead of handling one event at */
/* a time, also don't loose events */

/*
 * file ckmusr.c
 *
 * Module of mackermit containing code for the menus and other MacIntosh
 * things.
 *
 */

/*
 Copyright (C) 1985, Trustees of Columbia University in the City of New York.
 Permission is granted to any individual or institution to use, copy, or
 redistribute this software so long as it is not sold for profit, provided this
 copyright notice is retained. 
*/

#include "ckcker.h"
#include "ckmdef.h"			/* General Mac defs */
#include "ckmres.h"			/* Mac resource equates */
#include "ckcdeb.h"
#include "mac/quickdraw.h"		/* Macintosh C interface */
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "mac/packintf.h"
#include "ckmkkc.h"			/* keyboard config commons */
    
/* String defs */

MenuHandle menus[MAX_MENU+1];		/* handle on our menus */
     
/* Global Variables */
     
int innum,		    		/* Input driver refnum */
    outnum,		    		/* Output driver refnum */
    protocmd;	    			/* protocol file cmd, or -1 for */
					/*  remote cmds, or 0 if not in */
					/*  protocol */

char *mybuff;  	    			/* Serial drivers new buffer */

CursHandle watchcurs;			/* the watch cursor */

WindowPtr theWindow;
WindowRecord wRecord;

/* Rectangles */
short wirect[]={40,5,335,505}; 		/* Kermit window in global */
CSParam controlparam;      /* To change serial driver paramaters */

int quit=FALSE;

struct QDVar QDVar;

/*
 *  p a r s e r
 *
 *  Entry point for kermit.
 *  Establish a virtual terminal connection with the remote host and
 *  process mouse events, such as selecting items from the menu bars.
 *
 */

char
parser()
{
    char domouse(),rstate = 0;
    EventRecord myevent;
    WindowPtr evtwindow;
    int evtwcode, evtwref;

    SetCursor(&QD->arrow);		/* back to normal cursor */    
    protocmd = 0;			/* protocol not active */

    while (quit == FALSE && 		/* Until they want to quit */
      	   rstate == 0)			/* or return */
    {
	SystemTask();			/* Update system things */

	inpchars();			/* Handle all the pending port chars */

	GetNextEvent(everyEvent,&myevent);

	switch (myevent.what)		/* events */
	{
	    case keyDown:		/* Handle char input */
	    case autoKey:		/*  both ways */
	    	if (FrontWindow() == theWindow) handle_char(&myevent);
		break;

	    case updateEvt:		/* A window update event */
		doupdate((WindowPtr) myevent.message); /* Handle update */
		break;

	    case activateEvt:		/* Something turning active */
	    	doactivate((WindowPtr) myevent.message,myevent.modifiers);
		break;

	    case mouseDown:		/* Mouse event */
	    	evtwcode = FindWindow(&myevent.where,&evtwindow);
		if (evtwindow != (WindowPtr) NIL)
		    evtwref = GetWRefCon(evtwindow);
		rstate = domouse(evtwcode,evtwref,&myevent,evtwindow);
		break;
	}
    }  
    if (quit)				/* want to exit the program? */
     doexit(0);				/* yes, finish up */
    SetCursor(*watchcurs);		/* set the watch */
    return(rstate);			/* and return with state */
}


/* miniparser - called during protocol to handle events.  Handles dialog,
 *    	      	update, and keydown (the abort key) events.  Ignores
 *    	      	all other events.  The dialog events are assumed to
 *    	      	be for screen (status) display.
 */

miniparser(deplete)			/* deplete pending events */
{
  EventRecord ev;
  DialogPtr mydlg;
  int item;

  do {
    SystemTask();			/* let the system move */
    GetNextEvent(everyEvent,&ev);	/* get an event */
    
    if (ev.what == nullEvent)
     return;				/* depleted pending events */
     
    if (IsDialogEvent(&ev))		/* meant for dialog manager? */
     if (DialogSelect(&ev,&mydlg,&item))  /* must be for screen */
      scrmydlg(item);			/* let him handle it */

    switch (ev.what) {			/* we may need to do something */
      case updateEvt:
      	doupdate((WindowPtr) ev.message); /* handle updates */
	break;
	
      case keyDown:
      	if ((ev.modifiers & cmdKey) && ((ev.message & 0x7f) == '.'))
	  if (CautionAlert(ALERT_ABORT,NILPROC) == OKBtn)
	   sstate = 'a';		/* move into abort state */
        break;
    }
  } while (deplete);			/* return now, or loop */
}

/* domouse  - handle mouse down events for different windows. */

char domouse(wcode,wref,evt,w)
int wcode, wref;
EventRecord *evt;
WindowPtr w;
{
    char menu_event(), state = 0;
    Rect dragrect;

    SetRect(&dragrect,4,24,508,338);

    switch (wcode)			/* Tell us where */
    {
	case inMenuBar:			/* Looking at the menus? */
	    state = menu_event(MenuSelect(&evt->where)); /* Yes... */
	    HiliteMenu(0);		/* Done, so un-hilite */
	    break;			/* All done */
			
	case inSysWindow:		/* Looking at system, like */
	    SystemClick(evt,w); 	/* a desk accessary */
	    break;			/* Let the system handle it */

	case inContent:
	    if (wref == RCD_WREF)
	      rcdmouse(wcode,evt);
	    else
	      SelectWindow(w);		/* make window current */
	    break;
	    
	case inDrag:			/* Wanna drag? */
	    if (wref == RCD_WREF)
	      rcdmouse(wcode,evt);
	    else
	      DragWindow(w,&evt->where,&dragrect);
	    break;
	    
	case inGoAway:
	case inGrow:
	    if (wref == RCD_WREF)	/* Our remote command window? */
	    	rcdmouse(wcode,evt);
	    break;
   }
   return(state);			/* return with new state or 0 */
}

/* doupdate - handle update event on different windows, dispatch to
 *    	      redraw routines
 */

doupdate(w)
WindowPtr w;
{
    WindowPtr oldw;

    GetPort(&oldw);
  
    switch (GetWRefCon(w))
    {
	case SCR_WREF:			/* The main screen window */
	    BeginUpdate(w);
	    SetPort(w);
	    term_redraw();		/* Redraw terminal window */
	    SetPort(oldw);
	    EndUpdate(w);
	    break;

	case RCD_WREF:			/* Remote response window */
	    BeginUpdate(w);
	    SetPort(w);
	    rcdupdate(w);  		/* Draw it... */
	    SetPort(oldw);
	    EndUpdate(w); 		/* All done */
	    break;

	default:			/* All others, do nothing */
	    break;
    }
}

/* doactivate - activate a window */

doactivate(w,mod)
WindowPtr w;
int mod;
{
    switch (GetWRefCon(w))
    {
	case RCD_WREF:
	    rcdactivate(mod);
	    break;
    }
}


char genstr[100];

char menu_event(menu_item)
{
    int menu = HiWord(menu_item),	/* decompose arg */
    	item = LoWord(menu_item);
    char state = '\0';
    int remotedialog();			/* returns boolean */

    switch (menu)
    {
	case APPL_MENU:			/* Mac system menu item */
	    handapple(item);
	    break;			/* all done */
    
	case FILE_MENU:
	    switch (item)		/* Find out which was selected */
	    {
	      	case QUIT_FIL:		/* Want to quit program? */
		    quit = TRUE;	/* Yes... flag it */
		    break;

		case SAVE_FIL:		/* save settings */
		    savevals();		/* save em */
		    break;
		    
		case LOAD_FIL:		/* load settings */
		    loadvals();
		    break;

		case SEND_FIL:		/* send a file: local, remote files */
		    if (!dosenddialog(&cmarg,&cmarg2))
		      break;
		    nfils = -1;		/* Use cmarg, not cmlist */
		    state = 's';	/* return with send state */
		    break;

		case RECV_FIL:		/* Ask for recv info -- */
		    initfilrecv();	/* init recv flags */
		    state = 'v';	/* return with recv state */
		    break;

		case GETS_FIL:		/* Get from server */
		    if (dogetfdialog(&cmarg))	/* remote-file. */
		      state = 'r';	/* Say we want to get */
		    break;
	    }
	    if (state != '\0')		/* going to enter protocol? */
	    {
	      protocmd = item;		/* yes, remember how */
	      scrcreate();		/* create the status screen */
	    }
	    break;

	case SETG_MENU:
	    switch (item)
	    {
		case PROT_SETG:
		    protodialog();
		    break;

		case COMM_SETG:
		    commdialog();	/* communications dialog */
		    break;

		case FILE_SETG:
		    setfiledialog();	/* do default file settings */
		    break;
		    
		case SCRD_SETG:		/* screen dump (CLOVER-SHIFT-1...) */
		    ScrDmpEnb = (ScrDmpEnb == scrdmpenabled) ?
		      scrdmpdisabled : scrdmpenabled; /* toggle */
		    CheckItem(menus[SETG_MENU],SCRD_SETG,
		      	       (ScrDmpEnb == scrdmpenabled));
	      	    break;
	    }
	    break;

/* return either 'g' for generic or 'c' for host with cmarg holding cmd */

	case REMO_MENU:
      	    cmarg = genstr;		/* indicate cmd ok to proceed */
    	    switch (item)
	    {
	      	case RESP_REMO:		/* Want to toggle display */
		    togglercmdw();	/* Do it */
		    cmarg = NILPTR;	/* Don't do anything else */
		    break;

		case FIN_REMO:
		    setgen(genstr,'F',"","","");    /* Finish */
		    break;

		case BYE_REMO:
		    setgen(genstr,'L',"","","");  /* Bye, logout */
		    break;
		    
		case SERV_REMO:
		    displa = 1;		/* umm */
		    scrcreate();	/* create the status screen */
		    protocmd = item;	/* ummm */
		    return('x');	/* ummm */

      	      	default:
		    if (!remotedialog(item,genstr))
		    	cmarg = NILPTR;	/* cancel issued, prevent it */
		    break;
	    }
	    if (cmarg == NILPTR) break;	/* Gave up on this command? */
	    protocmd = -1;		/* hey we're going to protocol! */
	    if (item == HOST_REMO)	/* Remote host? */
	      state = 'c';		/* yes, return it to driver */
	    else state = 'g';		/* else generic */
	    break;

	case LAU_MENU:
	    handlelaunch(item);		/* Handle x-fer to application */
	    break;
    }
    return(state);			/* Don't go into Kermit protocol */
}

/*
 * init_menus - create the menu bar.
 * 
 */

setup_menus()
{
    int i;

    for (i=MIN_MENU; i<=MAX_MENU; i++)  /* For all menus */
    {
	menus[i] = GetMenu(i);		/* Fetch it from resource file */
	InsertMenu(menus[i],0);		/* Put it on menu line */
    }
    AddResMenu(menus[APPL_MENU],"DRVR");
    DrawMenuBar();			/* Finish up by displaying the bar */
}

/*
 * mac_init - Initialize the macintosh and any window, menu, or other
 * resources we will be using.
 *
 */
 
mac_init()
{
    int err;
	
    QD = &QDVar;				

    MaxApplZone();			/* Make appl. heap big as can be */
    err = MoreMasters();		/* Create some more master pointers */
    if (err != noErr) printerr("Unable to create masters",err);

    InitGraf(&thePort);			/* Init the graf port */
    InitFonts();			/* The fonts */
    InitWindows();			/* The windows */
    InitMenus();
    TEInit();				/* Init text edit */
    InitDialogs(NILPROC);		/* The dialog manager */
    SetEventMask(everyEvent-keyUpMask);

    watchcurs = GetCursor(watchCursor);	/* the waiting cursor */
    
    mybuff = NewPtr(MYBUFSIZE);		/* Allocate mybuff from the heap */
    if (mybuff == NIL) printerr("Unable to allocate mybuff",0);

    setup_menus();			/* build our menus */
 
    ScrDmpEnb = scrdmpdisabled;		/* disable screen dumping */
    
    SetCursor(&QD->arrow);		/* start with a nice cursor */
 
    theWindow = NewWindow(&wRecord,(Rect *) wirect,"MacKermit",VIS,
    	documentProc,(WindowPtr) -1,1,SCR_WREF);
			
    initrcmdw();			/* init remote cmd window */
    initfilset();			/* init file settings */

    SetPort(theWindow);
    theWindow->txFont = 4;   /* Maco font with non-proportional spacing */
    theWindow->txSize = 9;
    PenSize(1,1);
 
    FlushEvents(everyEvent,0);		/* clear click ahead (ha!) */
  
    innum = OpenDriver(".AIn");		/* Set up IO drivers */
    outnum = OpenDriver(".AOut");
    setserial(innum,outnum,DSPEED,DEFPAR);  /* set speed parity */

    controlparam.serInBuff.serBPtr = mybuff; /* Make driver use larger buff */
    controlparam.serInBuff.serBLen = (short) MYBUFSIZE;
    err = Control(innum,9,&controlparam);
    if (err) printerr("Trouble making io buffer:",err);

    controlparam.serShk.fXOn = (char) FALSE;	/* Specify handshake options */
    controlparam.serShk.fCTS = (char) FALSE;
    controlparam.serShk.xOn = (char) 17;
    controlparam.serShk.xOff = (char) 19;
    controlparam.serShk.errs = (char) FALSE;
    controlparam.serShk.evts = (char) FALSE;
    controlparam.serShk.fInX = (char) FALSE;
    controlparam.serShk.null = (char) FALSE;

    err = Control(outnum,10,&controlparam);
    if (err) printerr("Trouble with handshake: ",err);

    consetup();				/* Set up for connecting */
    displa = TRUE;			/* Make everything goes to screen */
    
}

/*
 * mac_cleanup() - called before leaving this program to clean up any
 *    	      	   dangling Mac stuff.  Called by doexit and transfer
 *
 */

mac_cleanup()
{
  ScrDmpEnb = scrdmpenabled;		/* re-enabled screen dumping */
}

/* doexit(status) - exit to shell.  Perhaps we should check for abnormal
 *    	      	    status codes...
 */

doexit(status)
{
  mac_cleanup();			/* make things tidy */
  ExitToShell();
}

conect()
{
    return;
}

cmdlin()
{
    return(0);				/* Say that we parsed nothing */
}

chkint()
{
    return;
}

/* Only place we can initialize the mac stuff from */

cmdini()
{
    mac_init();				/* Set up the Mac */
    findfinderfiles();			/* see if file was selected */
}

#ifdef DEBUG
debug(flags,str,str2,num)
int flags, num;
char *str, *str2;
{
    char numbuf[10];

    if (!debflg) return;

    switch (flags)
    {
	default:
	    NumToString(numbuf,num);
	    ParamText(str,str2,numbuf,"");
	    CautionAlert(ALERT_DEBUG,NILPROC);
	    break;
    }
}
#endif

/* sleep - called during protocol for a dismiss.  Keep machine running
 *    	   with calls to the miniparser during this period.
 */

sleep(secs)
{
  PLONG finalticks;			/* tickscount for exit */
    	  
  finalticks = TickCount()+(60*secs);	/* TickCount for exit  */
  while (finalticks > TickCount())	/* keep the machine running by */
  {
    miniparser(TRUE);			/* deplete the Q */
    if (sstate == 'a')			/* if in abort state, forget */
     return;				/* this wait */
  }
}

ermsg(msg)				/* Print error message */
char *msg;
{
    screen(SCR_EM,0,0l,msg);		/* Put the error on the screen */
    tlog(F110,"Error -",msg,0l);
}

intmsg(n)
long n;
{
    return;
}

#ifdef TLOG
tlog(f,s1,s2,n)
int f;
long n;
char *s1, *s2;
{
    return;
}
#endif
