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