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