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