|
|
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.