/* Edit by Bill on Thu May 30, 00:18 */ /* Do error handling, neaten up comments, and some code. */ /* Edit by Bill on Wed May 15, 16:09 */ /* Make zrtol call common sfprtol, .RSRC overrides default settings */ /* ckmfio.c, Mon Apr 29 17:48, Edit by Bill*2 */ /* Put null in translated name to tie it off. */ /* Make author text of new file to ???? instead of random string */ /* Do flushvol after closing a file */ /* Bill C., Apr 24 */ /* Change zchin to allow sending of files with high order bits on */ /* Bill C., Apr 22 */ /* Add error handling (informing) for more cases, e.g. can't delete */ /* Bill C., Apr 22 */ /* Fix Resource/Data fork stuff. Uppercase things where needed */ /* ckzmac.c, Thu Apr 21 17:19, Edit by Bill */ /* Ignore trying to close an not-openend file, driver does it alot */ /* ckzmac.c, Thu Apr 11 21:18, Edit by Bill */ /* Catch error in ZOPENO when trying to open an existing file */ /* ckzmac.c, Thu Apr 14 20:07, Edit by Bill */ /* Translate calls with ZCTERM to go to the console routines */ /* * File ckmfio -- Kermit file system support for the Macintosh * * 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. * */ /* Definitions of some Unix system commands */ char *DIRCMD = ""; /* For directory listing */ char *DELCMD = ""; /* For file deletion */ char *TYPCMD = ""; /* For typing a file */ char *SPACMD = ""; /* Space/quota of current directory */ char *SPACM2 = ""; /* For space in specified directory */ char *WHOCMD = ""; /* For seeing who's logged in */ /* Functions (n is one of the predefined file numbers from ckermi.h): zopeni(n,name) -- Opens an existing file for input. zopeno(n,name) -- Opens a new file for output. zclose(n) -- Closes a file. zchin(n) -- Gets the next character from an input file. zsout(n,s) -- Write a null-terminated string to output file, buffered. zsoutl(n,s) -- Like zsout, but appends a line terminator. zsoutx(n,s,x) -- Write x characters to output file, unbuffered. zchout(n,c) -- Add a character to an output file, unbuffered. zchki(name) -- Check if named file exists and is readable, return size. zchko(name) -- Check if named file can be created. znewn(name,s) -- Make a new unique file name based on the given name. zdelet(name) -- Delete the named file. zxpand(string) -- Expands the given wildcard string into a list of files. znext(string) -- Returns the next file from the list in "string". zxcmd(cmd) -- Execute the command in a lower fork. zclosf() -- Close input file associated with zxcmd()'s lower fork. zrtol(n1,n2) -- Convert remote filename into local form. zltor(n1,n2) -- Convert local filename into remote form. */ #include "ckcker.h" /* Kermit definitions */ #include "ckmdef.h" /* Common Mac module definitions */ #include "ckmres.h" /* Resource defs */ #include "ckcdeb.h" /* Debug() and tlog() defs */ #include /* Get islower and toupper */ #include "mac/quickdraw.h" #include "mac/osintf.h" #include "mac/toolintf.h" /* These should all be settable by the File Settings Menu */ char *authortext="????"; /* String to use as "author" of file */ #define FS_WIND 1 /* file is a text edit buffer */ #define FS_OPEN 2 /* file has been opened */ #define FS_RSRC 4 /* opened in resource fork */ #define FS_DATA 8 #define FS_PIPE 16 /* file is a memory buffer */ typedef struct { PLONG frefnum; /* file reference number (pascal) */ int fstatus; /* file status bits */ char *fpipeptr; /* pipe pointer */ } MACFILE; MACFILE fp[ZNFILS] = { /* File information */ {0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0}}; char pipebuf[128]; /* there's a limit to pipes! */ /* Z O P E N I -- Open an existing file for input. * * The file name has been returned from and the volume reference * number set by SFGetFile. * * Returns: * TRUE: file opened ok * FALSE: some error. */ zopeni(n,name) int n; char *name; { int err; register MACFILE *fpp; if (chkfn(n)) { printerr("At zopeni file is already open ",n); return(FALSE); } fpp = &fp[n]; if (n == ZCTERM) { /* Terminal open? */ if (chkfn(ZIFILE)) /* Check current ZOFILE */ printerr("ZIFILE already open...: ",n); fp[ZIFILE].fstatus = FS_WIND; /* redirect... here it is */ fpp->fstatus = FS_WIND; /* Indicate this is open too */ return(conopen()); /* Return from low level open */ } if (n == ZSYSFN) /* trying to open a pipe? */ return(zxcmd(name)); /* yes... */ if (n == ZIFILE && /* opening input file? */ (filargs.filflg & FIL_RSRC)) /* and they said resource? */ err = OpenRF(name,filargs.filvol,&fpp->frefnum); else /* else some other channel or data */ err = FSOpen(name,filargs.filvol,&fpp->frefnum); if (err != noErr) /* check for open error */ return(ioutil(err)); /* failed... */ fpp->fstatus = FS_OPEN | ( /* set flags */ (filargs.filflg & FIL_RSRC) ? FS_RSRC : FS_DATA); GetEOF(fpp->frefnum,&filargs.filsiz); /* set size for screen */ return(TRUE); /* Return success */ SYM(ZOPENI); } /* Z O P E N O -- Open a new file for output. * * Returns: * TRUE: File opened ok * FALSE: some error has occured or channel occupied. * */ zopeno(n,name) int n; char *name; { int err; char *forktext; FInfo finfo; register MACFILE *fpp; if (chkfn(n)) { printerr("zopeno - file is already open: ",n); return(FALSE); } fpp = &fp[n]; if (n == ZCTERM || n == ZSTDIO) { /* Terminal open? */ if (chkfn(ZOFILE)) /* Check current ZOFILE */ printerr("ZOFILE already open...: ",n); fp[ZOFILE].fstatus = FS_WIND; /* yes, redirect... here it is */ fpp->fstatus = FS_WIND; /* Indicate this is open too */ return(conopen()); /* Return from low level open */ } if (n == ZOFILE && (filargs.filflg & FIL_RSRC)) forktext = "APPL"; else forktext = "TEXT"; /* Make fork reflect fork choice */ err = Create(name,filargs.filvol,authortext,forktext); if (err == dupFNErr) { /* duplicate file? */ if (!ioutil(FSDelete(name, /* Try to delete it */ filargs.filvol))) /* checking for failure */ return(FALSE); /* failed... */ err = Create(name,filargs.filvol, /* recreate */ authortext,forktext); } if (err != noErr) /* some error? */ return(ioutil(err)); /* yes, do message and return */ /* set file's folder from filargs.filfldr which is either the */ /* applications folder or the settings file folder */ GetFInfo(name,filargs.filvol,&finfo); /* read current finder info */ finfo.fdFldr = filargs.filfldr; /* set new folder */ SetFInfo(name,filargs.filvol,&finfo); /* and tell system about it */ if (n == ZOFILE && /* is it our transferred file? */ (filargs.filflg & FIL_RSRC)) /* want to use resource fork? */ err = OpenRF(name,filargs.filvol, /* yes... */ &fpp->frefnum); else /* else data, or some other file */ err = FSOpen(name,filargs.filvol, &fpp->frefnum); if (err != noErr) /* able to open? */ return(ioutil(err)); /* no. fail return now */ fp[n].fstatus = FS_OPEN | ((filargs.filflg & FIL_RSRC) ? FS_RSRC : FS_DATA); return(TRUE); /* done ok */ SYM(ZOPENO); } /* Z C L O S E -- Close the given file. * * Returns: * TRUE: file closed ok. * FLASE: some error has occured. * */ zclose(n) int n; { int err = noErr; register MACFILE *fpp; if (!chkfn(n)) /* is it opened? */ return(FALSE); /* no return now */ fpp = &fp[n]; if (fpp->fstatus == FS_WIND) /* is this a window? */ fp[ZCTERM].fstatus = 0; /* yes, clear ZCTERM */ else if (fpp->fstatus == FS_PIPE) /* is this a pipe? */ fp[ZSYSFN].fstatus = 0; /* yes, no pipe now, clear ZSYSFN */ else { err = FSClose(fpp->frefnum); /* else use OS close */ if (err != noErr) /* and if that worked */ err = FlushVol(NILPTR, /* flush buffers in case write */ filargs.filvol); } fpp->fstatus = 0; /* clear out status word */ if (n == ZOFILE || n == ZIFILE) /* turn off both flags */ filargs.filflg &= ~(FIL_RSRC | FIL_DATA); return(ioutil(err)); /* return according to io operations */ SYM(ZCLOSE); } /* Z C H I N -- Get a character from the input file. * * Returns: * 0: Ok * -1: EOF (or other error). * */ zchin(n,c) int n; char *c; { int err; PLONG rdcnt; /* pascal long */ register MACFILE *fpp; if (!chkfn(n)) return(0); fpp = &fp[n]; if (fpp->fstatus == FS_WIND) { /* a window? */ printerr("zchin called for FS_WIND file: ",n); return(0); } if (fpp->fstatus == FS_PIPE) /* a pipe? */ if (*(fpp->fpipeptr) == '\0') /* is this eo-pipe? */ return(-1); /* yes, fail return */ else { *c = *(fpp->fpipeptr)++; /* read character */ return(0); /* success */ } rdcnt = 1; err = FSRead(fpp->frefnum,&rdcnt,c); if (err == eofErr) return(-1); /* Failure return */ return(ioutil(err) ? 0 : -1); /* success or unknown failure */ SYM(ZCHIN); } /* Z S O U T -- Write a string to the given file, buffered. * * Returns: * 0: OK * -1: Error * */ zsout(n,s) int n; char *s; { PLONG wrcnt; /* pascal long */ if (n == ZCTERM || fp[n].fstatus == FS_WIND) return(conol(s)); wrcnt = (long) strlen(s); return(ioutil(FSWrite(fp[n].frefnum,&wrcnt,s)) ? 0 : -1); SYM(ZSOUT); } /* Z S O U T L -- Write string to file, with line terminator, buffered. * * Returns: * 0: OK * -1: Error * */ zsoutl(n,s) int n; char *s; { PLONG wrcnt; /* pascal long */ int err; if (n == ZCTERM || fp[n].fstatus == FS_WIND) return(conoll(s)); wrcnt = (long) strlen(s); err = FSWrite(fp[n].frefnum,&wrcnt,s); if (err == noErr) { wrcnt = 2; err = FSWrite(fp[n].frefnum,&wrcnt,"\r\n"); } return(ioutil(err) ? 0 : -1); SYM(ZSOUTL); } /* Z S O U T X -- Write x characters to file, unbuffered. * * Returns: * 0: OK * -1: Error */ zsoutx(n,s,x) int n, x; char *s; { if (n == ZCTERM || fp[n].fstatus == FS_WIND) return(conxo(s,x)); return(ioutil(FSWrite(fp[n].frefnum,(PLONG *) &x,s)) ? 0 : -1); SYM(ZSOUTX); } /* Z C H O U T -- Add a character to the given file. * * Returns: * 0: OK * -1: Error */ zchout(n,c) int n; char c; { PLONG wrcnt; /* pascal long */ int err; if (n == ZCTERM || fp[n].fstatus == FS_WIND) return(conoc(c)); /* Then send to console routine */ wrcnt = 1; err = FSWrite(fp[n].frefnum,&wrcnt,&c); if (err != noErr) /* error occured? */ sstate = 'a'; /* yes, abort protocol */ return (ioutil(err) ? 0 : -1); /* else return code */ SYM(ZCOUT); } /* C H K F N -- Internal function to verify file number is ok. * * Returns: * TRUE - file is open * FALSE - file is not open * * Issues an error message if the file number is not in range. * */ chkfn(n) int n; { switch (n) { case ZCTERM: case ZSTDIO: case ZIFILE: case ZOFILE: case ZDFILE: case ZTFILE: case ZPFILE: case ZSYSFN: case ZSFILE: break; default: debug(F101,"chkfn: file number out of range","",n); printerr("chkfn - file number not in range: ",n); return(FALSE); /* ugh */ } return((fp[n].fstatus != 0)); /* if open, fstatus is nonzero */ SYM(CHKFN); } /* Z C H K I -- Check if input file exists and is readable. * * Returns: * >= 0 if the file can be read (returns the size). * -1 if file doesn't exist or can't be accessed, * -2 if file exists but is not readable (e.g. a directory file). * -3 if file exists but protected against read access. */ zchki(name) char *name; { PLONG size; int err; FileParam info; if (strcmp(name,"stdin") == 0) /* stdin is a pipe */ return(strlen(pipebuf)); /* return size of buffer */ c2pstr(name); /* convert to a pascal string */ info.ioFVersNum = 0; /* No version number */ info.ioFDirIndex = 0; /* Use the file name */ info.ioNamePtr = name; /* Point to the file name */ info.ioVRefNum = filargs.filvol; /* Volume number */ err = PBGetFInfo(&info,FALSE); /* Get info on file */ p2cstr(name); /* put the name back */ if (err == fnfErr) /* file not found? */ return(-1); /* then that is what they want */ if (err != noErr) /* any other error? */ printerr("zchki failed: ",err); /* tell me about it */ size = (filargs.filflg & FIL_RSRC) ? /* if thinking about RSRC */ info.ioFlRPyLen : info.ioFlPyLen; /* return that size, else DATA */ return(size); /* did ok */ SYM(ZCHKI); } /* Z C H K O -- Check if output file can be created. * * Returns * 0: Write OK * -1: write permission for the file should be denied. */ zchko(name) char *name; { char volname[100]; VolumeParam info; info.ioVolIndex = 0; /* Use the vol ref num only */ info.ioNamePtr = volname; /* Pointer to the volume name */ info.ioVRefNum = filargs.filvol; /* Volume reference number */ if (!ioutil(PBGetVInfo(&info,0))) /* Get info on vol, synchronously */ return(-1); /* failed... */ if ((info.ioVAtrb & 0x8000) != 0) /* Write locked? */ return(-1); /* yes... */ return(0); /* else success */ SYM(ZCHKO); } /* Z D E L E T -- Delete the named file. */ zdelet(name) char *name; { int err; err = FSDelete(name,filargs.filvol); if (err != fnfErr && err != noErr) /* file not found... I guess thats */ return(ioutil(err)); /* ok... */ return(TRUE); /* well done */ SYM(ZDELETE); } /* Z R T O L -- Convert remote filename into local form. * * Check here to see if this should go into the resource fork (.rsrc) * or into the data fork (.data). * */ zrtol(name,name2) char *name, *name2; { strcpy(name2,name); /* copy name to destination */ if (filargs.filflg & (FIL_DODLG)) /* selected by user? */ return; /* won't be called but... */ filargs.filflg &= ~(FIL_RBDT); /* clear out flags */ filargs.filflg |= sfprtol(name2); /* convert name2 and set flags */ binary = (filargs.filflg & FIL_BINA); /* selected binary mode? */ return; SYM(ZRTOL); } /* Z L T O R -- Convert filename from local format to common form. */ zltor(name,name2) char *name, *name2; { int dc = 0; while (*name != '\0') { if (*name == ' ') name++; /* Skip spaces */ else if ((*name == '.') && (++dc > 1)) { *name2++ = 'X'; /* Just 1 dot */ name++; } else *name2++ = (islower(*name)) ? toupper(*name++) : *name++; } *name2++ = '\0'; /* deposit final null */ return; SYM(ZLTOR); } /* Z C H D I R -- Change directory (used on the Mac to switch vols) */ zchdir(dirnam) char *dirnam; { int err; err = SetVol(dirnam,0); /* set default volume */ if (err == noErr) { screen(SCR_TN,0,0l,dirnam); filargs.filvol = 0; /* make default */ } else screen(SCR_TN,0,0l,"Can't set volume"); return(err == noErr); /* return ok or fail */ SYM(ZCHDIR); } /* Z X C M D -- Run a system command so its output can be read like a file. * * Used on the MAC to implement MAC settings commands -- commands from a * remote system when in server mode that change internal variables. * */ #define CMD_RSRC 1 #define CMD_DATA 2 #define CMD_TEXT 3 #define CMD_BINA 4 #define CMD_UNK 255 zxcmd(comand) char *comand; { int sc; fp[ZIFILE].fstatus = FS_PIPE; /* set input from pipe */ fp[ZIFILE].fpipeptr = pipebuf; /* init pointer to buffer */ switch (sc = getcmd(comand)) { case CMD_RSRC: case CMD_DATA: strcpy(pipebuf,"Default Fork set OK\n"); filargs.filflg &= ~(FIL_RSRC | FIL_DATA); /* turn off */ filargs.filflg |= (sc == CMD_RSRC) ? FIL_RSRC : FIL_DATA; return(TRUE); /* success */ case CMD_TEXT: case CMD_BINA: strcpy(pipebuf,"Default Mode set OK\n"); filargs.filflg &= ~(FIL_TEXT | FIL_BINA); filargs.filflg |= (sc == CMD_BINA) ? FIL_BINA : FIL_TEXT; return(TRUE); /* ok */ default: return(FALSE); /* fail, unknown */ } SYM(ZXCMD); } char *cmdtab[] = { "fork rsrc", "fork data", "mode binary", "mode text" }; int toktab[] = { CMD_RSRC, CMD_DATA, CMD_BINA, CMD_TEXT }; #define NTOKS (sizeof (toktab)/sizeof(int)) getcmd(cmd) char *cmd; { int k; for (k=0; k < NTOKS; k++) if (strcmp(cmdtab[k],cmd) == 0) return(toktab[k]); /* and return ID */ return(CMD_UNK); /* else unknown */ SYM(GETCMD); } /* Z C L O S F - wait for the child fork to terminate and close the pipe. */ zclosf() { return; } int znfirst = 0; char *zname; /* Z X P A N D -- Expand a wildcard string into an array of strings * * Returns the number of files that match fn1, with data structures set up * so that first file (if any) will be returned by the next znext() call. */ zxpand(fn) char *fn; { znfirst = 0; /* Say this is the first time thru */ zname = fn; /* Save a pointer to that name */ return(1); /* Say one file matches */ SYM(ZXPAND); } /* Z N E X T -- Get name of next file from list created by zxpand(). * * Returns >0 if there's another file, with its name copied into the * arg string, or 0 if no more files in list. */ znext(fn) char *fn; { if (znfirst++ == 0) { strcpy(fn,zname); /* Get the file's name */ return(1); /* No more files in this wildcard */ } else return(0); SYM(ZNEXT); } /* Z N E W N -- Make a new name for the given file */ znewn(fn,s) char *fn, **s; { char *extp; int ver; strcpy(*s,fn); /* copy in the name */ if (strlen(*s) > 59) /* don't allow long names */ *s[59] = '\0'; /* it breaks the finder */ extp = *s+strlen(*s); /* find position of extension */ *extp++ = '.'; /* add in the dot now */ for (ver=0; ver < 99; ver++) /* I'll try this many names */ { NumToString(ver,extp); /* add in the number */ if (zchki(*s) == -1) /* is this file known? */ return; /* no, made a good one! */ } fatal("znewn failed to find unique name in 64 attempts",0); return; SYM(ZNEWN); } /* zkself() - Kill self (reboot). On other machines does a logout. * Flush volumes and reboot. Called by remote BYE. * */ zkself() { DrvQEl *drvqe; char vname[255]; PLONG vfreeb; int vrefnum,err; for (drvqe = (DrvQEl *) DrvQHdr->qHead; /* handle on drive q */ drvqe != NULL; /* while still something */ drvqe = drvqe->qLink) /* step to next */ { /* for each drive */ err = GetVInfo(drvqe->dQDrive,vname,&vrefnum,&vfreeb); if (err = noErr) err = FlushVol(NILPTR,vrefnum); /* flush the volume given refnum */ else if (err != nsvErr) screen(SCR_TN,0,0l,"Remote cmd: GetVinfo returned unknown code"); } asm(" reset"); /* reset the machine */ asm(" jmp /40000A"); /* boot address */ return(FALSE); SYM(ZKSELF); } /* ioutil - handle the result from an IO call, checking for an * error return and displaying an appropriate error * message. Returns TRUE if no error occured, FALSE * otherwise. */ struct { int errnum; char *errstr; } ioerrs[] = { {dirFulErr,"Directory is full"}, {dskFulErr,"Disk is full"}, {wPrErr,"Diskette is write protected"}, {fLckdErr,"File is software locked"}, {vLckdErr,"Volume is software locked"}, {fBsyErr,"File is busy"}, {opWrErr,"File is already open with write permission"}, {0,NILPTR} }; ioutil(err) int err; { int e; if (err == noErr) return(TRUE); for (e = 0; ioerrs[e].errnum != 0 && ioerrs[e].errnum != err; e++); if (ioerrs[e].errstr == NILPTR) /* anything there? */ printerr("Unknown IO error: ",err); else printerr(ioerrs[e].errstr,0); return(FALSE); SYM(IOUTIL); }