/* @(#)utils.c 1.1 1/26/85 */ #include "kermit.h" #ifndef AMIGA # include # include #endif /* !AMIGA */ static jmp_buf env; /* Environment */ static unsigned int timint; /* Timeout for foreign host on sends */ /* * Library externals. */ #ifdef unix extern unsigned alarm (); #endif extern VOID longjmp (); /* * Various KERMIT utilities. */ clkint () { /* timer interrupt handlr */ longjmp (env, TRUE); /* tell rpack to give up */ } /* * tochar converts a control character to a printable one by adding * a space */ #ifndef tochar char tochar (ch) char ch; { return (ch + ' '); /* make sure not a control char */ } #endif /* * unchar undoes tochar */ #ifndef unchar char unchar (ch) char ch; { return (ch - ' '); /* restore char */ } #endif /* * ctl turns a control character into a printable character by toggling the * control bit (ie. ^A becomes A and A becomes ^A). */ #ifndef ctl char ctl (ch) char ch; { return (ch ^ 0100); /* toggle the control bit */ } #endif /* * s p a c k */ VOID spack (type, num, len, data) char type; char *data; int num; int len; { int i; char chksum; char buffer[100]; register char *bufp; bufp = buffer; /* issue necessary padding */ for (i = 1; i <= pad; i++) { (VOID) write (remfd, &padchar, (unsigned int)1); } *bufp++ = SOH; /* packet marker, ASCII 1 (SOH) */ chksum = tochar (len + 3); /* initialize the checksum */ *bufp++ = tochar (len + 3); /* send the character count */ chksum = chksum + tochar (num); /* ini checksum */ *bufp++ = tochar (num); /* packet number */ chksum = chksum + type; *bufp++ = type; /* packet type */ /* loop for all data characters */ for (i = 0; i < len && i < (MAXPACK - 1); i++) { *bufp++ = data[i]; chksum = chksum + data[i]; } chksum = (((chksum >> 6) & 3) + chksum) & 077; *bufp++ = tochar (chksum); /* checksum */ *bufp = eol; /* extra packet line terminator */ (VOID) write (remfd, buffer, (unsigned int) (bufp - buffer + 1)); if (tflg) { printf ("%c", type); fflush (stdout); } } /* * r p a c k */ char rpack (len, num, data) int *len; int *num; char *data; { int i; int fld; char chksum; auto char inchar; char type; DBUG_ENTER ("rpack"); DBUG_2 ("rcv", "beginning packet receive"); i = 0; chksum = 0; inchar = 0; #ifdef unix if (setjmp (env)) { DBUG_2 ("timeout", "read timed out"); if (tflg) { printf ("T"); fflush (stdout); } DBUG_RETURN (FALSE); } (VOID) signal (SIGALRM, clkint); if ((timint > MAXTIM) || (timint < MINTIM)) { timint = MYTIME; } (VOID) alarm (timint); #endif DBUG_3 ("rfd", "reading from fildes %d", remfd); while (inchar != SOH) { DBUG_3 ("read", "looking for SOH (%x)", (int) SOH); (VOID) read (remfd, &inchar, 1); DBUG_3 ("read", "read got '%x'", (int) inchar); } DBUG_2 ("SOH", "found packet header"); for (fld = 1; fld <= 5; fld++) { DBUG_3 ("fld", "current fld %d", fld); if (fld != 5 || i != 0) { /* no char or no data */ DBUG_3 ("read", "read from %d", remfd); (VOID) read (remfd, &inchar, 1); DBUG_3 ("read", "read got %3.3o", inchar); if (inchar == SOH) { DBUG_2 ("resync", "found SOH, resync"); fld = 0; /* resynch if SOH */ if (tflg) { printf ("R"); fflush (stdout); } } } DBUG_3 ("fld", "process field %d", fld); if (fld <= 3) { chksum = chksum + inchar; /* accumulate checksum */ } switch (fld) { case 0: chksum = 0; break; /* restart loop */ case 1: *len = unchar (inchar) - 3; DBUG_3 ("rcv", "count %d", *len); break; /* character count */ case 2: *num = unchar (inchar); DBUG_3 ("rcv", "packet %d", *num); break; /* packet number */ case 3: type = inchar; DBUG_3 ("rcv", "type '%c'", type); break; /* packet type */ case 4: for (i = 0; i < *len && i < (MAXPACK - 1); i++) { if (i != 0) { (VOID) read (remfd, &inchar, 1); if (inchar == SOH) { /* get a char */ fld = -1; break; } } chksum = chksum + inchar; /* add it to checksum */ data[i] = inchar; /* normal character */ } if (i < (MAXPACK - 1) && *len >= 0) { data[*len] = 0; } else { data[0] = 0; } DBUG_3 ("rcv", "data \"%s\"", data); break; case 5: chksum = (((chksum >> 6) & 3) + chksum) & 077; DBUG_3 ("chk", "checksum %d", chksum); break; } } #ifdef unix (VOID) alarm (0); /* disable timer interrupt */ #endif if (chksum != unchar (inchar)) { /* check the checksum */ printf ("X"); DBUG_4 ("chk", "checksum %o, should be %o", inchar, tochar (chksum)); DBUG_RETURN (FALSE); } DBUG_3 ("rcv", "got %c packet", type); if (tflg) { printf ("%c", type); fflush (stdout); } DBUG_RETURN (type); /* return packet type */ } /* * b u f i l l */ int bufill (buffer) char buffer[]; { int i; char inchar; DBUG_ENTER ("bufill"); i = 0; /* init data buffr pointr */ while (read (fd, &inchar, 1) > 0) { /* get the next character */ inchar = inchar & 0177; if (inchar < SP || inchar == DEL || inchar == quote) { if (inchar == '\n') { /* newline, squeeze CR */ buffer[i++] = quote; buffer[i++] = ctl ('\r'); } buffer[i++] = quote; if (inchar != quote) inchar = ctl (inchar); } buffer[i++] = inchar; if ((i >= spsiz - 8) || (i >= MAXPACK - 8)) { DBUG_RETURN (i); } } if (i == 0) { i = EOF; } DBUG_RETURN (i); } /* * b u f e m p */ VOID bufemp (buffer, ifd, len) char buffer[]; int ifd; int len; { int i; char outchar; DBUG_ENTER ("bufemp"); DBUG_4 ("buf", "ifd %d len %d", ifd, len); for (i = 0; i < len; i++) { outchar = buffer[i]; if (outchar == MYQUOTE) { outchar = buffer[++i]; if (outchar != MYQUOTE) { outchar = ctl (outchar); } } if (outchar != 015) { /* don't pass CR */ (VOID) write (ifd, &outchar, 1); } } DBUG_VOID_RETURN; } /* * g e t f i l */ int getfil (filenm) char *filenm; { DBUG_ENTER ("getfil"); if (filenm[0] == '\0') { fd = creat (packet, 0644); /* if filename known, use it */ } else { fd = creat (filenm, 0644); /* else use sourcefile name */ } DBUG_RETURN (fd > 0); /* return false if fle won't open */ } /* * g n x t f l */ int gnxtfl () { register int rtnval; DBUG_ENTER ("gnxtfl"); filnam = *(filelist++); if (filnam == 0) { rtnval = FALSE; } else { rtnval = TRUE; } DBUG_RETURN (rtnval); } /* * spar fills the data array with appropriate send-init paramaters */ VOID spar (data) char data[]; { data[0] = tochar (MAXPACK); /* biggest packet I can receive */ data[1] = tochar (MYTIME); /* when I want to be timed out */ data[2] = tochar (MYPAD); /* how much padding I need */ data[3] = ctl (MYPCHAR); /* padding characer I want */ data[4] = tochar (MYEOL); /* end-o-line character I want */ data[5] = MYQUOTE; /* quot character I send */ } /* * rpar gets the other host's send-init parameters */ VOID rpar (data) char data[]; { spsiz = unchar (data[0]); /* maximum send packe size */ timint = unchar (data[1]); /* when I should time out */ pad = unchar (data[2]); /* number of pads to send */ padchar = ctl (data[3]); /* padding character to send */ eol = unchar (data[4]); /* EOL character I must send */ quote = data[5]; /* incoming data quote char */ } /* * NAME * * tolower --- convert an alpha character to lowercase * * KEY WORDS * * extension libraries * tolower * character functions * * DESCRIPTION * * Converts an alpha character to lowercase. * * USAGE * * char tolower(ch) * char ch; * * RETURNED VALUE(S) * * If the input character is an alphabetic character then tolower * returns the lowercase version of that character. Otherwise * it simply returns the character passed to it. * * PROGRAMMER * * Fred Fish * Tempe, Az 85281 * (602) 966-8871 * * INTERNALS * * Since the possibility exists that the native character set may * not be ASCII, "tolower" maintains an internal table of the characters * which it considers to be alphabetic, along with their mappings to * lowercase. * */ #ifndef unix static char *alphas[] = { "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" }; char tolower (ch) char ch; { char *chp; chp = alphas[0]; while (*chp != NULL) { if (*chp++ == ch) { return (*chp); } else { chp++; } } return (ch); } #endif #ifdef AMIGA /* this is the public domain getopt from Usenet -- why re-invent the wheel? */ /* From: keith@seismo.UUCP (Keith Bostic) 23 Aug 84 In April of this year, Henry Spencer (utzoo!henry) released a public domain version of getopt (USG, getopt(3)). Well, I've been trying to port some USG dependent software and it didn't seem to work. The problem ended up being that the USG version of getopt has some external variables that aren't mentioned in the documentation. Anyway, to fix these problems, I rewrote the public version of getopt. It has the following advantages: -- it includes those "unknown" variables -- it's smaller/faster 'cause it doesn't use the formatted output conversion routines in section 3 of the UNIX manual. -- the error messages are the same as S5's. -- it has the same side-effects that S5's has. -- the posted bug on how the error messages are flushed has been implemented. (posting by Tony Hansen; pegasus!hansen) I won't post the man pages since Henry already did; a special note, it's not documented in the S5 manual that the options ':' and '?' are illegal. It should be obvious, but I thought I'd mention it... This software was derived from binaries of S5 and the S5 man page, and is (I think?) totally (I'm pretty sure?) compatible with S5 and backward compatible to Henry's version. Keith Bostic ARPA: keith@seismo UUCP: seismo!keith *UNIX is a trademark of Bell Laboratories */ /* * get option letter from argument vector */ /* * ADR, 8/7/85 -- opterr if set to 0 disables the printing of * error messages. Fixed this code to reflect that */ int opterr = 1, /* do or don't print the error message */ optind = 1, /* index into parent argv vector */ optopt; /* character checked for validity */ char *optarg; /* argument associated with option */ #define BADCH (int)'?' #define EMSG "" #define tell(msg) if (opterr) { fprintf (stderr, "%s%s%c\n", *nargv, msg, \ (char) optopt); } else /* no ; */ /* ADR, changed to used fprintf, not fputs */ getopt(nargc,nargv,ostr) int nargc; char **nargv, *ostr; { static char *place = EMSG; /* option letter processing */ register char *oli; /* option letter list index */ char *strchr(); /* ADR -- was index */ if(!*place) { /* update scanning pointer */ if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF); if (*place == '-') { /* found "--" */ ++optind; return(EOF); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) { if(!*place) ++optind; tell(": illegal option -- "); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) optarg = place; /* no white space */ else if (nargc <= ++optind) { /* no arg */ place = EMSG; tell(": option requires an argument -- "); } else optarg = nargv[optind]; /* white space */ place = EMSG; ++optind; } return(optopt); /* dump back option letter */ } #endif /* AMIGA */