|
|
1.1 ! root 1: char *protv = "C-Kermit Protocol Module 5A(043), 25 Dec 91"; /* -*-C-*- */ ! 2: ! 3: /* C K C P R O -- C-Kermit Protocol Module, in Wart preprocessor notation. */ ! 4: /* ! 5: Author: Frank da Cruz ([email protected], [email protected]), ! 6: Columbia University Center for Computing Activities. ! 7: First released January 1985. ! 8: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New ! 9: York. Permission is granted to any individual or institution to use, copy, or ! 10: redistribute this software so long as it is not sold for profit, provided this ! 11: copyright notice is retained. ! 12: */ ! 13: #include "ckcdeb.h" ! 14: #include "ckcasc.h" ! 15: #include "ckcker.h" ! 16: /* ! 17: Note -- This file may also be preprocessed by the Unix Lex program, but ! 18: you must indent the above #include statements before using Lex, and then ! 19: restore them to the left margin in the resulting C program before compilation. ! 20: Also, the invocation of the "wart()" function below must be replaced by an ! 21: invocation of the "yylex()" function. It might also be necessary to remove ! 22: comments in the %%...%% section. ! 23: */ ! 24: ! 25: /* State definitions for Wart (or Lex) */ ! 26: %states ipkt rfile rattr rdata ssinit ssfile ssattr ssdata sseof sseot ! 27: %states serve generic get rgen ! 28: ! 29: /* External C-Kermit variable declarations */ ! 30: extern char *versio, *srvtxt, *cmarg, *cmarg2, **cmlist; ! 31: extern char filnam[], ttname[]; ! 32: extern CHAR sstate, *rpar(), encbuf[], *srvptr, *data; ! 33: extern int timint, pkttim, nfils, hcflg, xflg, flow, mdmtyp, network; ! 34: extern int cxseen, czseen, server, srvdis, local, displa, bctu, bctr, quiet; ! 35: extern int tsecs, parity, backgrd, nakstate, atcapu, wslotn, winlo; ! 36: extern int wslots, success, xitsta, rprintf, discard, cdtimo, keep; ! 37: extern long speed; ! 38: extern char *DIRCMD, *DIRCM2, *DELCMD, *TYPCMD, *SPACMD, *SPACM2, *WHOCMD; ! 39: extern CHAR *rdatap; ! 40: extern struct zattr iattr; ! 41: #ifdef DYNAMIC ! 42: extern CHAR *srvcmd; ! 43: #else ! 44: extern CHAR srvcmd[]; ! 45: #endif /* DYNAMIC */ ! 46: ! 47: #ifndef NOSPL ! 48: extern int cmdlvl; ! 49: #else ! 50: extern int tlevel; ! 51: #endif /* NOSPL */ ! 52: ! 53: #ifdef NOMSEND ! 54: extern int sndsrc; ! 55: #endif /* NOMSEND */ ! 56: ! 57: /* Flags for the ENABLE and DISABLE commands */ ! 58: extern int ! 59: en_cwd, en_del, en_dir, en_fin, en_get, en_bye, ! 60: en_hos, en_sen, en_spa, en_set, en_typ, en_who; ! 61: ! 62: /* Global variables declared here */ ! 63: ! 64: int what = W_NOTHING; /* What we're doing */ ! 65: ! 66: /* Local variables */ ! 67: ! 68: static char vstate = 0; /* Saved State */ ! 69: static char vcmd = 0; /* Saved Command */ ! 70: ! 71: static int x; /* General-purpose integer */ ! 72: static char *s; /* General-purpose string pointer */ ! 73: ! 74: /* Macros - Note, BEGIN is predefined by Wart (and Lex) as "state = ", */ ! 75: /* BEGIN is NOT a GOTO! */ ! 76: #define TINIT if (tinit() < 0) return(-9) ! 77: #define SERVE TINIT; nakstate = 1; what = W_NOTHING; BEGIN serve ! 78: #define RESUME if (server) { SERVE; } else { sleep(2); return(0); } ! 79: #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); quiet=x; \ ! 80: return(1) ! 81: ! 82: %% ! 83: /* Protocol entry points, one for each start state (sstate) */ ! 84: /* nakstate = 1 means we're in a receiving state, in which we can send NAKs */ ! 85: ! 86: s { TINIT; /* Do Send command */ ! 87: if (sinit()) BEGIN ssinit; ! 88: else RESUME; } ! 89: ! 90: v { TINIT; nakstate = 1; BEGIN get; } /* Receive */ ! 91: r { TINIT; vstate = get; vcmd = 0; sipkt('I'); BEGIN ipkt; } /* Get */ ! 92: c { TINIT; vstate = rgen; vcmd = 'C'; sipkt('I'); BEGIN ipkt; } /* Host */ ! 93: k { TINIT; vstate = rgen; vcmd = 'K'; sipkt('I'); BEGIN ipkt; } /* Kermit */ ! 94: g { TINIT; vstate = rgen; vcmd = 'G'; sipkt('I'); BEGIN ipkt; } /* Generic */ ! 95: ! 96: x { sleep(1); SERVE; } /* Be a Server */ ! 97: ! 98: a { if (!data) TINIT; /* "ABEND" -- Tell other side. */ ! 99: errpkt((CHAR *)"User cancelled"); ! 100: success = 0; ! 101: return(0); } /* Return from protocol. */ ! 102: ! 103: /* Dynamic states: <current-states>input-character { action } */ ! 104: ! 105: <rgen,get,serve>S { /* Receive Send-Init packet. */ ! 106: if (state == serve && !en_sen) { /* Not allowed if in server mode */ ! 107: errpkt((CHAR *)"SEND disabled"); /* and SEND is disabled. */ ! 108: SERVE; ! 109: } else { /* OK to go ahead. */ ! 110: nakstate = 1; /* Can send NAKs from here. */ ! 111: rinit(rdatap); /* Set parameters */ ! 112: bctu = bctr; /* Switch to agreed-upon block check */ ! 113: timint = pkttim; /* Switch to per-packet timer */ ! 114: chktimo(); /* Check & adjust timeout */ ! 115: resetc(); /* Reset counters */ ! 116: rtimer(); /* Reset timer */ ! 117: what = W_RECV; /* Remember we're receiving */ ! 118: BEGIN rfile; /* Go into receive-file state */ ! 119: } ! 120: } ! 121: ! 122: /* States in which we get replies back from commands sent to a server. */ ! 123: /* Complicated because direction of protocol changes, packet number */ ! 124: /* stays at zero through I-G-S sequence, and complicated even more by */ ! 125: /* sliding windows buffer allocation. */ ! 126: ! 127: <ipkt>Y { /* Get ack for I-packet */ ! 128: spar(rdatap); /* Set parameters */ ! 129: #ifdef COMMENT ! 130: getsbuf(winlo = 0); /* Set window-low back to zero */ ! 131: #else ! 132: winlo = 0; ! 133: #endif ! 134: if (vcmd) { /* If sending a generic command */ ! 135: scmd(vcmd,(CHAR *)cmarg); /* Do that */ ! 136: vcmd = 0; /* and then un-remember it. */ ! 137: } else if (vstate == get) srinit(); /* If sending GET command, do that */ ! 138: winlo = 0; /* Again! */ ! 139: nakstate = 1; /* Can send NAKs from here. */ ! 140: BEGIN vstate; /* Switch to desired state */ ! 141: } ! 142: ! 143: <ipkt>E { /* Ignore Error reply to I packet */ ! 144: #ifdef COMMENT ! 145: getsbuf(winlo = 0); /* Set window-low back to zero */ ! 146: #else ! 147: winlo = 0; ! 148: #endif ! 149: if (vcmd) { /* in case other Kermit doesn't */ ! 150: scmd(vcmd,(CHAR *)cmarg); /* understand I-packets. */ ! 151: vcmd = 0; /* Otherwise act as above... */ ! 152: } else if (vstate == get) srinit(); ! 153: winlo = 0; /* Back to packet 0 again. */ ! 154: freerpkt(winlo); /* Discard the Error packet. */ ! 155: nakstate = 1; /* Can send NAKs from here. */ ! 156: BEGIN vstate; ! 157: } ! 158: ! 159: <get>Y { /* Resend of previous I-pkt ACK, same seq number! */ ! 160: srinit(); ! 161: } ! 162: ! 163: /* States in which we're being a server */ ! 164: ! 165: <serve>I { /* Get I-packet */ ! 166: spar(rdatap); /* Set parameters from it */ ! 167: ack1(rpar()); /* Respond with our own parameters */ ! 168: pktinit(); /* Reinitialize packet numbers */ ! 169: } ! 170: ! 171: <serve>R { /* Get Receive-Init (GET) */ ! 172: debug(F100,"<serve>R","",0); ! 173: if (!en_get) { /* Only if not disabled! */ ! 174: errpkt((CHAR *)"GET disabled"); ! 175: SERVE; ! 176: } else { /* OK to go ahead. */ ! 177: srvptr = srvcmd; /* Point to server command buffer */ ! 178: decode(rdatap,putsrv,0); /* Decode the GET command into it */ ! 179: /* Accept multiple filespecs */ ! 180: cmarg2 = ""; /* Don't use cmarg2 */ ! 181: cmarg = ""; /* Don't use cmarg */ ! 182: #ifndef NOMSEND /* New way. */ ! 183: nfils = fnparse((char *)srvcmd); /* Use cmlist instead */ ! 184: #else ! 185: nfils = 0 - zxpand((char *)srvcmd); ! 186: #endif /* NOMSEND */ ! 187: nakstate = 0; /* Now I'm the sender! */ ! 188: if (sinit()) { /* Send Send-Init */ ! 189: timint = pkttim; /* Switch to per-packet timer */ ! 190: BEGIN ssinit; /* If successful, switch state */ ! 191: } else { SERVE; } /* Else back to server command wait */ ! 192: } ! 193: } ! 194: ! 195: <serve>G { /* Generic server command */ ! 196: srvptr = srvcmd; /* Point to command buffer */ ! 197: decode(rdatap,putsrv,0); /* Decode packet data into it */ ! 198: putsrv('\0'); /* Insert a couple nulls */ ! 199: putsrv('\0'); /* for termination */ ! 200: if (srvcmd[0]) { ! 201: sstate = srvcmd[0]; /* Set requested start state */ ! 202: nakstate = 0; /* Now I'm the sender. */ ! 203: what = W_REMO; /* Doing a REMOTE command. */ ! 204: timint = pkttim; /* Switch to per-packet timer */ ! 205: BEGIN generic; /* Switch to generic command state */ ! 206: } else { ! 207: errpkt((CHAR *)"Badly formed server command"); /* report error */ ! 208: SERVE; /* & go back to server command wait */ ! 209: } ! 210: } ! 211: ! 212: <serve>C { /* Receive Host command */ ! 213: if (!en_hos) { ! 214: errpkt((CHAR *)"REMOTE HOST disabled"); ! 215: SERVE; ! 216: } else { ! 217: srvptr = srvcmd; /* Point to command buffer */ ! 218: decode(rdatap,putsrv,0); /* Decode command packet into it */ ! 219: putsrv('\0'); /* Null-terminate */ ! 220: nakstate = 0; /* Now sending, not receiving */ ! 221: if (syscmd((char *)srvcmd,"")) { /* Try to execute the command */ ! 222: what = W_REMO; /* Doing a REMOTE command. */ ! 223: timint = pkttim; /* Switch to per-packet timer */ ! 224: BEGIN ssinit; /* If OK, send back its output */ ! 225: } else { /* Otherwise */ ! 226: errpkt((CHAR *)"Can't do system command"); /* report error */ ! 227: SERVE; /* & go back to server command wait */ ! 228: } ! 229: } ! 230: } ! 231: ! 232: <serve>q { /* User typed Ctrl-C... */ ! 233: if (!en_fin) { ! 234: errpkt((CHAR *)"QUIT disabled"); ! 235: SERVE; ! 236: } else { ! 237: success = 0; QUIT; ! 238: } ! 239: } ! 240: ! 241: <serve>. { /* Any other command in this state */ ! 242: errpkt((CHAR *)"Unimplemented server function"); /* we don't know about */ ! 243: SERVE; /* back to server command wait */ ! 244: } ! 245: ! 246: <generic>C { /* Got REMOTE CWD command */ ! 247: if (!en_cwd) { ! 248: errpkt((CHAR *)"REMOTE CD disabled"); ! 249: SERVE; ! 250: } else { ! 251: if (!cwd((char *)(srvcmd+1))) errpkt((CHAR *)"Can't change directory"); ! 252: SERVE; /* Back to server command wait */ ! 253: } ! 254: } ! 255: ! 256: <generic>D { /* REMOTE DIRECTORY command */ ! 257: char *n2; ! 258: if (!en_dir) { /* If DIR is disabled, */ ! 259: errpkt((CHAR *)"REMOTE DIRECTORY disabled"); /* refuse. */ ! 260: SERVE; ! 261: } else { /* DIR is enabled. */ ! 262: if (!en_cwd) { /* But if CWD is disabled */ ! 263: zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */ ! 264: if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */ ! 265: errpkt((CHAR *)"Access denied"); ! 266: SERVE; /* Remember, this is not a goto! */ ! 267: } ! 268: } ! 269: if (state == generic) { /* It's OK to go ahead. */ ! 270: n2 = (*(srvcmd+2)) ? DIRCMD : DIRCM2; ! 271: if (syscmd(n2,(char *)(srvcmd+2))) /* If it can be done */ ! 272: BEGIN ssinit; /* send the results back */ ! 273: else { /* otherwise */ ! 274: errpkt((CHAR *)"Can't list directory"); /* report failure, */ ! 275: SERVE; /* return to server command wait */ ! 276: } ! 277: } ! 278: } ! 279: } ! 280: ! 281: <generic>E { /* REMOTE DELETE (Erase) command */ ! 282: char *n2; ! 283: if (!en_del) { ! 284: errpkt((CHAR *)"REMOTE DELETE disabled"); ! 285: SERVE; ! 286: } else { ! 287: if (!en_cwd) { /* But if CWD is disabled */ ! 288: zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */ ! 289: if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */ ! 290: errpkt((CHAR *)"Access denied"); ! 291: SERVE; /* Remember, this is not a goto! */ ! 292: } ! 293: } ! 294: if (state == generic) { /* It's OK to go ahead. */ ! 295: if (syscmd(DELCMD,(char *)(srvcmd+2))) /* Try to do it */ ! 296: BEGIN ssinit; /* If OK send results back */ ! 297: else { /* otherwise */ ! 298: errpkt((CHAR *)"Can't remove file"); /* report failure */ ! 299: SERVE; /* & return to server command wait */ ! 300: } ! 301: } ! 302: } ! 303: } ! 304: ! 305: <generic>F { /* FINISH */ ! 306: if (!en_fin) { ! 307: errpkt((CHAR *)"FINISH disabled"); ! 308: SERVE; ! 309: } else { ! 310: ack(); /* Acknowledge */ ! 311: screen(SCR_TC,0,0l,""); /* Display */ ! 312: return(0); /* Done */ ! 313: } ! 314: } ! 315: ! 316: <generic>L { /* BYE (LOGOUT) */ ! 317: if (!en_bye) { ! 318: errpkt((CHAR *)"BYE disabled"); ! 319: SERVE; ! 320: } else { ! 321: ack(); /* Acknowledge */ ! 322: ttres(); /* Reset the terminal */ ! 323: screen(SCR_TC,0,0l,""); /* Display */ ! 324: doclean(); /* Clean up files, etc */ ! 325: return(zkself()); /* Try to log self out */ ! 326: } ! 327: } ! 328: ! 329: <generic>H { /* REMOTE HELP */ ! 330: if (sndhlp()) BEGIN ssinit; /* Try to send it */ ! 331: else { /* If not ok, */ ! 332: errpkt((CHAR *)"Can't send help"); /* send error message instead */ ! 333: SERVE; /* and return to server command wait */ ! 334: } ! 335: } ! 336: ! 337: <generic>S { /* REMOTE SET */ ! 338: if (!en_set) { ! 339: errpkt((CHAR *)"REMOTE SET disabled"); ! 340: SERVE; ! 341: } else { ! 342: if (remset((char *)(srvcmd+1))) /* Try to do what they ask */ ! 343: ack(); /* If OK, then acknowledge */ ! 344: else /* Otherwise */ ! 345: errpkt((CHAR *)"Unknown REMOTE SET parameter"); /* give error msg */ ! 346: SERVE; /* Return to server command wait */ ! 347: } ! 348: } ! 349: ! 350: <generic>T { /* REMOTE TYPE */ ! 351: char *n2; ! 352: if (!en_typ) { ! 353: errpkt((CHAR *)"REMOTE TYPE disabled"); ! 354: SERVE; ! 355: } else { ! 356: if (!en_cwd) { /* But if CWD is disabled */ ! 357: zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */ ! 358: if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */ ! 359: errpkt((CHAR *)"Access denied"); ! 360: SERVE; /* Remember, this is not a goto! */ ! 361: } ! 362: } ! 363: if (state == generic) { /* It's OK to go ahead. */ ! 364: if (syscmd(TYPCMD,(char *)(srvcmd+2))) /* Try */ ! 365: BEGIN ssinit; /* OK */ ! 366: else { /* not OK */ ! 367: errpkt((CHAR *)"Can't type file"); /* give error message */ ! 368: SERVE; /* wait for next server command */ ! 369: } ! 370: } ! 371: } ! 372: } ! 373: ! 374: <generic>U { /* REMOTE SPACE */ ! 375: if (!en_spa) { ! 376: errpkt((CHAR *)"REMOTE SPACE disabled"); ! 377: SERVE; ! 378: } else { ! 379: x = *(srvcmd+1); /* Get area to check */ ! 380: x = ((x == '\0') || (x == SP)); ! 381: if (!x && !en_cwd) { /* If CWD disabled and they gave */ ! 382: errpkt((CHAR *)"Access denied"); /* a non-default area, */ ! 383: SERVE; /* refuse. */ ! 384: } else { ! 385: x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,(char *)(srvcmd+2))); ! 386: if (x) { /* If we got the info */ ! 387: BEGIN ssinit; /* send it */ ! 388: } else { /* otherwise */ ! 389: errpkt((CHAR *)"Can't check space"); /* send error message */ ! 390: SERVE; /* and await next server command */ ! 391: } ! 392: } ! 393: } ! 394: } ! 395: ! 396: <generic>W { /* REMOTE WHO */ ! 397: if (!en_who) { ! 398: errpkt((CHAR *)"REMOTE WHO disabled"); ! 399: SERVE; ! 400: } else { ! 401: if (syscmd(WHOCMD,(char *)(srvcmd+2))) /* The now-familiar scenario. */ ! 402: BEGIN ssinit; ! 403: else { ! 404: errpkt((CHAR *)"Can't do who command"); ! 405: SERVE; ! 406: } ! 407: } ! 408: } ! 409: ! 410: <generic>q { ! 411: if (!en_fin) { /* Ctrl-C typed */ ! 412: errpkt((CHAR *)"QUIT disabled"); ! 413: SERVE; ! 414: } else { ! 415: success = 0; QUIT; ! 416: } ! 417: } ! 418: ! 419: <generic>. { /* Anything else in this state... */ ! 420: errpkt((CHAR *)"Unimplemented REMOTE command"); /* Complain */ ! 421: SERVE; /* and return to server command wait */ ! 422: } ! 423: ! 424: <rgen>Y { /* Short-Form reply */ ! 425: decode(rdatap,puttrm,0); /* in ACK Data field */ ! 426: RESUME; ! 427: } ! 428: ! 429: <rgen,rfile>F { /* File header */ ! 430: xflg = 0; /* Not screen data */ ! 431: if (!rcvfil(filnam)) { /* Figure out local filename */ ! 432: errpkt((CHAR *)"Can't transform filename"); /* Trouble */ ! 433: RESUME; ! 434: } else { /* OK to receive */ ! 435: encstr((CHAR *)filnam); /* Encode the name */ ! 436: ack1((CHAR *)(encbuf+7)); /* Send it back in ACK */ ! 437: initattr(&iattr); /* Clear file attribute structure */ ! 438: window(wslotn); /* allocate negotiated window slots */ ! 439: BEGIN rattr; /* Now expect Attribute packets */ ! 440: } ! 441: } ! 442: ! 443: <rgen,rfile>X { /* X-packet instead of file header */ ! 444: xflg = 1; /* Screen data */ ! 445: ack(); /* Acknowledge the X-packet */ ! 446: initattr(&iattr); /* Initialize attribute structure */ ! 447: window(wslotn); /* allocate negotiated window slots */ ! 448: what = W_REMO; /* we're doing a REMOTE command */ ! 449: BEGIN rattr; /* Expect Attribute packets */ ! 450: } ! 451: ! 452: <rattr>A { /* Attribute packet */ ! 453: if (discard) { /* If SET FILE COLLISION DISCARD */ ! 454: ack1((CHAR *)"N"); /* refuse it */ ! 455: } else if (gattr(rdatap,&iattr) == 0) /* Read into attribute structure */ ! 456: ack(); /* If OK, acknowledge */ ! 457: else /* Otherwise */ ! 458: ack1((CHAR *)iattr.reply.val); /* refuse to accept the file */ ! 459: } ! 460: ! 461: <rattr>D { /* First data packet */ ! 462: if (discard) { /* if we're discarding the file */ ! 463: ack1((CHAR *)"X"); /* just ack the data like this. */ ! 464: BEGIN rdata; /* and wait for more data packets. */ ! 465: } else { /* Not discarding. */ ! 466: if (xflg) /* If screen data */ ! 467: x = opent(&iattr); /* "open" the screen */ ! 468: else /* otherwise */ ! 469: x = opena(filnam,&iattr); /* open the file, with attributes */ ! 470: if (x) { /* If file was opened ok */ ! 471: if (decode(rdatap,putfil,1) < 0) { /* decode first data packet */ ! 472: errpkt((CHAR *)"Error writing data"); ! 473: RESUME; ! 474: } ! 475: ack(); /* acknowledge it */ ! 476: BEGIN rdata; /* and switch to receive-data state */ ! 477: } else { /* otherwise */ ! 478: errpkt((CHAR *)"Can't open file"); /* send error message */ ! 479: RESUME; /* and quit. */ ! 480: } ! 481: } ! 482: } ! 483: ! 484: <rfile>B { /* EOT, no more files */ ! 485: ack(); /* Acknowledge */ ! 486: tsecs = gtimer(); /* Get timing for statistics */ ! 487: reot(); /* Do EOT things */ ! 488: RESUME; /* and quit */ ! 489: } ! 490: ! 491: <rdata>D { /* Data packet */ ! 492: if (cxseen || discard) /* If file interrupt */ ! 493: ack1((CHAR *)"X"); /* put "X" in ACK */ ! 494: else if (czseen) /* If file-group interrupt */ ! 495: ack1((CHAR *)"Z"); /* put "Z" in ACK */ ! 496: else if (decode(rdatap,putfil,1) < 0) { /* Normal case, decode to file */ ! 497: errpkt((CHAR *)"Error writing data"); /* If failure, */ ! 498: clsof(!keep); /* Close & keep/discard the file */ ! 499: RESUME; /* Send ACK only after data */ ! 500: } else ack(); /* written to file OK. */ ! 501: } ! 502: ! 503: <rattr>Z { /* EOF immediately after A-Packet. */ ! 504: if (xflg) /* Zero-length file. If screen data */ ! 505: x = opent(&iattr); /* "open" the screen */ ! 506: else /* otherwise */ ! 507: x = opena(filnam,&iattr); /* open the file, with attributes. */ ! 508: if (!x || reof(filnam, &iattr) < 0) { /* Now close & dispose of the file */ ! 509: errpkt((CHAR *)"Can't create file"); /* If problem, send error msg */ ! 510: RESUME; /* and quit */ ! 511: } else { /* otherwise */ ! 512: ack(); /* acknowledge the EOF packet */ ! 513: success = 1; ! 514: BEGIN rfile; /* and await another file */ ! 515: } ! 516: } ! 517: ! 518: <rdata>Z { /* End Of File (EOF) Packet */ ! 519: /* wslots = 1; */ /* Window size back to 1 */ ! 520: if (discard) { /* If discarding, there's no file */ ! 521: discard = 0; /* to close, just reset the discard */ ! 522: ack(); /* flag, ack, and proceed normally. */ ! 523: success = 1; /* Count this as a success. */ ! 524: BEGIN rfile; ! 525: } else ! 526: #ifndef COHERENT ! 527: /* ! 528: Coherent compiler blows up on this switch() statement. ! 529: */ ! 530: switch (x = reof(filnam, &iattr)) { ! 531: case -3: /* If problem, send error msg */ ! 532: errpkt((CHAR *)"Can't print file"); ! 533: RESUME; ! 534: break; ! 535: case -2: ! 536: errpkt((CHAR *)"Can't mail file"); ! 537: RESUME; ! 538: break; ! 539: case 2: ! 540: case 3: ! 541: errpkt((CHAR *)"Can't delete temp file"); ! 542: RESUME; ! 543: break; ! 544: default: ! 545: if (x < 0) { ! 546: errpkt((CHAR *)"Can't close file"); ! 547: RESUME; ! 548: } else { /* Success */ ! 549: success = 1; ! 550: ack(); /* Acknowledge the EOF packet */ ! 551: BEGIN rfile; /* and await another file */ ! 552: } ! 553: } ! 554: #else ! 555: if (reof(filnam, &iattr) < 0) { /* Close and dispose of the file */ ! 556: errpkt((CHAR *)"Error at end of file"); ! 557: RESUME; ! 558: } else { ! 559: ack(); ! 560: success = 1; ! 561: BEGIN rfile; ! 562: } ! 563: #endif /* COHERENT */ ! 564: } ! 565: ! 566: <ssinit>Y { /* ACK for Send-Init */ ! 567: spar(rdatap); /* set parameters from it */ ! 568: bctu = bctr; /* switch to agreed-upon block check */ ! 569: what = W_SEND; /* Remember we're sending */ ! 570: x = sfile(xflg); /* Send X or F header packet */ ! 571: if (x) { /* If the packet was sent OK */ ! 572: resetc(); /* reset per-transaction counters */ ! 573: rtimer(); /* reset timers */ ! 574: chktimo(); /* Check & adjust timeout */ ! 575: BEGIN ssfile; /* and switch to receive-file state */ ! 576: } else { /* otherwise send error msg & quit */ ! 577: s = xflg ? "Can't execute command" : "Can't open file"; ! 578: errpkt((CHAR *)s); ! 579: RESUME; ! 580: } ! 581: } ! 582: ! 583: /* ! 584: These states are necessary to handle the case where we get a server command ! 585: packet (R, G, or C) reply with an S packet, but the client retransmits the ! 586: command packet. The input() function doesn't catch this because the packet ! 587: number is still zero. ! 588: */ ! 589: <ssinit>R { /* R packet was retransmitted. */ ! 590: xsinit(); /* Resend packet 0 */ ! 591: } ! 592: ! 593: <ssinit>G { /* Same deal if G packet comes again */ ! 594: xsinit(); ! 595: } ! 596: ! 597: <ssinit>C { /* Same deal if C packet comes again */ ! 598: xsinit(); ! 599: } ! 600: ! 601: <ssfile>Y { /* ACK for F packet */ ! 602: srvptr = srvcmd; /* Point to string buffer */ ! 603: decode(rdatap,putsrv,0); /* Decode data field, if any */ ! 604: putsrv('\0'); /* Terminate with null */ ! 605: if (*srvcmd) /* If remote name was recorded */ ! 606: tlog(F110," stored as",(char *) srvcmd,0L); /* Log in transaction log. */ ! 607: if (atcapu) { /* If attributes are to be used */ ! 608: if (sattr(xflg) < 0) { /* set and send them */ ! 609: errpkt((CHAR *)"Can't send attributes"); /* if problem, say so */ ! 610: RESUME; /* and quit */ ! 611: } else BEGIN ssattr; /* if ok, switch to attribute state */ ! 612: } else { ! 613: window(wslotn); ! 614: if (sdata() < 0) { /* No attributes, send data */ ! 615: clsif(); /* If not ok, close input file, */ ! 616: window(wslots = 1); /* put window size back to 1, */ ! 617: seof((CHAR *)""); /* send EOF packet, */ ! 618: BEGIN sseof; /* and switch to EOF state. */ ! 619: } else BEGIN ssdata; /* All ok, switch to send-data state */ ! 620: } ! 621: } ! 622: ! 623: <ssattr>Y { /* Got ACK to A packet */ ! 624: if (rsattr(rdatap) < 0) { /* Was the file refused? */ ! 625: clsif(); /* yes, close it */ ! 626: sxeof((CHAR *)"D"); /* send EOF with "discard" code */ ! 627: BEGIN sseof; /* switch to send-EOF state */ ! 628: } else { ! 629: window(wslotn); /* Allocate negotiated window. */ ! 630: if (sdata() < 0) { /* File accepted, send data */ ! 631: clsif(); /* If problem, close input file */ ! 632: window(wslots = 1); /* Window size back to 1... */ ! 633: seof((CHAR *)""); /* send EOF packet */ ! 634: BEGIN sseof; /* and switch to send-EOF state. */ ! 635: } else { /* All ok, enter send-data state. */ ! 636: BEGIN ssdata; ! 637: } ! 638: } ! 639: } ! 640: ! 641: <ssdata>Y { /* Got ACK to Data packet */ ! 642: canned(rdatap); /* Check if file transfer cancelled */ ! 643: if (sdata() < 0) { /* Try to send next data */ ! 644: clsif(); /* If no more data, close file */ ! 645: window(wslots = 1); /* Window size back to 1... */ ! 646: if (cxseen || czseen) /* If interrupted */ ! 647: seof((CHAR *)"D"); /* send special EOF packet */ ! 648: else seof((CHAR *)""); /* Otherwise regular EOF packet */ ! 649: BEGIN sseof; /* And enter send-eof state */ ! 650: } ! 651: } ! 652: ! 653: <sseof>Y { /* Got ACK to EOF */ ! 654: success = (cxseen == 0 && czseen == 0); /* Set this for IF command */ ! 655: cxseen = 0; /* This goes back to zero. */ ! 656: if (gnfile() > 0) { /* Any more files to send? */ ! 657: if (sfile(xflg)) /* Yes, try to send next file header */ ! 658: BEGIN ssfile; /* if ok, enter send-file state */ ! 659: else { /* otherwise */ ! 660: errpkt((CHAR *)"Can't open file"); /* send error message */ ! 661: RESUME; /* and quit */ ! 662: } ! 663: } else { /* No next file */ ! 664: tsecs = gtimer(); /* get statistics timers */ ! 665: seot(); /* send EOT packet */ ! 666: BEGIN sseot; /* enter send-eot state */ ! 667: } ! 668: } ! 669: ! 670: <sseot>Y { /* Got ACK to EOT */ ! 671: RESUME; /* All done, just quit */ ! 672: } ! 673: ! 674: E { /* Got Error packet, in any state */ ! 675: ermsg((char *)rdatap); /* Issue message. */ ! 676: success = 0; /* For IF SUCCESS/FAIL. */ ! 677: debug(F101,"ckcpro.w sstate at E pkt","",sstate); ! 678: x = quiet; quiet = 1; /* Close files silently, */ ! 679: clsif(); clsof(1); /* discarding any output file. */ ! 680: tsecs = gtimer(); /* Get timers */ ! 681: quiet = x; /* restore quiet state */ ! 682: if (backgrd && !server) fatal("Protocol error"); ! 683: xitsta |= what; /* Save this for doexit(). */ ! 684: RESUME; ! 685: } ! 686: ! 687: q { QUIT; } /* Ctrl-C interrupt during packets. */ ! 688: ! 689: . { /* Anything not accounted for above */ ! 690: errpkt((CHAR *)"Unexpected packet type"); /* Give error message */ ! 691: xitsta |= what; /* Save this for doexit(). */ ! 692: RESUME; /* and quit */ ! 693: } ! 694: %% ! 695: ! 696: /* P R O T O -- Protocol entry function */ ! 697: ! 698: VOID ! 699: proto() { ! 700: ! 701: int x; ! 702: long lx; ! 703: ! 704: /* Set up the communication line for file transfer. */ ! 705: ! 706: if (local && (speed < 0L) && (network == 0)) { ! 707: screen(SCR_EM,0,0l,"Sorry, you must 'set speed' first"); ! 708: return; ! 709: } ! 710: x = -1; ! 711: if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) { ! 712: debug(F111,"failed: proto ttopen local",ttname,local); ! 713: screen(SCR_EM,0,0l,"Can't open line"); ! 714: return; ! 715: } ! 716: if (x > -1) local = x; ! 717: debug(F111,"proto ttopen local",ttname,local); ! 718: ! 719: lx = (local && !network) ? speed : -1; ! 720: if (ttpkt(lx,flow,parity) < 0) { /* Put line in packet mode, */ ! 721: screen(SCR_EM,0,0l,"Can't condition line"); ! 722: return; ! 723: } ! 724: if (!local) connoi(); /* No console interrupts if remote */ ! 725: ! 726: if (sstate == 'x') { /* If entering server mode, */ ! 727: server = 1; /* set flag, */ ! 728: debug(F101,"server backgrd","",backgrd); ! 729: debug(F101,"server quiet","",quiet); ! 730: if (!quiet && !backgrd) { ! 731: debug(F100,"SHOULD NOT SEE THIS IF IN BACKGROUND!","",0); ! 732: if (!local) /* and issue appropriate message. */ ! 733: conol(srvtxt); ! 734: else { ! 735: conol("Entering server mode on "); ! 736: conoll(ttname); ! 737: conoll("Type Ctrl-C to quit."); ! 738: if (srvdis) intmsg(-1L); ! 739: } ! 740: } ! 741: } else server = 0; ! 742: #ifdef VMS ! 743: if (!quiet && !backgrd) /* So message doesn't overwrite prompt */ ! 744: conoll(""); ! 745: if (local) conres(); /* So Ctrl-C will work */ ! 746: #endif /* VMS */ ! 747: if (sstate == 'v' && !local && !quiet && !backgrd && ! 748: #ifndef NOSPL ! 749: cmdlvl == 0 ! 750: #else ! 751: tlevel < 0 ! 752: #endif /* NOSPL */ ! 753: ) ! 754: conoll("Escape back to your local Kermit and give a SEND command..."); ! 755: if (sstate == 's' && !local && !quiet && !backgrd && ! 756: #ifndef NOSPL ! 757: cmdlvl == 0 ! 758: #else ! 759: tlevel < 0 ! 760: #endif /* NOSPL */ ! 761: ) ! 762: conoll("Escape back to your local Kermit and give a RECEIVE command..."); ! 763: sleep(1); ! 764: /* ! 765: The 'wart()' function is generated by the wart program. It gets a ! 766: character from the input() routine and then based on that character and ! 767: the current state, selects the appropriate action, according to the state ! 768: table above, which is transformed by the wart program into a big case ! 769: statement. The function is active for one transaction. ! 770: */ ! 771: wart(); /* Enter the state table switcher. */ ! 772: ! 773: if (server) { /* Back from packet protocol. */ ! 774: server = 0; ! 775: if (!quiet && !backgrd) { /* Give appropriate message */ ! 776: conoll(""); ! 777: conoll("C-Kermit server done"); ! 778: } ! 779: } ! 780: /* ! 781: Note: the following is necessary in case we have just done a remote-mode ! 782: file transfer, in which case the controlling terminal modes have been ! 783: changed by ttpkt(). In particular, special characters like Ctrl-C and ! 784: Ctrl-\ might have been turned off (see ttpkt). So this call to ttres() is ! 785: essential. ! 786: */ ! 787: if (!local) ttres(); /* Reset the terminal */ ! 788: screen(SCR_TC,0,0l,""); /* Transaction complete */ ! 789: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.