source: trunk/third/kermit/ckcpro.w @ 10780

Revision 10780, 50.7 KB checked in by brlewis, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10779, which included commits to RCS files with non-trunk default branches.
Line 
1char *protv = "C-Kermit Protocol Module 6.0.095, 6 Sep 96"; /* -*-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>,
6  Columbia University Academic Information Systems, New York City.
7
8  Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
9  York.  The C-Kermit software may not be, in whole or in part, licensed or
10  sold for profit as a software product itself, nor may it be included in or
11  distributed with commercial products or otherwise distributed by commercial
12  concerns to their clients or customers without written permission of the
13  Office of Kermit Development and Distribution, Columbia University.  This
14  copyright notice must not be removed, altered, or obscured.
15*/
16#include "ckcsym.h"
17#include "ckcdeb.h"
18#include "ckcasc.h"
19#include "ckcker.h"
20#ifdef OS2
21#ifndef NT
22#define INCL_NOPM
23#define INCL_VIO                        /* Needed for ckocon.h */
24#include <os2.h>
25#undef COMMENT
26#endif /* NT */
27#include "ckocon.h"
28#endif /* OS2 */
29
30/*
31 Note -- This file may also be preprocessed by the UNIX Lex program, but
32 you must indent the above #include statements before using Lex, and then
33 restore them to the left margin in the resulting C program before compilation.
34 Also, the invocation of the "wart()" function below must be replaced by an
35 invocation  of the "yylex()" function.  It might also be necessary to remove
36 comments in the %%...%% section.
37*/
38
39/* State definitions for Wart (or Lex) */
40%states ipkt rfile rattr rdata ssinit ssfile ssattr ssdata sseof sseot
41%states serve generic get rgen
42
43/* External C-Kermit variable declarations */
44  extern char *versio, *srvtxt, *cmarg, *cmarg2, **cmlist, *rf_err;
45  extern char filnam[], fspec[], ttname[];
46  extern CHAR sstate, *rpar(), *srvptr, *data;
47  extern int timint, rtimo, nfils, hcflg, xflg, flow, mdmtyp, network;
48  extern int rejection, moving, fncact, bye_active;
49  extern int protocol, prefixing, filcnt;
50  extern struct ck_p ptab[];
51  extern int remfile, rempipe;
52  extern char * remdest;
53
54#ifndef NOSERVER
55  extern char * x_user, * x_passwd, * x_acct;
56  extern int x_login, x_logged;
57#endif /* NOSERVER */
58
59#ifdef NETCONN
60#ifdef CK_SPEED
61  extern int ttnproto;                  /* Network protocol */
62  extern short ctlp[];                  /* Control-character prefix table */
63#endif /* CK_SPEED */
64#ifdef TCPSOCKET
65#include "ckcnet.h"
66  extern int me_binary, tn_b_nlm, tn_nlm;
67#endif /* TCPSOCKET */
68#endif /* NETCONN */
69
70#ifdef TCPSOCKET
71#ifndef NOLISTEN
72  extern int tcpsrfd;
73#endif /* NOLISTEN */
74#endif /* TCPSOCKET */
75
76  extern int cxseen, czseen, server, srvdis, local, displa, bctu, bctr, bctl;
77  extern int quiet, tsecs, parity, backgrd, nakstate, atcapu, wslotn, winlo;
78  extern int wslots, success, xitsta, rprintf, discard, cdtimo, keep, fdispla;
79  extern int timef, stdinf, rscapu, sendmode, epktflg;
80  extern int binary, fncnv;
81  extern long speed, ffc, crc16;
82  extern char *DIRCMD, *DIRCM2, *DELCMD, *TYPCMD, *SPACMD, *SPACM2, *WHOCMD;
83  extern CHAR *rdatap;
84  extern struct zattr iattr;
85
86#ifdef pdp11
87  extern CHAR srvcmd[];
88  extern CHAR *pktmsg;
89#else
90#ifdef DYNAMIC
91  extern CHAR *srvcmd;
92  extern CHAR *pktmsg;
93#else
94  extern CHAR srvcmd[];
95  extern CHAR pktmsg[];
96#endif /* DYNAMIC */
97#endif /* pdp11 */
98
99#ifdef CK_TMPDIR
100extern int f_tmpdir;                    /* Directory changed temporarily */
101extern char savdir[];                   /* For saving current directory */
102extern char * dldir;
103#endif /* CK_TMPDIR */
104
105#ifndef NOSPL
106  extern int cmdlvl;
107  char querybuf[QBUFL+1] = { NUL, NUL }; /* QUERY response buffer */
108  char *qbufp = querybuf;               /* Pointer to it */
109  int qbufn = 0;                        /* Length of data in it */
110  extern int query;                     /* Query-active flag */
111#else
112  extern int tlevel;
113#endif /* NOSPL */
114
115#ifdef NT
116  extern int escape;
117#endif /* NT */
118/*
119  If the following flag is nonzero when the protocol module is entered,
120  then server mode persists for exactly one transaction, rather than
121  looping until BYE or FINISH is received.
122*/
123int justone = 0;
124
125_PROTOTYP(static VOID xxproto,(void));
126_PROTOTYP(static int sgetinit,(int));
127_PROTOTYP(int sndspace,(int));
128_PROTOTYP(int wart,(void));
129
130/* Flags for the ENABLE and DISABLE commands */
131extern int
132  en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri,
133  en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, en_ret;
134#ifndef NOSPL
135extern int en_asg, en_que;
136#endif /* NOSPL */
137
138/* Global variables declared here */
139
140  int what = W_NOTHING;                 /* What I am doing */
141  int whatru = 0;                       /* What are you */
142
143/* Local variables */
144
145  static char vstate = 0;               /* Saved State   */
146  static char vcmd = 0;                 /* Saved Command */
147  static int reget = 0;
148  static int retrieve = 0;
149
150  static int x;                         /* General-purpose integer */
151  static char *s;                       /* General-purpose string pointer */
152
153/* Macros - Note, BEGIN is predefined by Wart (and Lex) as "state = ", */
154/* BEGIN is NOT a GOTO! */
155#define ENABLED(x) ((local && (x & 1)) || (!local && (x & 2)))
156#define TINIT if (tinit() < 0) return(-9)
157#define SERVE TINIT; nakstate=1; what=W_NOTHING; cmarg2=""; \
158sendmode=SM_SEND; BEGIN serve;
159#define RESUME if (!server) { return(0); } else \
160if (justone) { justone=0; return(0); } else { SERVE; }
161#define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); quiet=x; \
162 return(1)
163
164%%
165/*
166  Protocol entry points, one for each start state (sstate).
167  The lowercase letters are internal "inputs" from the user interface.
168*/
169
170s { TINIT;                              /* Do Send command */
171    if (sinit() > 0) BEGIN ssinit;
172       else RESUME; }
173
174v { TINIT; nakstate = 1; BEGIN get; }   /* Receive */
175
176r {                                     /* Get */
177    TINIT;
178    vstate = get;
179    reget = 0;
180    retrieve = 0;
181    vcmd = 0;
182    if (sipkt('I') >= 0)
183      BEGIN ipkt;
184    else
185      RESUME;
186}
187h {                                     /* RETRIEVE */
188    TINIT;
189    vstate = get;
190    reget = 0;
191    retrieve = 1;
192    vcmd = 0;
193    if (sipkt('I') >= 0)
194      BEGIN ipkt;
195    else
196      RESUME;
197}
198j {                                     /* REGET */
199    TINIT;
200    vstate = get;
201    reget = 1;
202    retrieve = 0;
203    vcmd = 0;
204    if (sipkt('I') >= 0)
205      BEGIN ipkt;
206    else
207      RESUME;
208}
209c {                                     /* Host */
210    TINIT;
211    vstate = rgen;
212    vcmd = 'C';
213    if (sipkt('I') >= 0)
214      BEGIN ipkt;
215    else
216      RESUME;
217}
218k { TINIT;                              /* Kermit */
219    vstate = rgen;
220    vcmd = 'K';
221    if (sipkt('I') >= 0)
222      BEGIN ipkt;
223    else
224      RESUME;
225}
226g {                                     /* Generic */
227    TINIT;
228    vstate = rgen;
229    vcmd = 'G';
230    if (sipkt('I') >= 0)
231      BEGIN ipkt;
232    else
233      RESUME;
234}
235x {                                     /* Be a Server */
236    int x;
237    x = justone;
238    debug(F101,"x justone 1","",justone);
239    SERVE;                              /* tinit() clears justone... */
240    debug(F101,"x justone 2","",justone);
241    justone = x;
242}
243a {
244    int b1 = 0, b2 = 0;
245    if (!data) TINIT;                   /* "ABEND" -- Tell other side. */
246#ifndef pdp11
247    if (epktflg) {                      /* If because of E-PACKET command */
248        b1 = bctl; b2 = bctu;           /* Save block check type */
249        bctl = bctu = 1;                /* set it to 1 */
250    }
251#endif /* pdp11 */
252    errpkt((CHAR *)"User cancelled");   /* Send the packet */
253#ifndef pdp11
254    if (epktflg) {                      /* Restore the block check */
255        epktflg = 0;
256        bctl = b1; bctu = b2;
257    }
258    screen(SCR_EM,0,0L,"User cancelled");
259#endif /* pdp11 */
260    success = 0;
261    return(0);                          /* Return from protocol. */
262}
263
264/*
265  Dynamic states: <current-states>input-character { action }
266  nakstate != 0 means we're in a receiving state, in which we send ACKs & NAKs.
267*/
268
269<rgen,get,serve>S {                     /* Receive Send-Init packet. */
270#ifndef NOSERVER
271    if (state == serve && x_login && !x_logged) {
272        errpkt((CHAR *)"Login required");
273        SERVE;
274    } else
275#endif /* NOSERVER */
276     
277      if (state == serve && !ENABLED(en_sen)) { /* Not in server mode */
278        errpkt((CHAR *)"SEND disabled"); /* when SEND is disabled. */
279        RESUME;
280    } else {                            /* OK to go ahead. */
281#ifdef CK_TMPDIR
282        if (dldir && !f_tmpdir) {       /* If they have a download directory */
283            debug(F110,"receive download dir",dldir,0);
284            if (s = zgtdir()) {         /* Get current directory */
285                debug(F110,"receive current dir",s,0);
286                if (zchdir(dldir)) {    /* Change to download directory */
287                    debug(F100,"receive zchdir ok","",0);
288                    strncpy(savdir,s,TMPDIRLEN);
289                    f_tmpdir = 1;       /* Remember that we did this */
290                } else
291                  debug(F100,"receive zchdir failed","",0);
292            }
293        }
294#endif /* CK_TMPDIR */
295        nakstate = 1;                   /* Can send NAKs from here. */
296        rinit(rdatap);                  /* Set parameters */
297        bctu = bctr;                    /* Switch to agreed-upon block check */
298        bctl = (bctu == 4) ? 2 : bctu;  /* Set block-check length */
299        what = W_RECV;                  /* Remember we're receiving */
300        resetc();                       /* Reset counters */
301        rtimer();                       /* Reset timer */
302        BEGIN rfile;                    /* Go into receive-file state */
303    }
304}
305
306/* States in which we get replies back from commands sent to a server. */
307/* Complicated because direction of protocol changes, packet number    */
308/* stays at zero through I-G-S sequence, and complicated even more by  */
309/* sliding windows buffer allocation. */
310
311<ipkt>Y {                               /* Get ack for I-packet */
312    int x = 0;
313    spar(rdatap);                       /* Set parameters */
314    winlo = 0;                          /* Set window-low back to zero */
315    if (vcmd) {                         /* If sending a generic command */
316        TINIT;
317        x = scmd(vcmd,(CHAR *)cmarg);   /* Do that */
318        vcmd = 0;                       /* and then un-remember it. */
319    } else if (vstate == get) {
320        debug(F101,"REGET sstate","",sstate);
321        x = srinit(reget, retrieve);    /* GET or REGET */
322    }
323    if (x < 0) {                        /* If command was too long */
324        errpkt((CHAR *)"Command too long for server"); /* cancel both sides. */
325        ermsg("Command too long for server");
326        success = 0;
327        RESUME;
328    } else {
329        rtimer();                       /* Reset the elapsed seconds timer. */
330        winlo = 0;                      /* Window back to 0, again. */
331        nakstate = 1;                   /* Can send NAKs from here. */
332        BEGIN vstate;                   /* Switch to desired state */
333    }
334}
335
336<ipkt>E {                               /* Ignore Error reply to I packet */
337    int x = 0;
338    winlo = 0;                          /* Set window-low back to zero */
339    if (vcmd) {                         /* In case other Kermit doesn't */
340        TINIT;
341        x = scmd(vcmd,(CHAR *)cmarg);   /* understand I-packets. */
342        vcmd = 0;                       /* Otherwise act as above... */
343    } else if (vstate == get) x = srinit(reget, retrieve);
344    if (x < 0) {                        /* If command was too long */
345        errpkt((CHAR *)"Command too long for server"); /* cancel both sides. */
346        ermsg("Command too long for server");
347        success = 0;
348        RESUME;
349    } else {
350        winlo = 0;                      /* Back to packet 0 again. */
351        freerpkt(winlo);                /* Discard the Error packet. */
352        nakstate = 1;                   /* Can send NAKs from here. */
353        BEGIN vstate;
354    }
355}
356
357<get>Y {                /* Resend of previous I-pkt ACK, same seq number! */
358    srinit(reget, retrieve);            /* Send the GET packet again. */
359}
360
361/* States in which we're being a server */
362
363<serve,get>I {                          /* Get I-packet */
364#ifndef NOSERVER
365    spar(rdatap);                       /* Set parameters from it */
366    ack1(rpar());                       /* Respond with our own parameters */
367    pktinit();                          /* Reinitialize packet numbers */
368#endif /* NOSERVER */
369}
370
371<serve>R {                              /* Get Receive-Init (GET) */
372#ifndef NOSERVER
373    if (x_login && !x_logged) {
374        errpkt((CHAR *)"Login required");
375        SERVE;
376    } else if (sgetinit(0) < 0) {
377        RESUME;
378    } else {
379        BEGIN ssinit;
380    }
381#endif /* NOSERVER */
382}
383
384<serve>H {                              /* GET and DELETE ("retrieve") */
385#ifndef NOSERVER
386    if (x_login && !x_logged) {
387        errpkt((CHAR *)"Login required");
388        RESUME;
389    } else if (!ENABLED(en_ret)) {
390        errpkt((CHAR *)"RETRIEVE disabled - use GET");
391        RESUME;
392    } else if (!ENABLED(en_del)) {
393        errpkt((CHAR *)"Deleting files disabled - use GET");
394        RESUME;
395    } else if (sgetinit(0) < 0) {
396        RESUME;
397    } else {
398        moving = 1;
399        BEGIN ssinit;
400    }
401#endif /* NOSERVER */
402}
403
404
405<serve>J {                              /* Get REGET */
406#ifndef NOSERVER
407    if (x_login && !x_logged) {
408        errpkt((CHAR *)"Login required");
409        SERVE;
410    } else if (sgetinit(1) < 0) {
411        RESUME;
412    } else {
413        BEGIN ssinit;
414    }
415#endif /* NOSERVER */
416}
417
418<serve>G {                              /* Generic server command */
419#ifndef NOSERVER
420    srvptr = srvcmd;                    /* Point to command buffer */
421    decode(rdatap,putsrv,0);            /* Decode packet data into it */
422    putsrv(NUL);                        /* Insert a couple nulls */
423    putsrv(NUL);                        /* for termination */
424    if (srvcmd[0]) {
425        sstate = srvcmd[0];             /* Set requested start state */
426        if (x_login && !x_logged && sstate != 'I') {
427            errpkt((CHAR *)"Login required");
428            SERVE;
429        } else {
430            nakstate = 0;               /* Now I'm the sender. */
431            what = W_REMO;              /* Doing a REMOTE command. */
432            if (timint < 1)
433              timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
434            BEGIN generic;              /* Switch to generic command state */
435        }
436    } else {
437        errpkt((CHAR *)"Badly formed server command"); /* report error */
438        RESUME;                 /* & go back to server command wait */
439    }
440#endif /* NOSERVER */
441}
442
443<serve>C {                              /* Receive Host command */
444#ifndef NOSERVER
445    if (x_login && !x_logged) {
446        errpkt((CHAR *)"Login required");
447        SERVE;
448    } else
449      if (!ENABLED(en_hos)) {
450        errpkt((CHAR *)"REMOTE HOST disabled");
451        RESUME;
452    } else {
453        srvptr = srvcmd;                /* Point to command buffer */
454        decode(rdatap,putsrv,0);        /* Decode command packet into it */
455        putsrv(NUL);                    /* Null-terminate */
456        nakstate = 0;                   /* Now sending, not receiving */
457        if (syscmd((char *)srvcmd,"")) { /* Try to execute the command */
458            what = W_REMO;              /* Doing a REMOTE command. */
459            if (timint < 1)
460              timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
461            BEGIN ssinit;               /* If OK, send back its output */
462        } else {                        /* Otherwise */
463            errpkt((CHAR *)"Can't do system command"); /* report error */
464            RESUME;                     /* & go back to server command wait */
465        }
466    }
467#endif /* NOSERVER */
468}
469
470<serve>q {                              /* User typed Ctrl-C... */
471#ifndef NOSERVER
472    if (!ENABLED(en_fin)) {
473        errpkt((CHAR *)"QUIT disabled");
474        RESUME;
475    } else {
476        success = 0; QUIT;
477    }
478#endif /* NOSERVER */
479}
480
481<serve>N {                              /* Server got a NAK in command-wait */
482#ifndef NOSERVER
483    errpkt((CHAR *)"Did you say RECEIVE instead of GET?");
484    RESUME;
485#endif /* NOSERVER */
486}
487
488<serve>. {                              /* Any other command in this state */
489#ifndef NOSERVER
490    if (c != ('E' - SP) && c != ('Y' - SP)) /* except E and Y packets. */
491      errpkt((CHAR *)"Unimplemented server function");
492    /* If we answer an E with an E, we get an infinite loop. */
493    /* A Y (ACK) can show up here if we sent back a short-form reply to */
494    /* a G packet and it was echoed.  ACKs can be safely ignored here. */
495    RESUME;                             /* Go back to server command wait. */
496#endif /* NOSERVER */
497}
498
499<generic>I {                            /* Login/out */
500#ifndef NOSERVER
501    char f1[LOGINLEN+1], f2[LOGINLEN+1], f3[LOGINLEN+1];
502    CHAR *p;
503    int len, i;
504
505    f1[0] = NUL; f2[0] = NUL; f3[0] = NUL;
506    if (x_login) {                      /* Login required */
507        len = 0;
508        if (srvcmd[1])                  /* First length field */
509          len = xunchar(srvcmd[1]);     /* Separate the parameters */
510        if (len > 0 && len <= LOGINLEN) { /* Have username */
511            p = srvcmd + 2;             /* Point to it */
512            for (i = 0; i < len; i++)   /* Copy it */
513              f1[i] = p[i];
514            f1[len] = NUL;              /* Terminate it */
515            p += len;                   /* Point to next length field */
516            if (*p) {                   /* If we have one */
517                len = xunchar(*p++);    /* decode it */
518                if (len > 0 && len <= LOGINLEN) {
519                    for (i = 0; i < len; i++) /* Same deal for password */
520                      f2[i] = p[i];
521                    f2[len] = NUL;
522                    p += len;           /* And account */
523                    if (*p) {
524                        len = xunchar(*p++);   
525                        if (len > 0 && len <= LOGINLEN) {
526                            for (i = 0; i < len; i++)
527                              f3[i] = p[i];
528                            f3[len] = NUL;
529                        }
530                    }
531                }
532            }
533        }
534        debug(F110,"XXX user",f1,0);
535        debug(F110,"XXX pass",f2,0);
536        debug(F110,"XXX acct",f3,0);
537        if (!f1[0]) {
538            if (x_logged) {
539                tlog(F110,"Logged out",x_user,0);
540                ack1((CHAR *)"Logged out");
541            } else {
542                ack1((CHAR *)"You were not logged in");
543            }
544            x_logged = 0;
545        } else {
546            x_logged = 0;
547            if (x_user && x_passwd) {   /* Username and password must match */
548                if (!strcmp(x_user,f1))
549                  if (!strcmp(x_passwd,f2))
550                    x_logged = 1;
551            } else if (x_user) {        /* Only username must match */
552                if (!strcmp(x_user,f1))
553                    x_logged = 1;
554            }             
555            if (x_logged) {
556                tlog(F110,"Logged in", x_user, 0);
557                ack1((CHAR *)"Logged in");
558            } else {
559                tlog(F110,"Login failed", f1, 0);
560                ack1((CHAR *)"Login failed");
561            }
562        }
563    } else {
564        ack1((CHAR *)"No login required");
565    }
566    SERVE;
567#endif /* NOSERVER */
568}
569
570<generic>C {                            /* Got REMOTE CD command */
571#ifndef NOSERVER
572    if (!ENABLED(en_cwd)) {
573        errpkt((CHAR *)"REMOTE CD disabled");
574        RESUME;
575    } else {
576        if (!cwd((char *)(srvcmd+1))) errpkt((CHAR *)"Can't change directory");
577        RESUME;                         /* Back to server command wait */
578    }
579#endif /* NOSERVER */
580}
581
582<generic>A {                            /* Got REMOTE PWD command */
583#ifndef NOSERVER
584    if (!ENABLED(en_cwd)) {
585        errpkt((CHAR *)"REMOTE CD disabled");
586        RESUME;
587    } else {
588        if (encstr((CHAR *)zgtdir()) > -1) /* Get & encode current directory */
589          ack1(data);                   /* If it fits, send it back in ACK */
590        RESUME;                         /* Back to server command wait */
591    }
592#endif /* NOSERVER */
593}
594
595<generic>D {                            /* REMOTE DIRECTORY command */
596#ifndef NOSERVER
597    char *n2;
598    if (!ENABLED(en_dir)) {             /* If DIR is disabled, */
599        errpkt((CHAR *)"REMOTE DIRECTORY disabled"); /* refuse. */
600        RESUME;
601    } else {                            /* DIR is enabled. */
602        if (!ENABLED(en_cwd)) {         /* But CWD is disabled */
603            zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
604            if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
605                errpkt((CHAR *)"Access denied");
606                RESUME;                 /* Remember, this is not a goto! */
607            }
608        }       
609        if (state == generic) {                 /* It's OK to go ahead. */
610#ifdef COMMENT
611            n2 = (*(srvcmd+2)) ? DIRCMD : DIRCM2;
612            if (syscmd(n2,(char *)(srvcmd+2)))  /* If it can be done */
613#else
614            if (snddir((char*)(srvcmd+2)))
615#endif /* COMMENT */
616              BEGIN ssinit;                     /* send the results back */
617            else {                              /* otherwise */
618                errpkt((CHAR *)"Can't list directory"); /* report failure, */
619                RESUME;                 /* return to server command wait */
620            }
621        }
622    }
623#endif /* NOSERVER */
624}
625
626<generic>E {                            /* REMOTE DELETE (Erase) command */
627#ifndef NOSERVER
628    char *n2;
629    if (!ENABLED(en_del)) {
630        errpkt((CHAR *)"REMOTE DELETE disabled");   
631        RESUME;
632    } else {                            /* DELETE is enabled */
633        if (!ENABLED(en_cwd)) {         /* but CWD is disabled */
634            zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
635            if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
636                errpkt((CHAR *)"Access denied");
637                RESUME;                 /* Remember, this is not a goto! */
638            }
639        }       
640        if (state == generic) {         /* It's OK to go ahead. */
641            if (
642#ifdef COMMENT
643            syscmd(DELCMD,(char *)(srvcmd+2)) /* Old way */
644#else
645            snddel((char*)(srvcmd+2))   /* New way */
646#endif /* COMMENT */
647                )
648              BEGIN ssinit;             /* If OK send results back */
649            else {                      /* otherwise */
650                errpkt((CHAR *)"Can't remove file"); /* report failure */
651                RESUME;                 /* & return to server command wait */
652            }
653        }
654    }
655#endif /* NOSERVER */
656}
657
658<generic>F {                            /* FINISH */
659#ifndef NOSERVER
660    if (!ENABLED(en_fin)) {
661        errpkt((CHAR *)"FINISH disabled");   
662        RESUME;
663    } else {
664        ack();                          /* Acknowledge */
665        screen(SCR_TC,0,0L,"");         /* Display */
666        return(0);                      /* Done */
667    }
668#endif /* NOSERVER */
669}
670
671<generic>L {                            /* BYE */
672#ifndef NOSERVER
673    if (!ENABLED(en_bye)) {
674        errpkt((CHAR *)"BYE disabled");   
675        RESUME;
676    } else {
677        ack();                          /* Acknowledge */
678        ttres();                        /* Reset the terminal */
679        screen(SCR_TC,0,0L,"");         /* Display */
680        doclean();                      /* Clean up files, etc */
681#ifdef DEBUG
682        debug(F100,"C-Kermit BYE","",0);
683        zclose(ZDFILE);
684#endif /* DEBUG */
685        return(zkself());               /* Try to log self out */
686    }
687#endif /* NOSERVER */
688}
689
690<generic>H {                            /* REMOTE HELP */
691#ifndef NOSERVER
692    extern char * hlptxt;
693    if (sndhlp(hlptxt)) BEGIN ssinit;   /* Try to send it */
694    else {                              /* If not ok, */
695        errpkt((CHAR *)"Can't send help"); /* send error message instead */
696        RESUME;                         /* and return to server command wait */
697    }
698#endif /* NOSERVER */
699}
700
701<generic>R {                            /* REMOTE RENAME */
702#ifndef NOSERVER
703#ifdef ZRENAME
704    char *str1, *str2, f1[256], f2[256];
705    int  len1, len2;
706
707    if (!ENABLED(en_ren)) {
708        errpkt((CHAR *)"REMOTE RENAME disabled");
709        RESUME;
710    } else {                            /* RENAME is enabled */
711        int len1, len2;
712        len1 = xunchar(srvcmd[1]);      /* Separate the parameters */
713        len2 = xunchar(srvcmd[2+len1]);
714        strncpy(f1,(char *)(srvcmd+2),len1);
715        f1[len1] = NUL;
716        strncpy(f2,(char *)(srvcmd+3+len1),len2);
717        f2[len2] = NUL;
718
719        len2 = xunchar(srvcmd[2+len1]);
720        strncpy(f1,(char *)(srvcmd+2),len1);
721        f1[len1] = NUL;
722        strncpy(f2,(char *)(srvcmd+3+len1),len2);
723        f2[len2] = NUL;
724           
725        if (!ENABLED(en_cwd)) {         /* If CWD is disabled */
726            zstrip(f1,&str1);           /* and they included a pathname, */
727            zstrip(f2,&str2);
728            if ( strcmp(f1,str1) || strcmp(f2,str2) ) { /* refuse. */
729                errpkt((CHAR *)"Access denied");
730                RESUME;                 /* Remember, this is not a goto! */
731            }
732        }       
733        if (state == generic) {         /* It's OK to go ahead. */
734            if (zrename(f1,f2)) {       /* Try */
735                errpkt((CHAR *)"Can't rename file"); /* Give error msg */
736            } else ack();
737            RESUME;                     /* Wait for next server command */
738        }
739    }
740#else /* no ZRENAME */
741    /* Give error message */
742    errpkt((CHAR *)"REMOTE RENAME not available");
743    RESUME;                             /* Wait for next server command */
744#endif /* ZRENAME */
745#endif /* NOSERVER */
746}
747
748<generic>K {                            /* REMOTE COPY */
749#ifndef NOSERVER
750#ifdef ZCOPY
751    char *str1, *str2, f1[256], f2[256];
752    int  len1, len2;
753    if (!ENABLED(en_cpy)) {
754        errpkt((CHAR *)"REMOTE COPY disabled");
755        RESUME;
756    } else {
757        len1 = xunchar(srvcmd[1]);      /* Separate the parameters */
758        len2 = xunchar(srvcmd[2+len1]);
759        strncpy(f1,(char *)(srvcmd+2),len1);
760        f1[len1] = NUL;
761        strncpy(f2,(char *)(srvcmd+3+len1),len2);
762        f2[len2] = NUL;
763
764        if (!ENABLED(en_cwd)) {         /* If CWD is disabled */
765            zstrip(f1,&str1);           /* and they included a pathname, */
766            zstrip(f2,&str2);
767            if (strcmp(f1,str1) || strcmp(f2,str2)) { /* Refuse. */
768                errpkt((CHAR *)"Access denied");
769                RESUME;                 /* Remember, this is not a goto! */
770            }
771        }       
772        if (state == generic) {         /* It's OK to go ahead. */
773            if (zcopy(f1,f2)) {         /* Try */
774                errpkt((CHAR *)"Can't copy file"); /* give error message */
775            } else ack();
776            RESUME;                     /* wait for next server command */
777        }
778    }
779#else /* no ZCOPY */
780    errpkt((CHAR *)"REMOTE COPY not available"); /* give error message */
781    RESUME;                             /* wait for next server command */
782#endif /* ZCOPY */
783#endif /* NOSERVER */
784}
785
786<generic>S {                            /* REMOTE SET */
787#ifndef NOSERVER
788    if (!ENABLED(en_set)) {
789        errpkt((CHAR *)"REMOTE SET disabled");
790        RESUME;
791    } else {
792        if (remset((char *)(srvcmd+1))) /* Try to do what they ask */
793          ack();                        /* If OK, then acknowledge */
794        else                            /* Otherwise */
795          errpkt((CHAR *)"Unknown REMOTE SET parameter"); /* give error msg */
796        RESUME;                         /* Return to server command wait */
797    }
798#endif /* NOSERVER */
799}
800
801<generic>T {                            /* REMOTE TYPE */
802#ifndef NOSERVER
803    char *n2;
804    if (!ENABLED(en_typ)) {
805        errpkt((CHAR *)"REMOTE TYPE disabled");
806        RESUME;
807    } else {
808        if (!ENABLED(en_cwd)) {         /* If CWD disabled */
809            zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
810            if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */
811                errpkt((CHAR *)"Access denied");
812                RESUME;                 /* Remember, this is not a goto! */
813            }
814        }       
815        if (state == generic) {         /* It's OK to go ahead. */
816            binary = XYFT_T;            /* Use text mode for this. */
817            if (                        /* (RESUME didn't change state) */
818#ifdef COMMENT
819              syscmd(TYPCMD,(char *)(srvcmd+2)) /* Old way */
820#else
821              sndtype((char *)(srvcmd+2)) /* New way */
822#endif /* COMMENT */
823                )
824              BEGIN ssinit;                     /* OK */
825            else {                              /* not OK */
826                errpkt((CHAR *)"Can't type file"); /* give error message */
827                RESUME;                 /* wait for next server command */
828            }
829        }
830    }
831#endif /* NOSERVER */
832}
833
834<generic>U {                            /* REMOTE SPACE */
835#ifndef NOSERVER
836    if (!ENABLED(en_spa)) {
837        errpkt((CHAR *)"REMOTE SPACE disabled");
838        RESUME;
839    } else {
840        x = srvcmd[1];                  /* Get area to check */
841        x = ((x == NUL) || (x == SP)
842#ifdef OS2
843             || (x == '!') || (srvcmd[3] == ':')
844#endif /* OS2 */
845             );
846        if (!x && !ENABLED(en_cwd)) {   /* CWD disabled */
847            errpkt((CHAR *)"Access denied"); /* and non-default area given, */
848            RESUME;                     /* refuse. */
849        } else {
850#ifdef OS2
851_PROTOTYP(int sndspace,(int));
852            if (sndspace(x ? toupper(srvcmd[2]) : 0))
853              BEGIN ssinit;             /* Try to send it */
854            else {                      /* If not ok, */
855                errpkt((CHAR *)"Can't send space"); /* send error message */
856                RESUME;                 /* and return to server command wait */
857            }
858#else
859            x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,(char *)(srvcmd+2)));
860            if (x) {                            /* If we got the info */
861                BEGIN ssinit;                   /* send it */
862            } else {                            /* otherwise */
863                errpkt((CHAR *)"Can't check space"); /* send error message */
864                RESUME;                 /* and await next server command */
865            }
866#endif /* OS2 */
867        }
868    }
869#endif /* NOSERVER */
870}
871
872<generic>W {                            /* REMOTE WHO */
873#ifndef NOSERVER
874    if (!ENABLED(en_who)) {
875        errpkt((CHAR *)"REMOTE WHO disabled");
876        RESUME;
877    } else {
878#ifdef OS2
879_PROTOTYP(int sndwho,(char *));
880            if (sndwho((char *)(srvcmd+2)))
881              BEGIN ssinit;             /* Try to send it */
882            else {                      /* If not ok, */
883                errpkt((CHAR *)"Can't do who command"); /* send error msg */
884                RESUME;                 /* and return to server command wait */
885            }
886#else
887        if (syscmd(WHOCMD,(char *)(srvcmd+2))) /* The now-familiar scenario. */
888          BEGIN ssinit;
889        else {
890            errpkt((CHAR *)"Can't do who command");
891            RESUME;
892        }
893#endif /* OS2 */
894    }
895#endif /* NOSERVER */
896}
897
898<generic>V {                            /* Variable query or set */
899#ifndef NOSERVER
900#ifndef NOSPL
901_PROTOTYP( int addmac, (char *, char *) );
902_PROTOTYP( int zzstring, (char *, char **, int *) );
903    char c;
904    c = *(srvcmd+2);                    /* Q = Query, S = Set */
905    if (c == 'Q') {                     /* Query */
906        if (!ENABLED(en_que)) { /* Security */
907            errpkt((CHAR *)"REMOTE QUERY disabled");
908            RESUME;
909        } else {                        /* Query allowed */
910            int n; char *p, *q;
911            qbufp = querybuf;           /* Wipe out old stuff */
912            qbufn = 0;
913            querybuf[0] = NUL;
914            p = (char *) srvcmd + 3;    /* Pointer for making wrapper */
915            n = strlen((char *)srvcmd); /* Position of end */
916            c = *(srvcmd+4);            /* Which type of variable */
917
918            if (*(srvcmd+6) == CMDQ) {  /* Starts with command quote? */
919                p = (char *) srvcmd + 6; /* Take it literally */
920                if (*p == CMDQ) p++;
921            } else {                    /* They played by the rules */
922                if (c == 'K') {         /* Kermit variable */
923                    int k;
924                    k = (int) strlen(p);
925                    if (k > 0 && p[k-1] == ')') {
926                        p = (char *)(srvcmd + 4);
927                        *(srvcmd+4) = CMDQ;
928                        *(srvcmd+5) = 'f'; /* Function, so make it \f...() */
929                    } else {
930                        *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
931                        *(srvcmd+4) = 'v';  /* Variable, so make it \v(...) */
932                        *(srvcmd+5) = '(';  /* around variable name */
933                        *(srvcmd+n) = ')';
934                        *(srvcmd+n+1) = NUL;
935                    }
936                } else {
937                    *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
938                    *(srvcmd+4) = 'v'; /*  Variable, so make it \v(...) */
939                    *(srvcmd+5) = '(';  /* around variable name */
940                    *(srvcmd+n) = ')';
941                    *(srvcmd+n+1) = NUL;
942                    if (c == 'S') {     /* System variable */
943                        *(srvcmd+4) = '$'; /*  so it's \$(...) */
944                    } else if (c == 'G') { /* Non-\ Global variable */
945                        *(srvcmd+4) = 'm'; /*  so wrap it in \m(...) */
946                    }
947                }
948            }                           /* Now evaluate it */
949            n = QBUFL;                  /* Max length */
950            q = querybuf;               /* Where to put it */
951            if (zzstring(p,&q,&n) < 0) {
952                errpkt((n > 0) ? (CHAR *)"Can't get value"
953                               : (CHAR *)"Value too long"
954                       );
955                RESUME;
956            } else {
957                if (encstr((CHAR *)querybuf) > -1) { /* Encode it */
958                    ack1(data);         /* If it fits, send it back in ACK */
959                    RESUME;
960                } else if (sndhlp(querybuf)) { /* Long form response */
961                    BEGIN ssinit;
962                } else {                /* sndhlp() fails */
963                    errpkt((CHAR *)"Can't send value");
964                    RESUME;
965                }
966            }
967        }
968    } else if (c == 'S') {              /* Set (assign) */
969        if (!ENABLED(en_asg)) {         /* Security */
970            errpkt((CHAR *)"REMOTE ASSIGN disabled");
971            RESUME;
972        } else {                        /* OK */
973            int n;
974            n = xunchar(*(srvcmd+3));   /* Length of name */
975            n = 3 + n + 1;              /* Position of length of value */
976            *(srvcmd+n) = NUL;          /* Don't need it */
977            if (addmac((char *)(srvcmd+4),(char *)(srvcmd+n+1)) < 0)
978              errpkt((CHAR *)"REMOTE ASSIGN failed");
979            else
980              ack();
981            RESUME;
982        }
983    } else {
984        errpkt((CHAR *)"Badly formed server command");
985        RESUME;
986    }
987#else
988    errpkt((CHAR *)"Variable query/set not available");
989    RESUME;
990#endif /* NOSPL */
991#endif /* NOSERVER */
992}
993
994<generic>q {
995#ifndef NOSERVER
996    if (!ENABLED(en_fin)) {             /* Ctrl-C typed */
997        errpkt((CHAR *)"QUIT disabled");
998        RESUME;
999    } else {
1000        success = 0; QUIT;
1001    }
1002#endif /* NOSERVER */
1003}
1004
1005<generic>. {                            /* Anything else in this state... */
1006#ifndef NOSERVER
1007    errpkt((CHAR *)"Unimplemented REMOTE command"); /* Complain */
1008    RESUME;                             /* and return to server command wait */
1009#endif /* NOSERVER */
1010}
1011
1012<rgen>Y {                               /* Short-Form reply */
1013#ifndef NOSERVER
1014#ifndef NOSPL
1015    if (query) {                        /* If to query, */
1016        qbufp = querybuf;               /*  initialize query response buffer */
1017        qbufn = 0;
1018        querybuf[0] = NUL;
1019    }
1020#endif /* NOSPL */
1021    decode(rdatap,puttrm,0);            /* Text is in ACK Data field */
1022    if (rdatap)                         /* If we had data */
1023      if (*rdatap)
1024         conoll("");                    /* Then add a CRLF */
1025    if (bye_active && network) {        /* I sent a BYE command and got */
1026        msleep(500);                    /* the ACK... */
1027        tthang();
1028    }
1029    success = 1;
1030    RESUME;
1031#endif /* NOSERVER */
1032}
1033
1034<rgen,rfile>F {                         /* File header */
1035    xflg = 0;                           /* Not screen data */
1036    if (!rcvfil(filnam)) {              /* Figure out local filename */
1037        errpkt((CHAR *)rf_err);         /* Trouble */
1038        screen(SCR_EM,0,0L,rf_err);
1039        RESUME;
1040    } else {                            /* Real file, OK to receive */
1041        if (filcnt == 1)                /* rcvfil set this to 1 for 1st file */
1042          crc16 = 0L;                   /* Clear file CRC */
1043#ifndef NOFULLNAME
1044#ifdef ZFNQFP                           /* Because of zfnqfp() */
1045#ifdef BIGBUFOK                         /* Because it's another 1K buffer */
1046#define USEFULLNAME                     /* Memory to burn - do it */
1047#endif /* BIGBUFOK */
1048#endif /* ZFNQFP */
1049#endif /* NOFULLNAME */
1050
1051#ifdef USEFULLNAME                      /* Name to send back in ACK */
1052        if (!isabsolute(filnam)) {
1053            CHAR tmpbuf[91];            /* Must fit in ACK Data field */
1054            struct zfnfp * fnp;
1055            fnp = zfnqfp(filnam,90,(char *)tmpbuf);
1056            encstr(fnp ? tmpbuf: (CHAR *)filnam); /* Send the full pathname */
1057        } else
1058#endif /* USEFULLNAME */
1059          encstr((CHAR *)filnam);       /* Encode the local filename */
1060
1061        ack1(data);                     /* Send it back in ACK */
1062        initattr(&iattr);               /* Clear file attribute structure */
1063        if (window(wslotn) < 0) {       /* Allocate negotiated window slots */
1064            errpkt((CHAR *)"Can't open window");
1065            RESUME;
1066        }
1067        BEGIN rattr;                    /* Now expect Attribute packets */
1068    }
1069}
1070
1071<rgen,rfile>X {                         /* X-packet instead of file header */
1072    xflg = 1;                           /* Screen data */
1073    ack();                              /* Acknowledge the X-packet */
1074    initattr(&iattr);                   /* Initialize attribute structure */
1075    if (window(wslotn) < 0) {           /* allocate negotiated window slots */
1076        errpkt((CHAR *)"Can't open window");
1077        RESUME;
1078    }
1079#ifndef NOSPL
1080    if (query) {                        /* If this is the response to */
1081        qbufp = querybuf;               /* a query that we sent, initialize */
1082        qbufn = 0;                      /* the response buffer */
1083        querybuf[0] = NUL;
1084    }
1085#endif /* NOSPL */
1086    what = W_REMO;                      /* we're doing a REMOTE command */
1087    BEGIN rattr;                        /* Expect Attribute packets */
1088}
1089
1090<rattr>A {                              /* Attribute packet */
1091    if (gattr(rdatap,&iattr) == 0) {    /* Read into attribute structure */
1092#ifdef CK_RESEND
1093        ack1((CHAR *)iattr.reply.val);  /* Reply with data */
1094#else
1095        ack();                          /* If OK, acknowledge */
1096#endif /* CK_RESEND */
1097    } else {                            /* Otherwise */
1098        ack1((CHAR *)iattr.reply.val);  /* refuse to accept the file */
1099        screen(SCR_ST,ST_REFU,0L,getreason(iattr.reply.val)); /* give reason */
1100    }
1101}
1102
1103<rattr>D {                              /* First data packet */
1104    if (discard) {                      /* if we're discarding the file */
1105        ack1((CHAR *)"X");              /* just ack the data like this. */
1106        BEGIN rdata;                    /* and wait for more data packets. */
1107    } else {                            /* Not discarding. */
1108        rf_err = "Can't open file";
1109        if (xflg) {                     /* If screen data */
1110            if (remfile) {              /* redirected to file */
1111                if (rempipe)            /* or pipe */
1112                  x = zxcmd(ZOFILE,remdest); /* Pipe: start command */
1113                else
1114                  x = opena(remdest,&iattr); /* File: open with attributes */
1115            } else {                    /* otherwise */
1116                x = opent(&iattr);      /* "open" the screen */
1117            }
1118        } else {                        /* otherwise */
1119            x = opena(filnam,&iattr);   /* open the file, with attributes */
1120        }
1121        if (x) {                        /* If file was opened ok */
1122            if (decode(rdatap,
1123#ifndef NOSPL
1124                       query ? puttrm :
1125#endif /* NOSPL */
1126                       putfil, 1) < 0) {
1127
1128                errpkt((CHAR *)"Error writing data");
1129                RESUME;
1130            }
1131            ack();                      /* acknowledge it */
1132            BEGIN rdata;                /* and switch to receive-data state */
1133        } else {                        /* otherwise */
1134            errpkt((CHAR *) rf_err);    /* send error message */
1135            RESUME;                     /* and quit. */
1136        }
1137    }
1138}
1139
1140<rfile>B {                              /* EOT, no more files */
1141    ack();                              /* Acknowledge */
1142    tsecs = gtimer();                   /* Get timing for statistics */
1143    reot();                             /* Do EOT things */
1144#ifdef CK_TMPDIR
1145/* If we were cd'd temporarily to another device or directory ... */
1146    if (f_tmpdir) {
1147        int x;
1148        x = zchdir((char *) savdir);    /* ... restore previous directory */
1149        f_tmpdir = 0;                   /* and remember we did it. */
1150        debug(F111,"ckcpro.w B tmpdir restoring",savdir,x);
1151    }
1152#endif /* CK_TMPDIR */
1153    RESUME;                             /* and quit */
1154}
1155
1156<rdata>D {                              /* Data packet */
1157    if (cxseen || discard)              /* If file interrupt */
1158      ack1((CHAR *)"X");                /* put "X" in ACK */
1159    else if (czseen)                    /* If file-group interrupt */
1160      ack1((CHAR *)"Z");                /* put "Z" in ACK */
1161    else if (decode(rdatap,
1162#ifndef NOSPL
1163                       query ? puttrm :
1164#endif /* NOSPL */
1165                       putfil, 1) < 0) {
1166        errpkt((CHAR *)"Error writing data"); /* If failure, */
1167        clsof(!keep);                   /*   Close & keep/discard the file */
1168        RESUME;                         /* Send ACK only after data */
1169    } else ack();                       /* written to file OK. */
1170}
1171
1172<rattr>Z {                              /* EOF immediately after A-Packet. */
1173    rf_err = "Can't create file";
1174    if (discard) {                      /* Discarding a real file... */
1175        x = 1;
1176    } else if (xflg) {                  /* If screen data */
1177        if (remfile) {                  /* redirected to file */
1178            if (rempipe)                /* or pipe */
1179              x = zxcmd(ZOFILE,remdest); /* Pipe: start command */
1180            else
1181              x = opena(remdest,&iattr); /* File: open with attributes */
1182        } else {                        /* otherwise */
1183            x = opent(&iattr);          /* "open" the screen */
1184        }
1185    } else {                            /* otherwise */
1186        x = opena(filnam,&iattr);       /* open the file, with attributes */
1187    }
1188    if (!x || reof(filnam, &iattr) < 0) { /* Now close & dispose of the file */
1189        errpkt((CHAR *) rf_err);        /* If problem, send error msg */
1190        RESUME;                         /* and quit */
1191    } else {                            /* otherwise */
1192        ack();                          /* acknowledge the EOF packet */
1193        BEGIN rfile;                    /* and await another file */
1194    }
1195}
1196
1197<rdata>Z {                              /* End Of File (EOF) Packet */
1198/*  wslots = 1; */                      /* Window size back to 1 */
1199#ifndef COHERENT
1200/*
1201  Coherent compiler blows up on this switch() statement.
1202*/
1203    x = reof(filnam, &iattr);           /* Handle the EOF packet */
1204    switch (x) {                        /* reof() sets the success flag */
1205      case -3:                          /* If problem, send error msg */
1206        errpkt((CHAR *)"Can't print file"); /* Fatal */
1207        RESUME;
1208        break;
1209      case -2:
1210        errpkt((CHAR *)"Can't mail file"); /* Fatal */
1211        RESUME;
1212        break;
1213      case 2:
1214      case 3:
1215        screen(SCR_EM,0,0L,"Can't delete temp file"); /* Not fatal */
1216        RESUME;
1217        break;
1218      default:
1219        if (x < 0) {                    /* Fatal */
1220            errpkt((CHAR *)"Can't close file");
1221            RESUME;
1222        } else {                        /* Success */
1223#ifndef NOSPL
1224            if (query)                  /* Query reponses generally */
1225              conoll("");               /* don't have line terminators */
1226#endif /* NOSPL */
1227            ack();                      /* Acknowledge the EOF packet */
1228            BEGIN rfile;                /* and await another file */
1229        }
1230    }
1231#else
1232    if (reof(filnam, &iattr) < 0) {     /* Close and dispose of the file */
1233        errpkt((CHAR *)"Error at end of file");
1234        RESUME;
1235    } else {                            /* reof() sets success flag */
1236        ack();
1237        BEGIN rfile;
1238    }
1239#endif /* COHERENT */
1240}
1241
1242<ssinit>Y {                             /* ACK for Send-Init */
1243    spar(rdatap);                       /* set parameters from it */
1244    bctu = bctr;                        /* switch to agreed-upon block check */
1245    bctl = (bctu == 4) ? 2 : bctu;      /* Set block-check length */
1246#ifdef CK_RESEND
1247    if ((sendmode == SM_RESEND) && (!atcapu || !rscapu)) { /* RESEND */
1248        errpkt((CHAR *) "RESEND capabilities not negotiated");
1249        ermsg("RESEND capabilities not negotiated");
1250        RESUME;
1251    } else {
1252#endif /* CK_RESEND */
1253        what = W_SEND;                  /* Remember we're sending */
1254        x = sfile(xflg);                /* Send X or F header packet */
1255        if (x) {                        /* If the packet was sent OK */
1256            if (!xflg && filcnt == 1)   /* and it's a real file */
1257              crc16 = 0L;               /* Clear the file CRC */
1258            resetc();                   /* reset per-transaction counters */
1259            rtimer();                   /* reset timers */
1260            BEGIN ssfile;               /* and switch to receive-file state */
1261        } else {                        /* otherwise send error msg & quit */
1262            s = xflg ? "Can't execute command" : "Can't open file";
1263            errpkt((CHAR *)s);
1264            RESUME;
1265        }
1266#ifdef CK_RESEND
1267    }
1268#endif /* CK_RESEND */
1269}
1270
1271/*
1272 These states are necessary to handle the case where we get a server command
1273 packet (R, G, or C) reply with an S packet, but the client retransmits the
1274 command packet.  The input() function doesn't catch this because the packet
1275 number is still zero.
1276*/
1277<ssinit>R {                             /* R packet was retransmitted. */
1278    xsinit();                           /* Resend packet 0 */
1279}
1280
1281<ssinit>G {                             /* Same deal if G packet comes again */
1282    xsinit();
1283}
1284
1285<ssinit>C {                             /* Same deal if C packet comes again */
1286    xsinit();
1287}
1288
1289<ssfile>Y {                             /* ACK for F packet */
1290    srvptr = srvcmd;                    /* Point to string buffer */
1291    decode(rdatap,putsrv,0);            /* Decode data field, if any */
1292    putsrv(NUL);                        /* Terminate with null */
1293    ffc = 0L;                           /* Reset file byte counter */
1294    if (*srvcmd) {                      /* If remote name was recorded */
1295        if (sendmode != SM_RESEND) {
1296            if (fdispla == XYFD_C)
1297              screen(SCR_AN,0,0L,(char *)srvcmd);
1298            tlog(F110," remote name:",(char *) srvcmd,0L);
1299        }
1300    }
1301    if (atcapu) {                       /* If attributes are to be used */
1302        if (sattr(xflg | stdinf) < 0) { /* set and send them */
1303            errpkt((CHAR *)"Can't send attributes"); /* if problem, say so */
1304            RESUME;                          /* and quit */
1305        } else BEGIN ssattr;            /* if ok, switch to attribute state */
1306    } else {
1307        if (window(wslotn) < 0) {
1308            errpkt((CHAR *)"Can't open window");
1309            RESUME;
1310        }
1311        if ((x = sdata()) == -2) {      /* No attributes, send data */
1312            return(success = 0);        /* Failed */
1313        } else if (x == -1) {           /* EOF (eh?) */
1314            clsif();                    /* If not ok, close input file, */
1315            window(1);                  /* put window size back to 1, */
1316            seof((CHAR *)"");           /* send EOF packet, */
1317            BEGIN sseof;                /* and switch to EOF state. */
1318        } else BEGIN ssdata;            /* All ok, switch to send-data state */
1319    }
1320}
1321
1322<ssattr>Y {                             /* Got ACK to A packet */
1323    ffc = 0L;                           /* Reset file byte counter */
1324    if (rsattr(rdatap) < 0) {           /* Was the file refused? */
1325        discard = 1;                    /* Set the discard flag */
1326        clsif();                        /* Close the file */
1327        sxeof((CHAR *)"D");             /* send EOF with "discard" code */
1328        BEGIN sseof;                    /* switch to send-EOF state */
1329    } else {
1330        if (window(wslotn) < 0) {       /* Allocate negotiated window slots */
1331            errpkt((CHAR *)"Can't open window");
1332            RESUME;
1333        }
1334        if ((x = sdata()) == -2) {      /* File accepted, send data */
1335            return(success = 0);        /* Failed */
1336        } else if (x == -1) {           /* EOF */
1337            clsif();                    /* If not ok, close input file, */
1338            window(1);                  /* put window size back to 1, */
1339            seof((CHAR *)"");           /* send EOF packet, */
1340            BEGIN sseof;                /* and switch to EOF state. */
1341        } else BEGIN ssdata;            /* All ok, switch to send-data state */
1342    }
1343}
1344
1345<ssdata>Y {                             /* Got ACK to Data packet */
1346    canned(rdatap);                     /* Check if file transfer cancelled */
1347    if ((x = sdata()) == -2) {          /* Try to send next data */
1348        return(success = 0);            /* Failed */
1349    } else if (x == -1) {               /* EOF - finished sending data */
1350        clsif();                        /* Close file */
1351        window(1);                      /* Set window size back to 1... */
1352        if (cxseen || czseen)           /* If interrupted */
1353          seof((CHAR *)"D");            /* send special EOF packet */
1354        else                            /* otherwise */
1355          seof((CHAR *)"");             /* regular EOF packet */
1356        BEGIN sseof;                    /* and enter send-eof state */
1357    }
1358}
1359
1360<sseof>Y {                              /* Got ACK to EOF */
1361    success = (cxseen == 0 && czseen == 0); /* Transfer status... */
1362    if (success && rejection > 0)           /* If rejected, succeed if */
1363      if (rejection != '#' &&               /* reason was date */
1364          rejection != 1 && rejection != '?') /* or name; */
1365        success = 0;                        /* fail otherwise. */
1366    cxseen = 0;                         /* This goes back to zero. */
1367    if (success && moving) {            /* If MOVE'ing */
1368        tlog(F110," deleting",filnam,0); /* delete the file */
1369        zdelet(filnam);
1370    }
1371    if (gnfile() > 0) {                 /* Any more files to send? */
1372        if (sfile(xflg))                /* Yes, try to send next file header */
1373          BEGIN ssfile;                 /* if ok, enter send-file state */
1374        else {                          /* otherwise */
1375            errpkt((CHAR *)"Can't open file");  /* send error message */
1376            RESUME;                     /* and quit */
1377        }
1378    } else {                            /* No next file */
1379        tsecs = gtimer();               /* get statistics timers */
1380        seot();                         /* send EOT packet */
1381        BEGIN sseot;                    /* enter send-eot state */
1382    }
1383}
1384
1385<sseot>Y {                              /* Got ACK to EOT */
1386    debug(F101,"sseot justone","",justone);
1387    RESUME;                             /* All done, just quit */
1388}
1389
1390E {                                     /* Got Error packet, in any state */
1391    char *s = "";
1392    if (pktmsg)                         /* Or we sent one. */
1393      if (*pktmsg)                      /* If so, this was the message. */
1394        s = (char *)pktmsg;
1395    if (!*s)                            /* We received an Error packet */
1396      s = (char *)rdatap;               /* with this message. */
1397    if (!*s)                            /* Hopefully we'll never see this. */
1398      s = "Unknown error";
1399    ermsg(s);                           /* Issue the message. */
1400    success = 0;                        /* For IF SUCCESS/FAIL. */
1401    debug(F101,"ckcpro.w justone at E pkt","",justone);
1402    x = quiet; quiet = 1;               /* Close files silently, */
1403    clsif(); clsof(1);                  /* discarding any output file. */
1404    tsecs = gtimer();                   /* Get timers */
1405    quiet = x;                          /* restore quiet state */
1406/*
1407  If we are executing commands from a command file or macro, let the command
1408  file or macro decide whether to exit, based on SET { TAKE, MACRO } ERROR.
1409*/
1410    if (
1411#ifndef NOSPL
1412        cmdlvl == 0
1413#else
1414        tlevel < 0
1415#endif /* NOSPL */
1416        )
1417      if (backgrd && !server)
1418        fatal("Protocol error");
1419    xitsta |= what;                     /* Save this for doexit(). */
1420#ifdef CK_TMPDIR
1421/* If we were cd'd temporarily to another device or directory ... */
1422    if (f_tmpdir) {
1423        int x;
1424        x = zchdir((char *) savdir);    /* ... restore previous directory */
1425        f_tmpdir = 0;                   /* and remember we did it. */
1426        debug(F111,"ckcpro.w E tmpdir restoring",savdir,x);
1427    }
1428#endif /* CK_TMPDIR */
1429    RESUME;
1430}
1431
1432q { success = 0; QUIT; }                /* Ctrl-C interrupt during packets. */
1433
1434. {                                     /* Anything not accounted for above */
1435    errpkt((CHAR *)"Unexpected packet type"); /* Give error message */
1436    xitsta |= what;                     /* Save this for doexit(). */
1437    RESUME;                             /* and quit */
1438}
1439%%
1440
1441/*  P R O T O  --  Protocol entry function  */
1442
1443VOID
1444proto() {
1445    extern int b_save, f_save;
1446#ifdef OS2
1447    extern int cursorena[], cursor_save;
1448    extern BYTE vmode;
1449#endif /* OS2 */
1450/*
1451  This is simply a wrapper for the real protocol function just below,
1452  that saves any items that might be changed automatically by protocol
1453  negotiations, but which should not be sticky, and then restores them
1454  upon exit from protocol mode.
1455*/
1456#ifdef OS2
1457    cursor_save = cursorena[vmode] ;
1458    cursorena[vmode] = 0 ;
1459#endif /* OS2 */
1460    b_save = binary;                    /* SET FILE TYPE */
1461    f_save = fncnv;                     /* SET FILE NAMES */
1462    xxproto();                          /* Call the real protocol function */
1463    fncnv  = f_save;
1464    binary = b_save;
1465#ifdef OS2
1466    cursorena[vmode] = cursor_save ;
1467#endif /* OS2 */
1468}
1469
1470static VOID
1471xxproto() {
1472
1473    int x;
1474    long lx;
1475#ifdef CK_XYZ
1476#ifdef XYZ_INTERNAL
1477_PROTOTYP( int pxyz, (int) );
1478#endif /* XYZ_INTERNAL */
1479#endif /* CK_XYZ */
1480
1481    debug(F101,"xxproto entry justone","",justone);
1482
1483/* Set up the communication line for file transfer. */
1484
1485    if (local && (speed < 0L) && (network == 0)) {
1486        screen(SCR_EM,0,0L,"Sorry, you must 'set speed' first");
1487        return;
1488    }
1489    x = -1;
1490    if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {
1491        debug(F111,"failed: proto ttopen local",ttname,local);
1492        screen(SCR_EM,0,0L,"Can't open line");
1493        success = 0;
1494        return;
1495    }
1496    if (x > -1) local = x;
1497    debug(F111,"proto ttopen local",ttname,local);
1498
1499    lx = (local && !network) ? speed : -1;
1500#ifdef NETCONN
1501#ifdef CK_SPEED
1502/*
1503  If we are a TELNET client, force quoting of IAC.
1504  Note hardwired "1" rather than NP_TELNET symbol, so we don't have
1505  to schlurp in ckcnet.h.
1506*/
1507    if (network && ttnproto == 1) {
1508        ctlp[255] = ctlp[CR] = 1;
1509        if (parity == 'e' || parity == 'm') ctlp[127] = 1;
1510    }
1511#endif /* CK_SPEED */
1512#endif /* NETCONN */
1513    if (ttpkt(lx,flow,parity) < 0) {    /* Put line in packet mode, */
1514        screen(SCR_EM,0,0L,"Can't condition line");
1515        success = 0;
1516        return;
1517    }
1518    /* Send remote side "receive" startup string, if any */
1519    if (local && sstate == 's') {
1520        char *s;
1521        s = binary ? ptab[protocol].h_b_init : ptab[protocol].h_t_init;
1522        if (s) if (*s) {
1523            char tmpbuf[356];
1524            int stuff = -1, stuff2 = -1, len = 0;
1525            extern int tnlm;
1526
1527            sprintf(tmpbuf, s, fspec);  /* We need this for XMODEM... */
1528
1529            strcat(tmpbuf, "\015");
1530            if (tnlm)                   /* TERMINAL NEWLINE ON */
1531              stuff = LF;               /* Stuff LF */
1532#ifdef NETCONN
1533#ifdef TCPSOCKET
1534            /* TELNET NEWLINE MODE */
1535            if (network) {
1536                if (ttnproto == NP_TELNET) {
1537                    switch (me_binary ? tn_b_nlm : tn_nlm) {
1538                      case TNL_CR:
1539                        break;
1540                      case TNL_CRNUL:
1541                        break;
1542                      case TNL_CRLF:
1543                        stuff2 = stuff;
1544                        stuff = LF;
1545                        break;
1546                    }
1547                }
1548#ifdef RLOGCODE
1549                else if (ttnproto == NP_RLOGIN) {
1550                    switch (tn_b_nlm) { /* Always BINARY */
1551                      case TNL_CR:
1552                        break;
1553                      case TNL_CRNUL:
1554                        stuff2 = stuff;
1555                        stuff  = NUL;
1556                        break;
1557                      case TNL_CRLF:
1558                        stuff2 = stuff;
1559                        stuff = LF;
1560                        break;
1561                    }
1562                }
1563#endif /* RLOGCODE */
1564            }
1565#endif /* TCPSOCKET */
1566#endif /* NETCONN */
1567            len = strlen(tmpbuf);
1568            if (stuff >= 0) {
1569                tmpbuf[len++] = stuff;
1570                if (stuff2 >= 0)
1571                  tmpbuf[len++] = stuff2;
1572                tmpbuf[len] = NUL;
1573            }
1574            ttol((CHAR *)tmpbuf,len);
1575        }
1576    }
1577#ifdef CK_XYZ
1578    if (protocol != PROTO_K) {          /* Non-Kermit protocol selected */
1579        char tmpbuf[356];
1580        char * s = "";
1581#ifdef XYZ_INTERNAL                     /* Internal */
1582        success = !pxyz(sstate);
1583#else
1584#ifdef CK_REDIR                         /* External */
1585        switch (sstate) {
1586          case 's':                     /* 'Tis better to SEND... */
1587            s = binary ? ptab[protocol].p_b_scmd : ptab[protocol].p_t_scmd;
1588            break;
1589          case 'v':                     /* ... than RECEIVE */
1590            s = binary ? ptab[protocol].p_b_rcmd : ptab[protocol].p_t_rcmd;
1591            break;
1592        }
1593        if (!s) s = "";
1594        if (*s) {
1595            sprintf(tmpbuf,s,(sstate == 's') ? fspec : cmarg2);
1596            ttruncmd(tmpbuf);
1597        } else {
1598            printf("?Sorry, no external protocol defined for %s\r\n",
1599                   ptab[protocol].p_name
1600                   );
1601        }
1602#else
1603        printf(
1604"Sorry, only Kermit protocol is supported in this version of Kermit\n"
1605               );
1606#endif /* CK_REDIR */
1607#endif /* XYZ_INTERNAL */
1608        return;
1609    }
1610#endif /* CK_XYZ */
1611
1612#ifdef NTSIGX
1613    conraw();
1614    connoi();
1615#else
1616    if (!local)
1617      connoi();                         /* No console interrupts if remote */
1618#endif /* NTSIG */
1619
1620    if (sstate == 'x') {                /* If entering server mode, */
1621        server = 1;                     /* set flag, */
1622        debug(F101,"server backgrd","",backgrd);
1623        debug(F101,"server quiet","",quiet);
1624        if (!quiet && !backgrd) {
1625            debug(F100,"SHOULD NOT SEE THIS IF IN BACKGROUND!","",0);
1626            if (!local) {               /* and issue appropriate message. */
1627                conoll(srvtxt);
1628                conoll("KERMIT READY TO SERVE...");
1629            } else {
1630                conol("Entering server mode on ");
1631                conoll(ttname);
1632                conoll("Type Ctrl-C to quit.");
1633                if (srvdis) intmsg(-1L);
1634            }
1635        }
1636#ifdef TCPSOCKET
1637#ifndef NOLISTEN
1638#ifndef NOSPL
1639        if (network && tcpsrfd > 0) {
1640            dooutput("KERMIT READY TO SERVE...\015\012");
1641        }
1642#endif /* NOSPL */
1643#endif /* NOLISTEN */
1644#endif /* TCPSOCKET */
1645    } else server = 0;
1646#ifdef VMS
1647    if (!quiet && !backgrd)    /* So message doesn't overwrite prompt */
1648      conoll("");
1649    if (local) conres();       /* So Ctrl-C will work */
1650#endif /* VMS */
1651/*
1652  If in remote mode, not shushed, not in background, and at top command level,
1653  issue a helpful message telling what to do...
1654*/
1655    if (!local && !quiet && !backgrd) {
1656        if (sstate == 'v') {
1657            conoll("Return to your local Kermit and give a SEND command.");
1658            conoll("");
1659            conoll("KERMIT READY TO RECEIVE...");
1660        } else if (sstate == 's') {
1661            conoll("Return to your local Kermit and give a RECEIVE command.");
1662            conoll("");
1663            conoll("KERMIT READY TO SEND...");
1664        } else if ( sstate == 'g' || sstate == 'r' || sstate == 'h' ||
1665                    sstate == 'j' || sstate == 'c' ) {
1666            conoll("Return to your local Kermit and give a SERVER command.");
1667            conoll("");
1668            conoll((sstate == 'r' || sstate == 'j' || sstate == 'h') ?
1669                   "KERMIT READY TO GET..." :
1670                   "KERMIT READY TO SEND SERVER COMMAND...");
1671        }
1672    }
1673#ifdef COMMENT
1674    if (!local) sleep(1);
1675#endif /* COMMENT */
1676/*
1677  The 'wart()' function is generated by the wart program.  It gets a
1678  character from the input() routine and then based on that character and
1679  the current state, selects the appropriate action, according to the state
1680  table above, which is transformed by the wart program into a big case
1681  statement.  The function is active for one transaction.
1682*/
1683    rtimer();                           /* Reset elapsed-time timer */
1684    resetc();                           /* & other per-transaction counters. */
1685
1686    debug(F101,"proto calling wart, justone","",justone);
1687
1688    wart();                             /* Enter the state table switcher. */
1689   
1690    if (server) {                       /* Back from packet protocol. */
1691        if (!quiet && !backgrd) {       /* Give appropriate message */
1692            conoll("");
1693            conoll("C-Kermit server done");
1694        }
1695    }
1696/*
1697  Note: the following is necessary in case we have just done a remote-mode
1698  file transfer, in which case the controlling terminal modes have been
1699  changed by ttpkt().  In particular, special characters like Ctrl-C and
1700  Ctrl-\ might have been turned off (see ttpkt).  So this call to ttres() is
1701  essential.
1702*/
1703#ifdef OS2
1704    ttres();                            /* Reset the communication device */
1705#else
1706    if (!local) {
1707        msleep(500);
1708        ttres();                        /* Reset the communication device */
1709    }
1710#endif /* OS2 */
1711    screen(SCR_TC,0,0L,"");             /* Transaction complete */
1712    server = 0;                         /* Not a server any more */
1713}
1714
1715static int
1716sgetinit(reget) int reget; {
1717    if (!ENABLED(en_get)) {             /* Only if not disabled!  */
1718        errpkt((CHAR *)"GET disabled");
1719        return(-1);
1720    } else {                            /* OK to go ahead. */
1721#ifdef WHATAMI
1722        debug(F101,"sgetinit whatru","",whatru);
1723        if (whatru & WM_FLAG) {         /* Did we get WHATAMI info? */
1724            debug(F101,"sgetinit binary (1)","",binary);
1725#ifdef VMS
1726            if (binary != XYFT_I && binary != XYFT_L)
1727#else
1728#ifdef OS2
1729            if (binary != XYFT_L)
1730#endif /* OS2 */
1731#endif /* VMS */
1732            binary = (whatru & WM_FMODE) ?  /* Yes, set transfer mode */
1733              XYFT_B : XYFT_T;              /* automatically */
1734            debug(F101,"sgetinit binary (2)","",binary);
1735            fncnv = (whatru & WM_FNAME) ? 1 : 0; /* And name conversion */
1736        }
1737#endif /* WHATAMI */
1738        srvptr = srvcmd;                /* Point to server command buffer */
1739        decode(rdatap,putsrv,0);        /* Decode the GET command into it */
1740        /* Accept multiple filespecs */
1741        cmarg2 = "";                    /* Don't use cmarg2 */
1742        cmarg = "";                     /* Don't use cmarg */
1743#ifndef NOMSEND                         /* New way. */
1744        nfils = fnparse((char *)srvcmd); /* Use cmlist instead */
1745#else
1746        nfils = 0 - zxpand((char *)srvcmd);
1747#endif /* NOMSEND */
1748        nakstate = 0;                   /* Now I'm the sender! */
1749        if (reget) sendmode = SM_RESEND;
1750        if (sinit() > 0) {              /* Send Send-Init */
1751            timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
1752            return(0);                  /* If successful, switch state */
1753        } else return(-1);              /* Else back to server command wait */
1754    }
1755}
Note: See TracBrowser for help on using the repository browser.