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