BSD 4_4_Lite2 development
[unix-history] / usr / src / contrib / kermit-5A.188 / ckcpro.w
CommitLineData
bebb6839
C
1char *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 (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
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 */
60extern 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
90s { TINIT; /* Do Send command */
91 if (sinit()) BEGIN ssinit;
92 else RESUME; }
93
94v { TINIT; nakstate = 1; BEGIN get; } /* Receive */
95r { TINIT; vstate = get; vcmd = 0; sipkt('I'); BEGIN ipkt; } /* Get */
96c { TINIT; vstate = rgen; vcmd = 'C'; sipkt('I'); BEGIN ipkt; } /* Host */
97k { TINIT; vstate = rgen; vcmd = 'K'; sipkt('I'); BEGIN ipkt; } /* Kermit */
98g { TINIT; vstate = rgen; vcmd = 'G'; sipkt('I'); BEGIN ipkt; } /* Generic */
99
100x { sleep(1); SERVE; } /* Be a Server */
101
102a { if (!data) TINIT; /* "ABEND" -- Tell other side. */
103 errpkt((CHAR *)"User cancelled");
104 success = 0;
105 return(0); } /* Return from protocol. */
106\f
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
714E { /* 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
739q { 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\f
748/* P R O T O -- Protocol entry function */
749
750VOID
751proto() {
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}