/* Edit by Bill on Wed May 15, 15:48 */
/* change name of rtol to sfprtol, make it the common file rtol rtn */
/* either use RSRC & BINA if .RSRC extension, or use current defaults */
/* Edit by Bill on Wed May 15, 15:48 */
/* in initfilerecv make sure kermit flag binary is set */

/* 
 * file ckmsfp.c
 *
 * Module of MacKermit containing standard file package calls:
 *
 *    dosenddialog() - Send file...
 *    dorecvdialog() - Receive file...
 *    dogetfdialog() - Get file from server...
 *
 * Bill Schilit, May, 1984
 *
 * 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"			/* Kermit definitions */
#include "ckmdef.h"			/* Common Mac module definitions */
#include "ckmres.h"			/* resource defs */
#include "mac/quickdraw.h"
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "mac/packintf.h"

FILINF filargs;				/* is global */

typedef struct {			/* SFPGetFile event filter */
  DialogPtr dlg;			/* (in stack order) */
  short item;
} SFdlgFilterArgs;

typedef struct {			/* SFPGetFile item hit filter  */
    short *itemhit;			/* (in stack order) */
    EventRecord *theevent;    
    DialogPtr thedialog;
 } ModalFilterArgs;


#define DLG_GETF 3998			/* SFPutFile DLOG replacement */
#define DLG_RECV 3999			/* SFPutFile DLOG replacement */
#define DLG_SEND 4000			/* SFGetFile DLOG replacement */
#define DLG_FSET 1004			/* File settings */

/* Resource IDs for DLG_GETF DITL (3998) */

#define GETF_GETB OK			/* "Get" button */
#define GETF_REMF 4			/* remote file name */

/* Resource IDs for DLG_RECV DITL (3999) */

#define RECV_RBTN putSave		/* "Receive" button */
#define RECV_PROC 15			/* proceed without more dialogs */

#define RADITM_DATA 11
#define RADITM_RSRC 12
#define RADITM_TEXT 13
#define RADITM_BINA 14

#define RADITM_FIRST RADITM_DATA
#define RADITM_LAST RADITM_BINA

int radflgs[] = {FIL_DATA,FIL_RSRC,FIL_TEXT,FIL_BINA};
int radnotflgs[] = {FIL_RSRC,FIL_DATA,FIL_BINA,FIL_TEXT};

/* Resource IDs for DLG_SEND DITL (4000) */

#define SEND_ASFN 17			/* "As" file name */
#define SEND_INVT 16			/* invisible edit text */

/* Globals used by SEND dialog */

SFReply sfr;				/* holds file info */
BOOL sendselflg,			/* TRUE means file was selected */
     sendasflg;				/* TRUE means AS field is active */

/* gethdl - return a control handle given a resource ID */

Handle gethdl(item,dp)
DialogPtr dp;
{
 int itype;
 Rect ibox;
 Handle ihdl;

 GetDItem(dp,item,&itype,&ihdl,&ibox);
 return(ihdl);
}

#define getctlhdl(item,dp) (ControlHandle) gethdl(item,dp)

/* setfilflgs - Manage the filflg word and radio controls.
 *
 * Flags will be changed when the resource ID of item hit (passed to
 * this routine) is one of the radio items, or alternately routines can
 * modify the filflg word itself and the radio items will be updated
 * accordingly.
 *
 * N.B. Each dialog using these flags has them defined with the same
 * DITL item numbers.
 *
 */

setfilflgs(item,dlg)
DialogPtr dlg;
{
 ControlHandle ctlhdl;
 int i;

  if (item >= RADITM_FIRST &&		/* check for item... is it  */
      item <= RADITM_LAST)		/*  a radio item for us? */
  {
    filargs.filflg |= radflgs[item-RADITM_FIRST];	/* yes... set flag */
    filargs.filflg &= ~radnotflgs[item-RADITM_FIRST];  /* clear opposite */
  }

  for (i=RADITM_FIRST; i <= RADITM_LAST; i++) /* update all */
  {  
    ctlhdl = getctlhdl(i,dlg); 		/* get a handle on his radio item */
    SetCtlValue(ctlhdl,
        (filargs.filflg & radflgs[i-RADITM_FIRST]) ? btnOn : btnOff);
  }
}

setfilnams(remfid,dlg)
DialogPtr dlg;
{
  filargs.filrem[0] = 0;		/* no remote file */

  p2cstr(sfr.fName);			/* convert to c */
  strcpy(filargs.fillcl,sfr.fName);	/* copy sfr into local name stg */
  c2pstr(sfr.fName);			/* back into pascal string */
    
  if (remfid != 0)			/* fetch remote name if present */
   GetIText(gethdl(remfid,dlg),filargs.filrem);	/* in an edittext field */
  
  binary = (filargs.filflg & FIL_BINA); /* selected binary mode? */
}

/* sendmydlg - SFPGetFIle item hit filter for "send file" dialog.
 *
 * This filter is called by SFPGetFile to let the programmer handle hits
 * on his custom items.  Our items are 2 sets of buttons for selecting
 * the fork (data or resource) and the transfer mode (binary or text).
 * Also we have an EditText item for filling in the AS name.
 *
 * The buttons are set when the user clicks, but they also are given
 * values depending on the selection of a file.  If the file's type is
 * "APPL" then controls "Resource" and "Binary" are automaticlly set,
 * otherwise the controls "Data" and "Text" are set.  SF-File keeps the
 * SFReply upto date when a file name is selected, but...  unfortunately
 * we are called before the SFReply is updated and so when we notice
 * "getNmList" is hit we defer our update for one cycle.
 *
 * Our other item, the TextEdit item to set the "AS" file name, can be
 * enabled or disabled to allow the selection of a file name by typing a
 * character (standard SFGetFile stuff).  By using the global flag
 * sendasflg and an event filter we switch between sending the chars to
 * SF-File for filename selection and to ModalDialog for TextEdit of our
 * AS name.  Since it would be nice to get rid of that blinking cursor
 * in the TextEdit item our DITL has an invisible EditText item which
 * becomes active for this purpose. 
 *
 * At startup the AS field is disabled (the invisible EditText is
 * current and sndasflg is FALSE).  The user can make AS active by
 * clicking in it.  The user can toggle by clicking on the StatText
 * "AS" -- though I won't tell anybody if you don't.
 *
 */

sendmydlg()
{
 SFdlgFilterArgs args;
 short *rslt;
 BOOL isappl;				/* file is an application */

 rslt = (short *) getpargs(&args,sizeof(args));
 
 if (sendselflg)			/* file name selection occured? */
 {
   sendselflg = FALSE;			/* yes, don't do this again */
  
   p2cstr(sfr.fName);
   zltor(sfr.fName,filargs.filrem);	/* convert to remote form */
   SetIText(gethdl(SEND_ASFN,args.dlg),	/* display converted name */
      	    filargs.filrem);		/*  in "As" field */
   c2pstr(sfr.fName);			/* back to pascal form */
   setfilnams(SEND_ASFN,args.dlg); 	/* set file names since double */    
					/*  clicking fouls us */

   filargs.filflg &= ~FIL_RBDT;		/* turn off all of our flags */
   isappl = (strncmp(sfr.ftype.s,"APPL",4) == 0); /* application? */
   filargs.filflg |= (isappl) ?		/* update flags */
      	  (FIL_RSRC | FIL_BINA) :	/* application */
	  (FIL_DATA | FIL_TEXT);	/* not application */
 }
 
 switch (args.item) {			/* according to the item */
  
  case getNmList:			/* user hit file name */
  
    if (sendasflg)			/* "As" active? */
    {					/* yes... */
      sendasflg = FALSE;		/* deactivate "As" name */
      SelIText(args.dlg,SEND_INVT,0,256); /* activate invisible editText  */
    }
    sendselflg = TRUE;			/* next time around set buttons */
    break;				/* nothing more to do in this pass */

  case SEND_ASFN:			/* hit EditText for "AS" */
    sendasflg = TRUE;			/* let modal filter pass to us */
    break;

  case getOpen:				/* done? */
    setfilnams(SEND_ASFN,args.dlg); 	/* set file names */
    break;				/* done... */
 }
 setfilflgs(args.item,args.dlg);	/* check for and handle radio items */
 
 *rslt = args.item;			/* pass item back */
}
  

/* sendfilter - SFPGetFile event filter for "send file" dialog.
 *
 * This filter is the same form as a ModalDialog filter, it is used
 * internally by SFPGetFile's ModalDialog call.  Our filter allows the
 * user to select a file by typing the first character, which is a
 * normal function of SFGetFile but is broken when we use EditText in
 * our customized SFGetFile box.  Return 0x1000+char in itemhit to
 * SFGetFile instead of letting ModalDialog handle it with a call to
 * TextEdit.  Using a global flag "sendasflg" we decide to send the
 * character to TextEdit via ModalDialog, or to SFGetFile.
 *
 */
 
sendfilter()
{
 ModalFilterArgs args;
 BOOL *retval;				/* returned value */

 retval = (BOOL *) getpargs(&args,sizeof(args));
 
 *retval = FALSE;			/* default is to left Modal handle */
 if (args.theevent->what == keyDown)	/* key down? */
  if (!sendasflg)			/*  and the text isn't selected? */
  {					/* then use as file name selector */
    *args.itemhit = 0x1000 +		/* return char+0x1000 to */
      (args.theevent->message & 0x7f); 	/*  SFPGetfile... */
    *retval = TRUE;			/* let SFP handle it, not modal */
  }
}
 

/* recvmydlg - SFPPutFile item filter for "receive file" dialog.
 *
 *
 */

recvmydlg()
{
 SFdlgFilterArgs args;
 short *rslt;

 rslt = (short *) getpargs(&args,sizeof(args));
 *rslt = args.item; 
 
 switch (args.item) {
   case RECV_PROC:
     filargs.filflg &= ~FIL_DODLG;	/* no more dialogs for me! */  
     *rslt = RECV_RBTN;			/* did "OK" */
   case RECV_RBTN:
     setfilnams(0,args.dlg);		/* set names */   
     break;
  }
  setfilflgs(args.item,args.dlg);	/* check for and handle radios */
}
 
 
/* dosenddialog - Use SFPGetFile to fetch a file to send. */

short recvpt[] = {75,100};
short sendpt[] = {75,80};

dosenddialog(lclf,remf)
char *lclf[],*remf[];
{
 filargs.filflg = 0; 
 sendasflg = FALSE;			/* "AS" starts off inactive */
 sendselflg = TRUE;			/* need to update file buttons */
 sfr.fName[0] = 0;			/* clear our old stuff */
 SFPGetFile((Point *) sendpt,"",NILPROC,0, /* all file types, 2 filters */
      	    NILPTR,sendmydlg,&sfr,DLG_SEND,sendfilter);
 *lclf = filargs.fillcl;
 *remf = filargs.filrem;
 filargs.filvol = sfr.vRefNum;		/* remember volume number */  
 return(sfr.good);			/* pass back return */
} 


dorecvdialog(fn,lclf)
char *lclf[],*fn;
{
  int err;

  if (!(filargs.filflg & FIL_DODLG))	/* don't want to do dialogs? */
  {
   *lclf = "";				/* then use a null string */
   return;				/* and return now */
  }

  for (;;) {				/* keep trying */
    filargs.filflg &= ~(FIL_RBDT); 	/* clear file modes */
    filargs.filflg |= sfprtol(fn);	/* convert fn and set modes */
    SFPPutFile((Point *) recvpt,"Receive as:",fn,
      	      	recvmydlg,&sfr,DLG_RECV,NILPROC);
    *lclf = filargs.fillcl;
    filargs.filvol = sfr.vRefNum;	/* remember volume number */
    if (!sfr.good) {			/* CANCEL */
      cxseen = TRUE;			/* indicate cancel */
      return;
    } else {
      err = FSDelete(filargs.fillcl,filargs.filvol); /* delete if there */
      if (err == fnfErr)  		/* everything ok? */
        return;				/* yes, return now */
    }
    if (ioutil(err)) return;		/* until no error */
  }
}


/* setfiledialog - enter file settings dialog. */
 
#define FSET_ATTEND 4
#define FSET_UNATTEND 5
#define FSET_SUPERSEDE 6
#define FSET_NEWNAMES 7

setradpair(rid1,rid2,bool,dlg)
DialogPtr dlg;
{
  SetCtlValue(getctlhdl(rid1,dlg),bool ? btnOn : btnOff);
  SetCtlValue(getctlhdl(rid2,dlg),bool ? btnOff : btnOn);
}
  
setfiledialog()
{
  DialogPtr setfdlg;
  int item;

  setfdlg = GetNewDialog(DLG_FSET,NILPTR,(WindowPtr) -1);
  filargs.filflg = filargs.fildflg;	  /* use current defaults */
  ShowWindow(setfdlg);			  /* show it */
  
  for (;;) {
    setfilflgs(item,setfdlg);		  /* keep flags upto date */
    
    setradpair(FSET_ATTEND,FSET_UNATTEND,
      	      (filargs.filflg & FIL_DODLG),setfdlg);
    setradpair(FSET_SUPERSEDE,FSET_NEWNAMES,
      	      (filargs.filflg & FIL_OKILL),setfdlg);
	
    ModalDialog(NILPROC,&item);
    switch (item) {
      case OK:
      	filargs.fildflg = filargs.filflg; /* set default flags */
      case Cancel:
      	DisposDialog(setfdlg);		  /* all done with dialog */
	return;				  /* can go home... */

      case FSET_ATTEND:
      case FSET_UNATTEND:
      	filargs.filflg ^= FIL_DODLG;	/* toggle flag */
	break;
	
      case FSET_SUPERSEDE:
      case FSET_NEWNAMES:
      	filargs.filflg ^= FIL_OKILL;	  /* toggle flag */
	break;	
    }
  }    
}

initfilrecv()
{
  filargs.filflg = filargs.fildflg;	/* default flags are active */
  warn = !(filargs.filflg & FIL_OKILL);	/* set kermit flag */
  binary = (filargs.filflg & FIL_BINA); /* selected binary mode? */  
  filargs.filsiz = 0;			/* no known size */
}

initfilset()
{
  filargs.filvol = 0;			/* default volume is always default */
  filargs.fildflg = FIL_DATA | FIL_TEXT;  /* default file setting */
					  /*  if no settings file */
}  

dogetfdialog(remf)
char *remf[];
{
 DialogPtr getfdlg;
 ControlHandle getbhdl;
 Handle remfhdl;
 int item;

 getfdlg = GetNewDialog(DLG_GETF,NILPTR,(WindowPtr) -1);
 
 remfhdl = gethdl(GETF_REMF,getfdlg);
 getbhdl = getctlhdl(GETF_GETB,getfdlg);
 HiliteControl(getbhdl,255);		/* start with deactive Get button */
 
 ShowWindow(getfdlg);
 for (;;) {
   ModalDialog(NILPROC,&item);
   switch (item) {
     case OK:
       if (filargs.filrem[0] == '\0')	/* no file name? */
         break;				/* then they hit CR, don't allow */
       *remf = filargs.filrem;		/* fill in for return */     
       initfilrecv();			/* init recv flags */
     case Cancel:
       DisposDialog(getfdlg);
       return(item == OK);
     case GETF_REMF:
       GetIText(remfhdl,filargs.filrem);
       HiliteControl(getbhdl,(filargs.filrem[0] == 0) ? 255 : 0);
       break;		 
    }
  }   
}

/* sfprtol - translate remote file name to a local file name and
 *    	  and figure out the flags as well.
 */

#define RSXLEN 5			/* ".rsrc" length */

int sfprtol(fn)
char *fn;
{
  int l;

  if ((l = strlen(fn)) > RSXLEN &&	/* big enough? */
      (strcmp(&fn[l-RSXLEN],".rsrc") == 0 || /* and matches extension? */
       strcmp(&fn[l-RSXLEN],".RSRC") == 0))  /* either way? */
  {      
   fn[l-RSXLEN] = '\0';			/* so remove the extension */
   return(FIL_BINA | FIL_RSRC);		/* want rsrc and binary */
  }
  return(filargs.fildflg & FIL_RBDT);	/* else return default */
}
