|
|
1.1 root 1: /*
2: * K e r m i t File Transfer Utility
3: *
4: * UNIX Kermit, Columbia University, 1981, 1982, 1983
5: * Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
6: *
7: * Also: Jim Guyton, Rand Corporation
8: * Walter Underwood, Ford Aerospace
9: * Lauren Weinstein
10: *
11: * usage: kermit c|C [lbe line baud escapechar] to connect
12: * kermit s [d..iflbht line baud] file ... to send files
13: * kermit r [d..iflbht line baud] to receive files
14: *
15: * where c|C=connect, s=send, r=receive,
16: * d=debug, i=image mode, f=no filename conversion, l=tty line,
17: * b=baud rate, e=escape char, h=host (server) mode, t=tymnet mode.
18: *
19: * For remote Kermit, format is either:
20: * kermit r to receive files
21: * or kermit s file ... to send files
22: *
23: */
24:
25: /*
26: * Modification History:
27: *
28: * Oct. 17 Included fixes from Alan Crosswell (CUCCA) for IBM_UTS:
29: * - Changed MYEOL character from \n to \r.
30: * - Change char to int in bufill so getc would return -1 on
31: * EOF instead of 255 (-1 truncated to 8 bits)
32: * - Added read() in rpack to eat the EOL character
33: * - Added fflush() call in printmsg to force the output
34: * NOTE: The last three changes are not conditionally compiled
35: * since they should work equally well on any system.
36: *
37: * Changed Berkeley 4.x conditional compilation flag from
38: * UNIX4X to UCB4X.
39: * Added support for error packets and cleaned up the printing
40: * routines.
41: * Nov. 5, 1983 (Lauren Weinstein)
42: * Changed "write(0..." to "write(1..." in escape char code.
43: * Changed escape char processing to send the escape char to
44: * the remote system if entered twice in a row.
45: * Added support for the "Coherent" OS.
46: * Changed the "UCB4X" conditional to "UNIXL" to more correctly
47: * indicate its broader meaning.
48: * Added explicit "host" (server) flag ("-h") option.
49: * Misc. code cleanups.
50: * Jan. 21, 1984 (Lauren Weinstein)
51: * Added "suspend" (no hangup) command (^s) for Coherent.
52: * Added default tty line/speed settings for Coherent.
53: * Added Tymnet mode option ("-t").
54: * Apr. 6, 1984 (Lauren Weinstein)
55: * Misc. code cleanups.
56: * June 4, 1984 (Lauren Weinstein)
57: * Added ability to pass the first line of data to send over the
58: * connection via the command line (after the "-C" option flag).
59: */
60:
61: #include <stdio.h> /* Standard UNIX definitions */
62: #include <errno.h>
63:
64: /* Conditional compilation for different machines/operating systems */
65: /* One and only one of the following lines should be 1 */
66:
67: #define UNIXL 1 /* Various UNIX and UNIX look-alikes */
68: #define TOPS_20 0 /* TOPS-20 */
69: #define IBM_UTS 0 /* Amdahl UTS on IBM systems */
70: #define VAX_VMS 0 /* VAX/VMS (not yet implemented) */
71:
72: /* Conditional compilation for the different Unix and Unix-like variants */
73: /* 0 means don't compile it, nonzero means do */
74:
75: #if UNIXL
76: #define V6_LIBS 0 /* Use retrofit libraries */
77: #define NO_FIONREAD 1 /* Don't use ioctl for flushinput() */
78: #define NO_TANDEM 0 /* Don't use TANDEM line discipline (xon/xoff) */
79: #define MULTIREAD 1 /*++1++*/
80: /* True for multiple byte read/write in -c mode */
81: #define COHERENT 1 /* True for Coherent OS */
82: #define LOCK_LINE 1 /* Lock the line when in local mode */
83: #endif
84:
85: #if IBM_UTS
86: #define V6_LIBS 0 /* Use retrofit libraries */
87: #define NO_FIONREAD 1 /* Don't use ioctl for flushinput() */
88: #define NO_TANDEM 1 /* Don't use TANDEM line discipline (xon/xoff) */
89: #define MULTIREAD 0 /* True for multiple byte read/write in -c mode */
90: #endif
91:
92: #if V6_LIBS
93: #include <retrofit/sgtty.h>
94: #include <retrofit/signal.h>
95: #include <retrofit/setjmp.h>
96: #else
97: #include <sgtty.h>
98: #include <signal.h>
99: #include <setjmp.h>
100: #endif
101:
102: #if NO_TANDEM
103: #define TANDEM 0 /* define it to be nothing if it's unsupported */
104: #endif
105:
106: #if COHERENT
107: #define DEFLINE "/dev/modem" /* default tty comm line */
108: #define DEFSPEED 9600 /* default tty speed */
109: #endif
110:
111: /* Symbol Definitions */
112:
113: #define MAXPACKSIZ 94 /* Maximum packet size */
114: #define SOH 1 /* Start of header */
115: #define CR 13 /* ASCII Carriage Return */
116: #define SP 32 /* ASCII space */
117: #define DEL 127 /* Delete (rubout) */
118: #define ESCCHR '^' /* Default escape character for CONNECT */
119:
120: #define MAXTRY 20 /* Times to retry a packet */
121: #define MYQUOTE '#' /* Quote character I will use */
122: #define MYPAD 0 /* Number of padding characters I will need */
123: #define MYPCHAR 0 /* Padding character I need (NUL) */
124: #define NUL '\0'
125: #if IBM_UTS
126: #define MYEOL '\r' /* End-Of-Line character for UTS systems */
127: #else
128: #define MYEOL '\n' /* End-Of-Line character I need */
129: #endif
130:
131: #define MYTIME 10 /* (10) Seconds after which I should be timed out */
132: #define MAXTIM 60 /* (60) Maximum timeout interval */
133: #define MINTIM 2 /* (2) Minumum timeout interval */
134:
135: #define TRUE -1 /* Boolean constants */
136: #define FALSE 0
137:
138:
139: /* Macro Definitions */
140:
141: /*
142: * tochar: converts a control character to a printable one by adding a space.
143: *
144: * unchar: undoes tochar.
145: *
146: * ctl: converts between control characters and printable characters by
147: * toggling the control bit (ie. ^A becomes A and A becomes ^A).
148: */
149: #define tochar(ch) ((ch) + ' ')
150: #define unchar(ch) ((ch) - ' ')
151: #define ctl(ch) ((ch) ^ 64 )
152:
153:
154: /* Global Variables */
155:
156: int size, /* Size of present data */
157: rpsiz, /* Maximum receive packet size */
158: spsiz, /* Maximum send packet size */
159: pad, /* How much padding to send */
160: timint, /* Timeout for foreign host on sends */
161: n, /* Packet number */
162: numtry, /* Times this packet retried */
163: oldtry, /* Times previous packet retried */
164: ttyfd, /* File descriptor of tty for I/O, 0 if remote */
165: remote, /* -1 means we're a remote kermit */
166: image, /* -1 means 8-bit mode */
167: debug, /* indicates level of debugging output (0=none) */
168: filnamcnv, /* -1 means do file name case conversions */
169: filecount, /* Number of files left to send */
170: tflg; /* Flag for Tymnet mode */
171: logflg; /* Log connect transactions */
172: loglastch; /* last log character for cr elim */
173:
174: char state, /* Present state of the automaton */
175: padchar, /* Padding character to send */
176: eol, /* End-Of-Line character to send */
177: escchr, /* Connect command escape character */
178: quote, /* Quote character in incoming data */
179: **filelist, /* List of files to be sent */
180: *filnam, /* Current file name */
181: *ttyline, /* Pointer to tty line */
182: ttynbuff[128]; /* Name buffer for tty line */
183: inbuff[128]; /* remote data input buffer */
184: recpkt[MAXPACKSIZ], /* Receive packet buffer */
185: packet[MAXPACKSIZ]; /* Packet buffer */
186: ldata[1024]; /* First line of data to send over connection */
187:
188: FILE *fp, /* File pointer for current disk file */
189: *log; /* File pointer for Logfile */
190: int logfd; /* File descriptor for Logfile */
191:
192: jmp_buf env; /* Environment ptr for timeout longjump */
193:
194:
195: /*
196: * m a i n
197: *
198: * Main routine - parse command and options, set up the
199: * tty lines, and dispatch to the appropriate routine.
200: */
201:
202: main(argc,argv)
203: int argc; /* Character pointers to and count of */
204: char **argv; /* command line arguments */
205: {
206: char *cp; /* char pointer */
207: int speed, /* speed of assigned tty, */
208: cflg, rflg, sflg; /* flags for CONNECT, RECEIVE, SEND */
209: int hflg; /* flag for HOST (server) mode */
210: struct sgttyb
211: rawmode, /* Controlling tty raw mode */
212: cookedmode, /* Controlling tty cooked mode */
213: ttymode; /* mode of tty line in LINE option */
214:
215: if (argc < 2) usage(); /* Make sure there's a command line */
216:
217: cp = *++argv; argv++; argc -= 2; /* Set up pointers to args */
218:
219: /* Initialize these values and hope the first packet will get across OK */
220:
221: eol = CR; /* EOL for outgoing packets */
222: quote = '#'; /* Standard control-quote char "#" */
223: pad = 0; /* No padding */
224: padchar = NUL; /* Use null if any padding wanted */
225:
226: speed = hflg = cflg = logflg = sflg = 0; /* Turn off all parse flags */
227: loglastch = -1;
228: rflg = tflg = 0;
229: ttyline = 0; /* Default is remote mode */
230:
231: #if UNIXL /* Default to 7-bit masking, CRLF */
232: image = FALSE; /* translation and filename case */
233: filnamcnv = TRUE; /* conversion for UNIX systems */
234: #if COHERENT
235: ttyline = DEFLINE; /* set default tty line */
236: speed = DEFSPEED; /* set default tty speed */
237: #endif
238: #else
239: image = TRUE; /* Default to no processing for */
240: filnamcnv = FALSE; /* non-UNIX-type systems */
241: #endif
242:
243: escchr = ESCCHR; /* Default escape character */
244:
245: while ((*cp) != NUL) /* Parse characters in first arg */
246: switch (*cp++)
247: {
248: case 'c': /* c/C = Connect command */
249: case 'C':
250: cflg++;
251: if (*(cp-1) == 'C' && argc--) /* "C" command? */
252: strcpy(ldata, *argv++); /* get starting data line */
253: break;
254: case 's': sflg++; break; /* S = Send command */
255: case 'r': rflg++; break; /* R = Receive command */
256: case 'h': hflg++; break; /* H = Host (server) mode */
257: case 't': tflg++; break; /* T = Tymnet mode */
258: case 'd': /* D = Increment debug mode count */
259: debug++; break;
260:
261: case 'f':
262: filnamcnv = FALSE; /* F = don't do case conversion */
263: break; /* on filenames */
264:
265: case 'i': /* I = Image (8-bit) mode */
266: image = TRUE; break; /* (this is default for non-UNIX) */
267:
268: case 'l': /* L = specify tty line to use */
269: if (argc--) ttyline = *argv++;
270: else usage();
271: if (debug) printf("Line to remote host is %s\n", ttyline);
272: break;
273:
274: case 'L': /* write to log file */
275: logflg++; break;
276:
277: case 'e': /* E = specify escape char */
278: if (argc--) escchr = **argv++;
279: else usage();
280: if (debug) printf("Escape char is \"%c\"\n",escchr);
281: break;
282:
283: case 'b': /* B = specify baud rate */
284: #if UNIXL
285: if (argc--) speed = atoi(*argv++);
286: else usage();
287: if (debug) printf("Line speed to remote host is %d\n",speed);
288: break;
289: #else
290: printmsg("Speed setting not implemented.");
291: exit(1);
292: #endif
293: }
294:
295: /* Done parsing */
296:
297: if ((cflg+sflg+rflg) != 1) /* Only one command allowed */
298: usage();
299:
300: if (!hflg) /* local mode if "hflg" is FALSE */
301: {
302: ttyfd = open(ttyline,2); /* Open the tty line */
303: if (ttyfd < 0) {
304: printmsg("Cannot open %s", ttyline);
305: exit(1);
306: }
307: #if LOCK_LINE /* Set exclusive-use mode on line */
308: if (ioctl(ttyfd,TIOCEXCL,0) != 0)
309: {
310: printmsg("Cannot lock %s", ttyline);
311: exit(1);
312: }
313: #endif
314: remote = FALSE; /* Indicate we're in local mode */
315: }
316: else /* No LINE specified so we operate */
317: { /* in remote mode (ie. controlling */
318: ttyfd = 0; /* tty is the communications line) */
319: remote = TRUE;
320: }
321:
322:
323: /* Put the proper tty into the correct mode */
324:
325: if (remote) /* If remote, use controlling tty */
326: {
327: gtty(0,&cookedmode); /* Save current mode so we can */
328: gtty(0,&rawmode); /* restore it later */
329: rawmode.sg_flags |= (RAW|TANDEM);
330: rawmode.sg_flags &= ~(ECHO|CRMOD);
331: stty(0,&rawmode); /* Put tty in raw mode */
332: }
333: else /* Local, use assigned line */
334: {
335: gtty(ttyfd,&ttymode);
336: ttymode.sg_flags |= (RAW|TANDEM);
337: ttymode.sg_flags &= ~(ECHO|CRMOD);
338:
339: #if UNIXL /* Speed changing for UNIX only */
340: if (speed) /* User specified a speed? */
341: {
342: switch(speed) /* Get internal system code */
343: {
344: case 110: speed = B110; break;
345: case 150: speed = B150; break;
346: case 300: speed = B300; break;
347: case 1200: speed = B1200; break;
348: case 2400: speed = B2400; break;
349: case 4800: speed = B4800; break;
350: case 9600: speed = B9600; break;
351: case 19200: speed = B19200; break;
352:
353: default:
354: printmsg("Bad line speed.");
355: exit(1);
356: }
357: ttymode.sg_ispeed = speed;
358: ttymode.sg_ospeed = speed;
359: }
360: #endif /* UNIXL */
361:
362: stty(ttyfd,&ttymode); /* Put asg'd tty in raw mode */
363: }
364:
365:
366: /* All set up, now execute the command that was given. */
367:
368: if (debug)
369: {
370: printf("Debugging level = %d\n\n",debug);
371:
372: if (cflg) printf("Connect command\n\n");
373: if (sflg) printf("Send command\n\n");
374: if (rflg) printf("Receive command\n\n");
375: if (logflg) printf("Logging connect transactions\n\n");
376: }
377:
378: if (cflg) connect(); /* Connect command */
379:
380: if (sflg) /* Send command */
381: {
382: if (argc--) filnam = *argv++; /* Get file to send */
383: else
384: { if (remote)
385: stty(0,&cookedmode); /* Restore controlling tty's modes */
386: usage(); /* and give error */
387: }
388: fp = NULL; /* Indicate no file open yet */
389: filelist = argv; /* Set up the rest of the file list */
390: filecount = argc; /* Number of files left to send */
391: if (sendsw() == FALSE) /* Send the file(s) */
392: printmsg("Send failed."); /* Report failure */
393: else /* or */
394: printmsg("done."); /* success */
395: }
396:
397: if (rflg) /* Receive command */
398: {
399: if (recsw() == FALSE) /* Receive the file(s) */
400: printmsg("Receive failed.");
401: else /* Report failure */
402: printmsg("done."); /* or success */
403: }
404:
405: if (remote) stty(0,&cookedmode); /* Restore controlling tty's modes */
406: exit(0);
407: }
408:
409:
410: /*
411: * s e n d s w
412: *
413: * Sendsw is the state table switcher for sending files. It loops until
414: * either it finishes, or an error is encountered. The routines called
415: * by sendsw are responsible for changing the state.
416: *
417: */
418:
419: sendsw()
420: {
421: char sinit(), sfile(), sdata(), seof(), sbreak();
422:
423: state = 'S'; /* Send initiate is the start state */
424: n = 0; /* Initialize message number */
425: numtry = 0; /* Say no tries yet */
426: while(TRUE) /* Do this as long as necessary */
427: {
428: if (debug) printf("sendsw state: %c\n",state);
429: switch(state)
430: {
431: case 'S': state = sinit(); break; /* Send-Init */
432: case 'F': state = sfile(); break; /* Send-File */
433: case 'D': state = sdata(); break; /* Send-Data */
434: case 'Z': state = seof(); break; /* Send-End-of-File */
435: case 'B': state = sbreak(); break; /* Send-Break */
436: case 'C': return (TRUE); /* Complete */
437: case 'A': return (FALSE); /* "Abort" */
438: default: return (FALSE); /* Unknown, fail */
439: }
440: }
441: }
442:
443:
444: /*
445: * s i n i t
446: *
447: * Send Initiate: send this host's parameters and get other side's back.
448: */
449:
450: char sinit()
451: {
452: int num, len; /* Packet number, length */
453:
454: if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
455: spar(packet); /* Fill up init info packet */
456:
457: flushinput(); /* Flush pending input */
458:
459: spack('S',n,6,packet); /* Send an S packet */
460: switch(rpack(&len,&num,recpkt)) /* What was the reply? */
461: {
462: case 'N': return(state); /* NAK, try it again */
463:
464: case 'Y': /* ACK */
465: if (n != num) /* If wrong ACK, stay in S state */
466: return(state); /* and try again */
467: rpar(recpkt); /* Get other side's init info */
468:
469: if (eol == 0) eol = '\n'; /* Check and set defaults */
470: if (quote == 0) quote = '#';
471:
472: numtry = 0; /* Reset try counter */
473: n = (n+1)%64; /* Bump packet count */
474: return('F'); /* OK, switch state to F */
475:
476: case 'E': /* Error packet received */
477: prerrpkt(recpkt); /* Print it out and */
478: return('A'); /* abort */
479:
480: case FALSE: return(state); /* Receive failure, try again */
481:
482: default: return('A'); /* Anything else, just "abort" */
483: }
484: }
485:
486:
487: /*
488: * s f i l e
489: *
490: * Send File Header.
491: */
492:
493: char sfile()
494: {
495: int num, len; /* Packet number, length */
496: char filnam1[50], /* Converted file name */
497: *newfilnam, /* Pointer to file name to send */
498: *cp; /* char pointer */
499:
500: if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
501:
502: if (fp == NULL) /* If not already open, */
503: { if (debug) printf(" Opening %s for sending.\n",filnam);
504: fp = fopen(filnam,"r"); /* open the file to be sent */
505: if (fp == NULL) /* If bad file pointer, give up */
506: {
507: error("Cannot open file %s",filnam);
508: return('A');
509: }
510: }
511:
512: strcpy(filnam1, filnam); /* Copy file name */
513: newfilnam = cp = filnam1;
514: while (*cp != '\0') /* Strip off all leading directory */
515: if (*cp++ == '/') /* names (ie. up to the last /). */
516: newfilnam = cp;
517:
518: if (filnamcnv) /* Convert lower case to upper */
519: for (cp = newfilnam; *cp != '\0'; cp++)
520: if (*cp >= 'a' && *cp <= 'z')
521: *cp ^= 040;
522:
523: len = cp - newfilnam; /* Compute length of new filename */
524:
525: printmsg("Sending %s as %s",filnam,newfilnam);
526:
527: spack('F',n,len,newfilnam); /* Send an F packet */
528: switch(rpack(&len,&num,recpkt)) /* What was the reply? */
529: {
530: case 'N': /* NAK, just stay in this state, */
531: num = (--num<0 ? 63:num); /* unless it's NAK for next packet */
532: if (n != num) /* which is just like an ACK for */
533: return(state); /* this packet so fall thru to... */
534:
535: case 'Y': /* ACK */
536: if (n != num) return(state); /* If wrong ACK, stay in F state */
537: numtry = 0; /* Reset try counter */
538: n = (n+1)%64; /* Bump packet count */
539: size = bufill(packet); /* Get first data from file */
540: return('D'); /* Switch state to D */
541:
542: case 'E': /* Error packet received */
543: prerrpkt(recpkt); /* Print it out and */
544: return('A'); /* abort */
545:
546: case FALSE: return(state); /* Receive failure, stay in F state */
547:
548: default: return('A'); /* Something else, just "abort" */
549: }
550: }
551:
552:
553: /*
554: * s d a t a
555: *
556: * Send File Data
557: */
558:
559: char sdata()
560: {
561: int num, len; /* Packet number, length */
562:
563: if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
564: spack('D',n,size,packet); /* Send a D packet */
565: switch(rpack(&len,&num,recpkt)) /* What was the reply? */
566: {
567: case 'N': /* NAK, just stay in this state, */
568: num = (--num<0 ? 63:num); /* unless it's NAK for next packet */
569: if (n != num) /* which is just like an ACK for */
570: return(state); /* this packet so fall thru to... */
571:
572: case 'Y': /* ACK */
573: if (n != num) return(state); /* If wrong ACK, fail */
574: numtry = 0; /* Reset try counter */
575: n = (n+1)%64; /* Bump packet count */
576: if ((size = bufill(packet)) == EOF) /* Get data from file */
577: return('Z'); /* If EOF set state to that */
578: return('D'); /* Got data, stay in state D */
579:
580: case 'E': /* Error packet received */
581: prerrpkt(recpkt); /* Print it out and */
582: return('A'); /* abort */
583:
584: case FALSE: return(state); /* Receive failure, stay in D */
585:
586: default: return('A'); /* Anything else, "abort" */
587: }
588: }
589:
590:
591: /*
592: * s e o f
593: *
594: * Send End-Of-File.
595: */
596:
597: char seof()
598: {
599: int num, len; /* Packet number, length */
600: if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
601:
602: spack('Z',n,0,packet); /* Send a 'Z' packet */
603: switch(rpack(&len,&num,recpkt)) /* What was the reply? */
604: {
605: case 'N': /* NAK, just stay in this state, */
606: num = (--num<0 ? 63:num); /* unless it's NAK for next packet, */
607: if (n != num) /* which is just like an ACK for */
608: return(state); /* this packet so fall thru to... */
609:
610: case 'Y': /* ACK */
611: if (n != num) return(state); /* If wrong ACK, hold out */
612: numtry = 0; /* Reset try counter */
613: n = (n+1)%64; /* and bump packet count */
614: if (debug) printf(" Closing input file %s, ",filnam);
615: fclose(fp); /* Close the input file */
616: fp = NULL; /* Set flag indicating no file open */
617:
618: if (debug) printf("looking for next file...\n");
619: if (gnxtfl() == FALSE) /* No more files go? */
620: return('B'); /* if not, break, EOT, all done */
621: if (debug) printf(" New file is %s\n",filnam);
622: return('F'); /* More files, switch state to F */
623:
624: case 'E': /* Error packet received */
625: prerrpkt(recpkt); /* Print it out and */
626: return('A'); /* abort */
627:
628: case FALSE: return(state); /* Receive failure, stay in Z */
629:
630: default: return('A'); /* Something else, "abort" */
631: }
632: }
633:
634:
635: /*
636: * s b r e a k
637: *
638: * Send Break (EOT)
639: */
640:
641: char sbreak()
642: {
643: int num, len; /* Packet number, length */
644: if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
645:
646: spack('B',n,0,packet); /* Send a B packet */
647: switch (rpack(&len,&num,recpkt)) /* What was the reply? */
648: {
649: case 'N': /* NAK, just stay in this state, */
650: num = (--num<0 ? 63:num); /* unless NAK for previous packet, */
651: if (n != num) /* which is just like an ACK for */
652: return(state); /* this packet so fall thru to... */
653:
654: case 'Y': /* ACK */
655: if (n != num) return(state); /* If wrong ACK, fail */
656: numtry = 0; /* Reset try counter */
657: n = (n+1)%64; /* and bump packet count */
658: return('C'); /* Switch state to Complete */
659:
660: case 'E': /* Error packet received */
661: prerrpkt(recpkt); /* Print it out and */
662: return('A'); /* abort */
663:
664: case FALSE: return(state); /* Receive failure, stay in B */
665:
666: default: return ('A'); /* Other, "abort" */
667: }
668: }
669:
670:
671: /*
672: * r e c s w
673: *
674: * This is the state table switcher for receiving files.
675: */
676:
677: recsw()
678: {
679: char rinit(), rfile(), rdata(); /* Use these procedures */
680:
681: state = 'R'; /* Receive-Init is the start state */
682: n = 0; /* Initialize message number */
683: numtry = 0; /* Say no tries yet */
684:
685: while(TRUE)
686: {
687: if (debug) printf(" recsw state: %c\n",state);
688: switch(state) /* Do until done */
689: {
690: case 'R': state = rinit(); break; /* Receive-Init */
691: case 'F': state = rfile(); break; /* Receive-File */
692: case 'D': state = rdata(); break; /* Receive-Data */
693: case 'C': return(TRUE); /* Complete state */
694: case 'A': return(FALSE); /* "Abort" state */
695: }
696: }
697: }
698:
699:
700: /*
701: * r i n i t
702: *
703: * Receive Initialization
704: */
705:
706: char rinit()
707: {
708: int len, num; /* Packet length, number */
709:
710: if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
711:
712: switch(rpack(&len,&num,packet)) /* Get a packet */
713: {
714: case 'S': /* Send-Init */
715: rpar(packet); /* Get the other side's init data */
716: spar(packet); /* Fill up packet with my init info */
717: spack('Y',n,6,packet); /* ACK with my parameters */
718: oldtry = numtry; /* Save old try count */
719: numtry = 0; /* Start a new counter */
720: n = (n+1)%64; /* Bump packet number, mod 64 */
721: return('F'); /* Enter File-Receive state */
722:
723: case 'E': /* Error packet received */
724: prerrpkt(recpkt); /* Print it out and */
725: return('A'); /* abort */
726:
727: case FALSE: /* Didn't get packet */
728: spack('N',n,0,0); /* Return a NAK */
729: return(state); /* Keep trying */
730:
731: default: return('A'); /* Some other packet type, "abort" */
732: }
733: }
734:
735:
736: /*
737: * r f i l e
738: *
739: * Receive File Header
740: */
741:
742: char rfile()
743: {
744: int num, len; /* Packet number, length */
745: char filnam1[50]; /* Holds the converted file name */
746:
747: if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
748:
749: switch(rpack(&len,&num,packet)) /* Get a packet */
750: {
751: case 'S': /* Send-Init, maybe our ACK lost */
752: if (oldtry++ > MAXTRY) return('A'); /* If too many tries abort */
753: if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
754: { /* Yes, ACK it again with */
755: spar(packet); /* our Send-Init parameters */
756: spack('Y',num,6,packet);
757: numtry = 0; /* Reset try counter */
758: return(state); /* Stay in this state */
759: }
760: else return('A'); /* Not previous packet, "abort" */
761:
762: case 'Z': /* End-Of-File */
763: if (oldtry++ > MAXTRY) return('A');
764: if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
765: { /* Yes, ACK it again. */
766: spack('Y',num,0,0);
767: numtry = 0;
768: return(state); /* Stay in this state */
769: }
770: else return('A'); /* Not previous packet, "abort" */
771:
772: case 'F': /* File Header (just what we want) */
773: if (num != n) return('A'); /* The packet number must be right */
774: strcpy(filnam1, packet); /* Copy the file name */
775:
776: if (filnamcnv) /* Convert upper case to lower */
777: for (filnam=filnam1; *filnam != '\0'; filnam++)
778: if (*filnam >= 'A' && *filnam <= 'Z')
779: *filnam |= 040;
780:
781: if ((fp=fopen(filnam1,"w"))==NULL) /* Try to open a new file */
782: {
783: error("Cannot create %s",filnam1); /* Give up if can't */
784: return('A');
785: }
786: else /* OK, give message */
787: printmsg("Receiving %s as %s",packet,filnam1);
788:
789: spack('Y',n,0,0); /* Acknowledge the file header */
790: oldtry = numtry; /* Reset try counters */
791: numtry = 0; /* ... */
792: n = (n+1)%64; /* Bump packet number, mod 64 */
793: return('D'); /* Switch to Data state */
794:
795: case 'B': /* Break transmission (EOT) */
796: if (num != n) return ('A'); /* Need right packet number here */
797: spack('Y',n,0,0); /* Say OK */
798: return('C'); /* Go to complete state */
799:
800: case 'E': /* Error packet received */
801: prerrpkt(recpkt); /* Print it out and */
802: return('A'); /* abort */
803:
804: case FALSE: /* Didn't get packet */
805: spack('N',n,0,0); /* Return a NAK */
806: return(state); /* Keep trying */
807:
808: default: return ('A'); /* Some other packet, "abort" */
809: }
810: }
811:
812:
813: /*
814: * r d a t a
815: *
816: * Receive Data
817: */
818:
819: char rdata()
820: {
821: int num, len; /* Packet number, length */
822: if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
823:
824: if (tflg)
825: sleep(1); /* Delay for Tymnet */
826:
827: switch(rpack(&len,&num,packet)) /* Get packet */
828: {
829: case 'D': /* Got Data packet */
830: if (num != n) /* Right packet? */
831: { /* No */
832: if (oldtry++ > MAXTRY)
833: return('A'); /* If too many tries, abort */
834: if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
835: { /* Previous packet again? */
836: spack('Y',num,6,packet); /* Yes, re-ACK it */
837: numtry = 0; /* Reset try counter */
838: return(state); /* Don't write out data! */
839: }
840: else
841: return('A'); /* sorry, wrong number */
842: }
843: /* Got data with right packet number */
844: bufemp(packet,len); /* Write the data to the file */
845: spack('Y',n,0,0); /* Acknowledge the packet */
846: oldtry = numtry; /* Reset the try counters */
847: numtry = 0; /* ... */
848: n = (n+1)%64; /* Bump packet number, mod 64 */
849: return('D'); /* Remain in data state */
850:
851: case 'F': /* Got a File Header */
852: if (oldtry++ > MAXTRY)
853: return('A'); /* If too many tries, "abort" */
854: if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
855: { /* It was the previous one */
856: spack('Y',num,0,0); /* ACK it again */
857: numtry = 0; /* Reset try counter */
858: return(state); /* Stay in Data state */
859: }
860: else
861: return('A'); /* Not previous packet, "abort" */
862:
863: case 'Z': /* End-Of-File */
864: if (num != n) return('A'); /* Must have right packet number */
865: spack('Y',n,0,0); /* OK, ACK it. */
866: fclose(fp); /* Close the file */
867: n = (n+1)%64; /* Bump packet number */
868: return('F'); /* Go back to Receive File state */
869:
870: case 'E': /* Error packet received */
871: prerrpkt(recpkt); /* Print it out and */
872: return('A'); /* abort */
873:
874: case FALSE: /* Didn't get packet */
875: spack('N',n,0,0); /* Return a NAK */
876: return(state); /* Keep trying */
877:
878: default:
879: return('A'); /* Some other packet, "abort" */
880:
881: }
882: }
883:
884: /*
885: * c o n n e c t
886: *
887: * Establish a virtual terminal connection with the remote host, over an
888: * assigned tty line.
889: */
890:
891: connect()
892: {
893: int pid, /* Holds process id of child */
894: connected; /* TRUE if connection open */
895: int closemode = FALSE; /* TRUE if we closed connection */
896: register char *p;
897: register int count;
898: char filetoread [25];
899: char * ofp;
900: int rcount;
901: char bel = '\07',
902: c;
903: static char *heremsg = "\r\nYes, I'm still here... ^r version\r\n";
904: struct sgttyb
905: rawmode, /* Controlling tty raw mode */
906: cookedmode; /* Controlling tty cooked mode */
907:
908: if (remote) /* Nothing to connect to in remote */
909: { /* mode, so just return */
910: printmsg("No line specified for connection.");
911: return;
912: }
913:
914: gtty(0,&cookedmode); /* Save current mode so we can */
915: gtty(0,&rawmode); /* restore it later */
916: rawmode.sg_flags |= (RAW|TANDEM);
917: rawmode.sg_flags &= ~(ECHO|CRMOD);
918: stty(0,&rawmode); /* Put tty in raw mode */
919:
920: if (logflg) {
921: if ((logfd = open ("Log", 2)) == -1) {
922: if ((logfd = creat ("Log", 0644)) == -1) {
923: printmsg ("Cannot open log file\n");
924: stty(0, &cookedmode); /* Restore tty mode */
925: return(-1);
926: }
927: }
928: if ((lseek (logfd, 0L, 2) == -1)) {
929: printmsg ("Cannot seek to end of log file\n");
930: stty(0, &cookedmode); /* Restore tty mode */
931: return (-1);
932: }
933: }
934:
935: pid = fork(); /* Start fork to get typeout from remote host */
936:
937: if (pid) /* Parent: send type-in to remote host */
938: {
939: printmsg("connected...\r");
940: connected = TRUE; /* Put us in "connect mode" */
941:
942: if (*ldata) /* initial data line to send? */
943: { write(ttyfd, ldata, strlen(ldata));
944: write(ttyfd, "\r", 1); /* ending <CR> */
945: }
946:
947: while (connected)
948: {
949: read(0,&c,1); /* Get a character */
950: if ((c&0177) == escchr) /* Check for escape character */
951: {
952: read(0,&c,1);
953: if ((c&0177) == escchr)
954: write(ttyfd,&c,1);
955: else
956: switch (c&0177)
957: {
958: case 'c': /* close connection */
959: case 'C':
960: closemode = TRUE; /* we're closing connection */
961: #if COHERENT
962: ioctl(ttyfd, TIOCHPCL); /* set hangup on modem */
963:
964: case 's': /* suspend connection */
965: case 'S':
966: #endif
967: connected = FALSE;
968: write(1,"\r\n",2);
969: break;
970:
971: case 'r': /* read a file and send it */
972: ofp = filetoread;
973: write (0, "File to send: ", strlen("File to send: "));
974: read(0, &c, 1);
975: while (c != '\r') {
976: write(0, &c, 1);
977: *ofp++ = c;
978: read(0, &c, 1);
979: }
980: *ofp++ = '\0';
981: write(0,"\r\n",2);
982: fp = fopen (filetoread,"r");
983:
984: if (fp == NULL) {
985: error("Cannot open file %s\r\n",filetoread);
986: } else {
987: while((c = getc(fp)) != EOF) {
988: if (c == '\n')
989: c = '\r';
990: write(ttyfd, &c, 1);
991: }
992: fclose(fp);
993: }
994: fp = NULL;
995: break;
996:
997: case 'h':
998: case 'H':
999: write(1,heremsg, strlen(heremsg));
1000: break;
1001:
1002: default:
1003: write(1,"\7",1); /* bell */
1004: break;
1005: }
1006: }
1007: else
1008: { /* If not escape charater, */
1009: write(ttyfd,&c,1); /* write it out */
1010: c = NUL; /* Nullify it (why?) */
1011: }
1012: }
1013: kill(pid,9); /* Done, kill the child */
1014: wait(0); /* and bury him */
1015: stty(0,&cookedmode); /* Restore tty mode */
1016: printmsg(closemode ? "disconnected." : "suspended.");
1017: return; /* Done */
1018: }
1019: else /* Child does the reading from the remote host */
1020: {
1021: for(;;) /* Do this forever */
1022: {
1023: #if MULTIREAD
1024: count = rcount = read(ttyfd, inbuff, 128); /* read chars */
1025: #else
1026: count = read(ttyfd, inbuff, 1); /* read one char */
1027: #endif
1028: if (count > 0){
1029: #if COHERENT
1030: for (p = inbuff; count--; p++)
1031: *p &= 0177; /* strip parity for IBM display */
1032: #endif
1033: #if MULTIREAD
1034: write(1, inbuff, rcount); /* write chars */
1035: if (logflg) {
1036: p = inbuff;
1037: for (count = rcount; count--; p++) {
1038: if (*p != '\r')
1039: write (logfd, p, 1);
1040: }
1041: }
1042: #else
1043: write(1, inbuff, 1); /* write char */
1044:
1045: if (logflg)
1046: if (inbuff [0] != '\r');
1047: write (logfd, inbuff, 1); /* log chars */
1048: #endif
1049: }
1050: }
1051: }
1052: }
1053:
1054: /*
1055: * KERMIT utilities.
1056: */
1057:
1058: clkint() /* Timer interrupt handler */
1059: {
1060: longjmp(env, TRUE); /* Tell rpack to give up */
1061: }
1062:
1063:
1064: /*
1065: * s p a c k
1066: *
1067: * Send a Packet
1068: */
1069:
1070: spack(type,num,len,data)
1071: char type, *data;
1072: int num, len;
1073: {
1074: int i; /* Character loop counter */
1075: char chksum, buffer[100]; /* Checksum, packet buffer */
1076: register char *bufp; /* Buffer pointer */
1077:
1078: if (debug>1) /* Display outgoing packet */
1079: {
1080: if (data != NULL)
1081: data[len] = '\0'; /* Null-terminate data to print it */
1082: printf(" spack type: %c\n",type);
1083: printf(" num: %d\n",num);
1084: printf(" len: %d\n",len);
1085: if (data != NULL)
1086: printf(" data: \"%s\"\n",data);
1087: }
1088:
1089: bufp = buffer; /* Set up buffer pointer */
1090: for (i=1; i<=pad; i++) write(ttyfd,&padchar,1); /* Issue any padding */
1091:
1092: *bufp++ = SOH; /* Packet marker, ASCII 1 (SOH) */
1093: *bufp++ = tochar(len+3); /* Send the character count */
1094: chksum = tochar(len+3); /* Initialize the checksum */
1095: *bufp++ = tochar(num); /* Packet number */
1096: chksum += tochar(num); /* Update checksum */
1097: *bufp++ = type; /* Packet type */
1098: chksum += type; /* Update checksum */
1099:
1100: for (i=0; i<len; i++) /* Loop for all data characters */
1101: {
1102: *bufp++ = data[i]; /* Get a character */
1103: chksum += data[i]; /* Update checksum */
1104: }
1105: chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
1106: *bufp++ = tochar(chksum); /* Put it in the packet */
1107: *bufp = eol; /* Extra-packet line terminator */
1108: write(ttyfd, buffer,bufp-buffer+1); /* Send the packet */
1109: }
1110:
1111: /*
1112: * r p a c k
1113: *
1114: * Read a Packet
1115: */
1116:
1117: rpack(len,num,data)
1118: int *len, *num; /* Packet length, number */
1119: char *data; /* Packet data */
1120: {
1121: int i, done; /* Data character number, loop exit */
1122: char t, /* Current input character */
1123: type, /* Packet type */
1124: cchksum, /* Our (computed) checksum */
1125: rchksum; /* Checksum received from other host */
1126:
1127: #if UNIXL /* TOPS-20 can't handle timeouts... */
1128: if (setjmp(env)) return FALSE; /* Timed out, fail */
1129: signal(SIGALRM,clkint); /* Setup the timeout */
1130: if ((timint > MAXTIM) || (timint < MINTIM)) timint = MYTIME;
1131: alarm(timint);
1132: #endif /* UNIXL */
1133:
1134: while (t != SOH) /* Wait for packet header */
1135: {
1136: read(ttyfd,&t,1);
1137: t &= 0177; /* Handle parity */
1138: }
1139:
1140: done = FALSE; /* Got SOH, init loop */
1141: while (!done) /* Loop to get a packet */
1142: {
1143: read(ttyfd,&t,1); /* Get character */
1144: if (!image) t &= 0177; /* Handle parity */
1145: if (t == SOH) continue; /* Resynchronize if SOH */
1146: cchksum = t; /* Start the checksum */
1147: *len = unchar(t)-3; /* Character count */
1148:
1149: read(ttyfd,&t,1); /* Get character */
1150: if (!image) t &= 0177; /* Handle parity */
1151: if (t == SOH) continue; /* Resynchronize if SOH */
1152: cchksum = cchksum + t; /* Update checksum */
1153: *num = unchar(t); /* Packet number */
1154:
1155: read(ttyfd,&t,1); /* Get character */
1156: if (!image) t &= 0177; /* Handle parity */
1157: if (t == SOH) continue; /* Resynchronize if SOH */
1158: cchksum = cchksum + t; /* Update checksum */
1159: type = t; /* Packet type */
1160:
1161: for (i=0; i<*len; i++) /* The data itself, if any */
1162: { /* Loop for character count */
1163: read(ttyfd,&t,1); /* Get character */
1164: if (!image) t &= 0177; /* Handle parity */
1165: if (t == SOH) continue; /* Resynch if SOH */
1166: cchksum = cchksum + t; /* Update checksum */
1167: data[i] = t; /* Put it in the data buffer */
1168: }
1169: data[*len] = 0; /* Mark the end of the data */
1170:
1171: read(ttyfd,&t,1); /* Get last character (checksum) */
1172: rchksum = unchar(t); /* Convert to numeric */
1173: read(ttyfd,&t,1); /* get EOL character and toss it */
1174: if (!image) t &= 0177; /* Handle parity */
1175: if (t == SOH) continue; /* Resynchronize if SOH */
1176: done = TRUE; /* Got checksum, done */
1177: }
1178:
1179: #if UNIXL
1180: alarm(0); /* Disable the timer interrupt */
1181: #endif
1182:
1183: if (debug>1) /* Display incoming packet */
1184: {
1185: if (data != NULL)
1186: data[*len] = '\0'; /* Null-terminate data to print it */
1187: printf(" rpack type: %c\n",type);
1188: printf(" num: %d\n",*num);
1189: printf(" len: %d\n",*len);
1190: if (data != NULL)
1191: printf(" data: \"%s\"\n",data);
1192: }
1193: /* Fold in bits 7,8 to compute */
1194: cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
1195:
1196: if (cchksum != rchksum) return(FALSE);
1197:
1198: return(type); /* All OK, return packet type */
1199: }
1200:
1201:
1202: /*
1203: * b u f i l l
1204: *
1205: * Get a bufferful of data from the file that's being sent.
1206: * Only control-quoting is done; 8-bit & repeat count prefixes are
1207: * not handled.
1208: */
1209:
1210: bufill(buffer)
1211: char buffer[]; /* Buffer */
1212: {
1213: int i, /* Loop index */
1214: t; /* Char read from file */
1215: char t7; /* 7-bit version of above */
1216:
1217: i = 0; /* Init data buffer pointer */
1218: while((t = getc(fp)) != EOF) /* Get the next character */
1219: {
1220: t7 = t & 0177; /* Get low order 7 bits */
1221:
1222: if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */
1223: { /* special handling? */
1224: if (t=='\n' && !image)
1225: { /* Do LF->CRLF mapping if !image */
1226: buffer[i++] = quote;
1227: buffer[i++] = ctl('\r');
1228: }
1229: buffer[i++] = quote; /* Quote the character */
1230: if (t7 != quote)
1231: {
1232: t = ctl(t); /* and uncontrolify */
1233: t7 = ctl(t7);
1234: }
1235: }
1236: if (image)
1237: buffer[i++] = t; /* Deposit the character itself */
1238: else
1239: buffer[i++] = t7;
1240:
1241: if (i >= spsiz-8) return(i); /* Check length */
1242: }
1243: if (i==0) return(EOF); /* Wind up here only on EOF */
1244: return(i); /* Handle partial buffer */
1245: }
1246:
1247:
1248: /*
1249: * b u f e m p
1250: *
1251: * Put data from an incoming packet into a file.
1252: */
1253:
1254: bufemp(buffer,len)
1255: char buffer[]; /* Buffer */
1256: int len; /* Length */
1257: {
1258: int i; /* Counter */
1259: char t; /* Character holder */
1260:
1261: for (i=0; i<len; i++) /* Loop thru the data field */
1262: {
1263: t = buffer[i]; /* Get character */
1264: if (t == MYQUOTE) /* Control quote? */
1265: { /* Yes */
1266: t = buffer[++i]; /* Get the quoted character */
1267: if ((t & 0177) != MYQUOTE) /* Low order bits match quote char? */
1268: t = ctl(t); /* No, uncontrollify it */
1269: }
1270: if (t==CR && !image) /* Don't pass CR if in image mode */
1271: continue;
1272:
1273: putc(t,fp);
1274: }
1275: }
1276:
1277:
1278: /*
1279: * g n x t f l
1280: *
1281: * Get next file in a file group
1282: */
1283:
1284: gnxtfl()
1285: {
1286: if (debug) printf(" gnxtfl: filelist = \"%s\"\n",*filelist);
1287: filnam = *(filelist++);
1288: if (filecount-- == 0) return FALSE; /* If no more, fail */
1289: else return TRUE; /* else succeed */
1290: }
1291:
1292:
1293: /*
1294: * s p a r
1295: *
1296: * Fill the data array with my send-init parameters
1297: *
1298: */
1299:
1300: spar(data)
1301: char data[];
1302: {
1303: data[0] = tochar(MAXPACKSIZ); /* Biggest packet I can receive */
1304: data[1] = tochar(MYTIME); /* When I want to be timed out */
1305: data[2] = tochar(MYPAD); /* How much padding I need */
1306: data[3] = ctl(MYPCHAR); /* Padding character I want */
1307: data[4] = tochar(MYEOL); /* End-Of-Line character I want */
1308: data[5] = MYQUOTE; /* Control-Quote character I send */
1309: }
1310:
1311:
1312: /* r p a r
1313: *
1314: * Get the other host's send-init parameters
1315: *
1316: */
1317:
1318: rpar(data)
1319: char data[];
1320: {
1321: spsiz = unchar(data[0]); /* Maximum send packet size */
1322: timint = unchar(data[1]); /* When I should time out */
1323: pad = unchar(data[2]); /* Number of pads to send */
1324: padchar = ctl(data[3]); /* Padding character to send */
1325: eol = unchar(data[4]); /* EOL character I must send */
1326: quote = data[5]; /* Incoming data quote character */
1327: }
1328:
1329:
1330: /*
1331: * f l u s h i n p u t
1332: *
1333: * Dump all pending input to clear stacked up NACK's.
1334: * (Implemented only for Berkeley Unix at this time).
1335: */
1336:
1337: #if UNIXL&(~NO_FIONREAD)
1338: flushinput()
1339: {
1340: #if COHERENT
1341: int count; /* Number of bytes ready to read */
1342: #else
1343: long int count; /* Number of bytes ready to read */
1344: #endif
1345: long int i; /* Number of bytes to read in loop */
1346:
1347: #if COHERENT
1348: ioctl(ttyfd, TIOCQUERY, &count); /* See how many bytes pending read */
1349: #else
1350: ioctl(ttyfd, FIONREAD, &count); /* See how many bytes pending read */
1351: #endif
1352:
1353: if (!count) return; /* If zero, then no input to flush */
1354:
1355: while (count) /* Loop till all are flushed */
1356: {
1357: i = (count<sizeof(recpkt)) ? /* Read min of count and size of */
1358: count : sizeof(recpkt); /* the read buffer */
1359: read(ttyfd, recpkt, i); /* Read a bunch */
1360: count -= i; /* Subtract from amount to read */
1361: }
1362: }
1363: #else
1364: flushinput() /* Null version */
1365: {}
1366: #endif /* UNIXL&(~FIONREAD) */
1367:
1368:
1369: /*
1370: * Kermit printing routines:
1371: *
1372: * usage - print command line options showing proper syntax
1373: * printmsg - like printf with "Kermit: " prepended
1374: * error - like printmsg if local kermit; sends a error packet if remote
1375: * prerrpkt - print contents of error packet received from remote host
1376: */
1377:
1378: /*
1379: * u s a g e
1380: *
1381: * Print summary of usage info and quit
1382: */
1383:
1384: usage()
1385: {
1386: #if UNIXL
1387: printf("Usage: kermit c|C [lbe line baud esc.char] (connect mode)\n");
1388: printf("or: kermit s[diflbht line baud] file ... (send mode)\n");
1389: printf("or: kermit r[diflbht line baud] (receive mode)\n");
1390: #else
1391: printf("Usage: kermit c|C [le line esc.char] (connect mode)\n");
1392: printf("or: kermit s[diflht line] file ... (send mode)\n");
1393: printf("or: kermit r[diflht line] (receive mode)\n");
1394: #endif
1395: exit(1);
1396: }
1397:
1398: /*
1399: * p r i n t m s g
1400: *
1401: * Print message on standard output if not remote.
1402: */
1403:
1404: /*VARARGS1*/
1405: printmsg(fmt, a1, a2, a3, a4, a5)
1406: char *fmt;
1407: {
1408: if (!remote)
1409: {
1410: printf("kermit: ");
1411: printf(fmt,a1,a2,a3,a4,a5);
1412: printf("\n");
1413: fflush(stdout); /* force output (UTS needs it) */
1414: }
1415: }
1416:
1417: /*
1418: * e r r o r
1419: *
1420: * Print error message.
1421: *
1422: * If local, print error message with printmsg.
1423: * If remote, send an error packet with the message.
1424: */
1425:
1426: /*VARARGS1*/
1427: error(fmt, a1, a2, a3, a4, a5)
1428: char *fmt;
1429: {
1430: char msg[80];
1431: int len;
1432:
1433: if (remote)
1434: {
1435: sprintf(msg,fmt,a1,a2,a3,a4,a5); /* Make it a string */
1436: len = strlen(msg);
1437: spack('E',n,len,msg); /* Send the error packet */
1438: }
1439: else
1440: printmsg(fmt, a1, a2, a3, a4, a5);
1441:
1442: return;
1443: }
1444:
1445: /*
1446: * p r e r r p k t
1447: *
1448: * Print contents of error packet received from remote host.
1449: */
1450: prerrpkt(msg)
1451: char *msg;
1452: {
1453: printf("kermit: aborting with following error from remote host:\n%s\n",
1454: msg);
1455: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.