dh_installchangelogs: adjust to use ckc301.txt. changelog: explain -O1 usage
[ckermit.git] / ckcpro.w
1 char *protv =                                                     /* -*-C-*- */
2 "C-Kermit Protocol Module 9.0.160, 16 Oct 2009";
3
4 int kactive = 0;                        /* Kermit protocol is active */
5
6 #define PKTZEROHACK
7
8 /* C K C P R O  -- C-Kermit Protocol Module, in Wart preprocessor notation. */
9 /*
10   Author: Frank da Cruz <fdc@columbia.edu>,
11   Columbia University Academic Information Systems, New York City.
12
13   Copyright (C) 1985, 2009,
14     Trustees of Columbia University in the City of New York.
15     All rights reserved.  See the C-Kermit COPYING.TXT file or the
16     copyright text in the ckcmai.c module for disclaimer and permissions.
17 */
18 #ifndef NOXFER
19 #include "ckcsym.h"
20 #include "ckcdeb.h"
21 #include "ckcasc.h"
22 #include "ckcker.h"
23 #ifdef OS2
24 #ifndef NT
25 #define INCL_NOPM
26 #define INCL_VIO                        /* Needed for ckocon.h */
27 #include <os2.h>
28 #undef COMMENT
29 #endif /* NT */
30 #include "ckocon.h"
31 #endif /* OS2 */
32
33 /*
34  Note -- This file may also be preprocessed by the UNIX Lex program, but
35  you must indent the above #include statements before using Lex, and then
36  restore them to the left margin in the resulting C program before compilation.
37  Also, the invocation of the "wart()" function below must be replaced by an
38  invocation  of the "yylex()" function.  It might also be necessary to remove
39  comments in the (%)(%)...(%)(%) section.
40 */
41
42 /* State definitions for Wart (or Lex) */
43 %states ipkt rfile rattr rdpkt ssinit ssfile ssattr ssdata sseof sseot
44 %states serve generic get rgen ssopkt ropkt
45
46 _PROTOTYP(static VOID xxproto,(void));
47 _PROTOTYP(static VOID wheremsg,(void));
48 _PROTOTYP(int wart,(void));
49 _PROTOTYP(static int sgetinit,(int,int));
50 _PROTOTYP(int sndspace,(int));
51
52 /* External C-Kermit variable declarations */
53   extern char *versio, *srvtxt, *cmarg, *cmarg2, **cmlist, *rf_err;
54   extern char * rfspec, * sfspec, * srfspec, * rrfspec;
55   extern char * prfspec, * psfspec, * psrfspec, * prrfspec;
56   extern char *cdmsgfile[];
57   extern char * snd_move, * snd_rename, * srimsg;
58   extern char filnam[], ofilnam[], fspec[], ttname[], ofn1[];
59   extern CHAR sstate, *srvptr, *data;
60   extern int timint, rtimo, nfils, hcflg, xflg, flow, mdmtyp, network;
61   extern int oopts, omode, oname, opath, nopush, isguest, xcmdsrc, rcdactive;
62   extern int rejection, moving, fncact, bye_active, urserver, fatalio;
63   extern int protocol, prefixing, filcnt, carrier, fnspath, interrupted;
64   extern int recursive, inserver, nzxopts, idletmo, srvidl, xfrint;
65   extern struct ck_p ptab[];
66   extern int remfile, rempipe, xferstat, filestatus, wearealike, fackpath;
67   extern int patterns, filepeek, gnferror;
68   extern char * remdest;
69
70 #ifdef PKTZEROHACK
71 #define PKTZEROLEN 32
72 static char ipktack[PKTZEROLEN];
73 static int ipktlen = 0;
74 #endif /* PKTZEROHACK */
75
76 static int s_timint = -1;               /* For saving timeout value */
77 static int myjob = 0;
78 static int havefs = 0;
79 #ifdef CK_LOGIN
80 static int logtries = 0;
81 #endif /* CK_LOGIN */
82
83 static int cancel = 0;
84 int fackbug = 0;
85
86 #ifdef STREAMING
87 extern int streaming, streamok;
88
89 static VOID
90 streamon() {
91     if (streamok) {
92         debug(F100,"streamon","",0);
93         streaming = 1;
94         timint = 0;                     /* No timeouts while streaming. */
95     }
96 }
97
98 #ifdef COMMENT                          /* (not used) */
99 static VOID
100 streamoff() {
101     if (streaming) {
102         debug(F100,"streamoff","",0);
103         streaming = 0;
104         timint = s_timint;              /* Restore timeout */
105     }
106 }
107 #endif /* COMMENT */
108 #else /* STREAMING */
109 #define streamon()
110 #define streamoff()
111 #endif /* STREAMING */
112
113 #ifndef NOSPL
114 _PROTOTYP( int addmac, (char *, char *) );
115 _PROTOTYP( int zzstring, (char *, char **, int *) );
116 #endif /* NOSPL */
117 #ifndef NOICP
118 _PROTOTYP( int cmdsrc, (void) );
119 #endif /* NOICP */
120
121 #ifndef NOSERVER
122   extern char * x_user, * x_passwd, * x_acct;
123   extern int x_login, x_logged;
124 #endif /* NOSERVER */
125
126 #include "ckcnet.h"
127
128 #ifdef TNCODE
129   extern int ttnproto;                  /* Network protocol */
130 #endif /* TNCODE */
131
132 #ifdef CK_SPEED
133   extern short ctlp[];                  /* Control-character prefix table */
134 #endif /* CK_SPEED */
135
136 #ifdef TNCODE
137   extern int tn_b_nlm, tn_b_xfer, tn_nlm;
138 #ifdef CK_ENCRYPTION
139   extern int tn_no_encrypt_xfer;
140 #endif /* CK_ENCRYPTION */
141 #endif /* TNCODE */
142
143 #ifdef TCPSOCKET
144 #ifndef NOLISTEN
145   extern int tcpsrfd;
146 #endif /* NOLISTEN */
147 #endif /* TCPSOCKET */
148
149   extern int cxseen, czseen, server, srvdis, local, displa, bctu, bctr, bctl;
150   extern int bctf;
151   extern int quiet, tsecs, parity, backgrd, nakstate, atcapu, wslotn, winlo;
152   extern int wslots, success, xitsta, rprintf, discard, cdtimo, keep, fdispla;
153   extern int timef, stdinf, rscapu, sendmode, epktflg, epktrcvd, epktsent;
154   extern int binary, fncnv;
155   extern long speed, ffc, crc16, calibrate, dest;
156 #ifdef COMMENT
157   extern char *TYPCMD, *DIRCMD, *DIRCM2;
158 #endif /* COMMENT */
159 #ifndef OS2
160   extern char *SPACMD, *SPACM2, *WHOCMD;
161 #endif /* OS2 */
162   extern CHAR *rdatap;
163   extern struct zattr iattr;
164
165 #ifdef VMS
166   extern int batch;
167 #endif /* VMS */
168
169 #ifdef GFTIMER
170   extern CKFLOAT fptsecs;
171 #endif /* GFTIMER */
172
173   extern CHAR *srvcmd;
174   extern CHAR *epktmsg;
175
176 #ifdef CK_TMPDIR
177 extern int f_tmpdir;                    /* Directory changed temporarily */
178 extern char savdir[];                   /* For saving current directory */
179 extern char * dldir;
180 #endif /* CK_TMPDIR */
181
182   extern int query;                     /* Query-active flag */
183 #ifndef NOSPL
184   extern int cmdlvl;
185   char querybuf[QBUFL+1] = { NUL, NUL }; /* QUERY response buffer */
186   char *qbufp = querybuf;               /* Pointer to it */
187   int qbufn = 0;                        /* Length of data in it */
188 #else
189   extern int tlevel;
190 #endif /* NOSPL */
191
192 #ifndef NOICP
193   extern int escape;
194 #endif /* NOICP */
195 /*
196   If the following flag is nonzero when the protocol module is entered,
197   then server mode persists for exactly one transaction, rather than
198   looping until BYE or FINISH is received.
199 */
200 extern int justone;
201
202 static int r_save = -1;
203 static int p_save = -1;
204
205 /* Function to let remote-mode user know where their file(s) went */
206
207 int whereflg = 1;                       /* Unset with SET XFER REPORT */
208
209 static VOID
210 wheremsg() {
211     extern int quiet, filrej;
212     int n;
213     n = filcnt - filrej;
214     debug(F101,"wheremsg n","",n);
215
216     debug(F110,"wheremsg prfspec",prfspec,0);
217     debug(F110,"wheremsg rfspec",rfspec,0);
218     debug(F110,"wheremsg psfspec",psfspec,0);
219     debug(F110,"wheremsg sfspec",sfspec,0);
220
221     debug(F110,"wheremsg prrfspec",prrfspec,0);
222     debug(F110,"wheremsg rrfspec",rrfspec,0);
223     debug(F110,"wheremsg psrfspec",psrfspec,0);
224     debug(F110,"wheremsg srfspec",srfspec,0);
225
226     if (!quiet && !local) {
227         if (n == 1) {
228             switch (myjob) {
229               case 's':
230                 if (sfspec) {
231                     printf(" SENT: [%s]",sfspec);
232                     if (srfspec)
233                       printf(" To: [%s]",srfspec);
234                     printf(" (%s)\r\n", success ? "OK" : "FAILED");
235                 }
236                 break;
237               case 'r':
238               case 'v':
239                 if (rrfspec) {
240                     printf(" RCVD: [%s]",rrfspec);
241                     if (rfspec)
242                       printf(" To: [%s]",rfspec);
243                     printf(" (%s)\r\n", success ? "OK" : "FAILED");
244                 }
245             }
246         } else if (n > 1) {
247             switch (myjob) {
248               case 's':
249                 if (sfspec) {
250                     printf(" SENT: (%d files)",n);
251                     if (srfspec)
252                       printf(" Last: [%s]",srfspec);
253                     printf(" (%s)\r\n", success ? "OK" : "FAILED");
254                 }
255                 break;
256               case 'r':
257               case 'v':
258                 if (rrfspec) {
259                     printf(" RCVD: (%d files)",n);
260                     if (rfspec)
261                       printf(" Last: [%s]",rfspec);
262                     printf(" (%s)\r\n", success ? "OK" : "FAILED");
263                 }
264             }
265         } else if (n == 0) {
266             if (myjob == 's')
267               printf(" SENT: (0 files)          \r\n");
268             else if (myjob == 'r' || myjob == 'v')
269               printf(" RCVD: (0 files)          \r\n");
270         }
271     }
272 }
273
274 static VOID
275 rdebug() {
276     if (server)
277       debug(F111,"RESUME","server=1",justone);
278     else
279       debug(F111,"RESUME","server=0",justone);
280 }
281
282 /* Flags for the ENABLE and DISABLE commands */
283 extern int
284   en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri,
285   en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, en_ret, en_xit,
286   en_mkd, en_rmd;
287 #ifndef NOSPL
288 extern int en_asg, en_que;
289 #endif /* NOSPL */
290 extern int what, lastxfer;
291
292 /* Global variables declared here */
293
294   int whatru = 0;                       /* What are you. */
295   int whatru2 = 0;                      /* What are you, cont'd. */
296
297 /* Local variables */
298
299   static char vstate = 0;               /* Saved State   */
300   static char vcmd = 0;                 /* Saved Command */
301   static int reget = 0;                 /* Flag for executing REGET */
302   static int retrieve = 0;              /* Flag for executing RETRIEVE */
303   static int opkt = 0;                  /* Send Extended GET packet */
304
305   static int x;                         /* General-purpose integer */
306   static char *s;                       /* General-purpose string pointer */
307
308 /* Macros - Note, BEGIN is predefined by Wart (and Lex) as "state = ", */
309 /* BEGIN is NOT a GOTO! */
310 #define TINIT if (tinit(1) < 0) return(-9)
311 #define SERVE { TINIT; resetc(); nakstate=1; what=W_NOTHING; cmarg2=""; \
312 sendmode=SM_SEND; havefs=0; recursive=r_save; fnspath=p_save; BEGIN serve; }
313 #define RESUME { rdebug(); if (!server) { wheremsg(); return(0); } else \
314 if (justone) { justone=0; wheremsg(); return(0); } else { SERVE; } }
315
316 #ifdef GFTIMER
317 #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); \
318  fptsecs=gftimer(); quiet=x; return(success)
319 #else
320 #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); quiet=x; \
321  return(success)
322 #endif /* GFTIMER */
323
324 /*
325   By late 1999, the big switch() statement generated from the following state
326   table began choking even gcc, so here we extract the code from the larger
327   states into static routines to reduce the size of the cases and the
328   switch() overall.  The routines follow the state table; the prototypes are
329   here.  Each of these routines simply contains the text from the
330   corresponding case, but with return(-1) added in appropriate places; see
331   instructions after the state table switcher.
332 */
333 static int rc;                          /* Return code for these routines */
334 static int rcv_s_pkt();                 /* Received an S packet */
335 static int rcv_firstdata();             /* Received first Data packet */
336 static int rcv_shortreply();            /* Short reply to a REMOTE command  */
337 static int srv_query();                 /* Server answers an query */
338 static int srv_copy();                  /* Server executes REMOTE COPY */
339 static int srv_rename();                /* Server executes REMOTE RENAME */
340 static int srv_login();                 /* Server executes REMOTE LOGIN */
341 static int srv_timeout();               /* Server times out */
342
343 %%
344
345 /*
346   Protocol entry points, one for each start state (sstate).
347   The lowercase letters are internal "inputs" from the user interface.
348   NOTE: The start state letters that appear on the left margin immediately
349   below can NOT be used as packet types OR as G-packet subcodes.
350 */
351
352 s { TINIT;                              /* Send file(s) */
353     if (sinit() > 0) BEGIN ssinit;
354        else RESUME; }
355
356 v { TINIT; nakstate = 1; BEGIN get; }   /* Receive file(s) */
357
358 r {                                     /* Client sends a GET command */
359     TINIT;
360     vstate = get;
361     reget = 0;
362     retrieve = 0;
363     opkt = 0;
364     vcmd = 0;
365 #ifdef PKTZEROHACK
366     ipktack[0] = NUL;
367 #endif /* PKTZEROHACK */
368     if (sipkt('I') >= 0)
369       BEGIN ipkt;
370     else
371       RESUME;
372 }
373
374 h {                                     /* Client sends a RETRIEVE command */
375     TINIT;
376     vstate = get;
377     reget = 0;
378     retrieve = 1;
379     opkt = 0;
380     vcmd = 0;
381     if (sipkt('I') >= 0)
382       BEGIN ipkt;
383     else
384       RESUME;
385 }
386 j {                                     /* Client sends a REGET command */
387     TINIT;
388     vstate = get;
389     reget = 1;
390     retrieve = 0;
391     opkt = 0;
392     vcmd = 0;
393     if (sipkt('I') >= 0)
394       BEGIN ipkt;
395     else
396       RESUME;
397 }
398 o {                                     /* Client sends Extended GET Packet */
399     TINIT;
400     vstate = get;
401     reget = oopts & GOPT_RES;
402     retrieve = oopts & GOPT_DEL;
403     opkt = 1;
404     vcmd = 0;
405     if (sipkt('I') >= 0)
406       BEGIN ipkt;
407     else
408       RESUME;
409 }
410 c {                                     /* Client sends a Host command */
411     TINIT;
412     vstate = rgen;
413     vcmd = 'C';
414     if (sipkt('I') >= 0)
415       BEGIN ipkt;
416     else
417       RESUME;
418 }
419 k { TINIT;                              /* Client sends a Kermit command */
420     vstate = rgen;
421     vcmd = 'K';
422     if (sipkt('I') >= 0)
423       BEGIN ipkt;
424     else
425       RESUME;
426 }
427 g {                                     /* Client sends a REMOTE command */
428     TINIT;
429     vstate = rgen;
430     vcmd = 'G';
431     if (sipkt('I') >= 0)
432       BEGIN ipkt;
433     else
434       RESUME;
435 }
436 x {                                     /* Enter server mode */
437     int x;
438     x = justone;
439     if (!ENABLED(en_del)) {             /* If DELETE is disabled */
440         if (fncact == XYFX_B ||         /* undo any file collision action */
441             fncact == XYFX_U ||         /* that could result in deletion or */
442             fncact == XYFX_A ||         /* modification of existing files. */
443             fncact == XYFX_X) {
444 #ifndef NOICP
445             extern int g_fncact;
446             g_fncact = fncact;          /* Save current setting */
447 #endif /* NOICP */
448             fncact = XYFX_R;            /* Change to RENAME */
449             debug(F101,"server DELETE disabled so fncact RENAME","",fncact);
450         }
451     }
452     SERVE;                              /* tinit() clears justone... */
453     justone = x;
454 #ifdef IKSDB
455     if (ikdbopen) slotstate(what, "SERVER", "", "");
456 #endif /* IKSDB */
457 }
458
459 a {
460     int b1 = 0, b2 = 0;
461     if (!data) TINIT;                   /* "ABEND" -- Tell other side. */
462
463     if (!bctf) {                     /* Block check 3 forced on all packets */
464 #ifndef pdp11
465         if (epktflg) {                  /* If because of E-PACKET command */
466             b1 = bctl; b2 = bctu;       /* Save block check type */
467             bctl = bctu = 1;            /* set it to 1 */
468         }
469 #endif /* pdp11 */
470     }
471     errpkt((CHAR *)"User cancelled");   /* Send the packet */
472     if (!bctf) {                     /* Block check 3 forced on all packets */
473 #ifndef pdp11
474         if (epktflg) {                  /* Restore the block check */
475             epktflg = 0;
476             bctl = b1; bctu = b2;
477         }
478     }
479 #endif /* pdp11 */
480     success = 0;
481     return(0);                          /* Return from protocol. */
482 }
483
484 /*
485   Dynamic states: <current-states>input-character { action }
486   nakstate != 0 means we're in a receiving state, in which we send ACKs & NAKs.
487 */
488
489 <rgen,get,serve,ropkt>S {               /* Receive Send-Init packet. */
490     rc = rcv_s_pkt();
491     cancel = 0;                         /* Reset cancellation counter */
492     debug(F101,"rcv_s_pkt","",rc);
493     if (rc > -1) return(rc);            /* (see below) */
494 }
495
496 /* States in which we get replies back from commands sent to a server. */
497 /* Complicated because direction of protocol changes, packet number    */
498 /* stays at zero through I-G-S sequence, and complicated even more by  */
499 /* sliding windows buffer allocation. */
500
501 <ipkt>Y {                               /* Get ack for I-packet */
502     int x = 0;
503 #ifdef PKTZEROHACK
504     ckstrncpy(ipktack,(char *)rdatap,PKTZEROLEN); /* Save a copy of the ACK */
505     ipktlen = strlen(ipktack);
506 #endif /* PKTZEROHACK */
507     spar(rdatap);                       /* Set parameters */
508     cancel = 0;
509     winlo = 0;                          /* Set window-low back to zero */
510     debug(F101,"<ipkt>Y winlo","",winlo);
511     urserver = 1;                       /* So I know I'm talking to a server */
512     if (vcmd) {                         /* If sending a generic command */
513         if (tinit(0) < 0) return(-9);   /* Initialize many things */
514         x = scmd(vcmd,(CHAR *)cmarg);   /* Do that */
515         if (x >= 0) x = 0;              /* (because of O-Packet) */
516         debug(F101,"proto G packet scmd","",x);
517         vcmd = 0;                       /* and then un-remember it. */
518     } else if (vstate == get) {
519         debug(F101,"REGET sstate","",sstate);
520         x = srinit(reget, retrieve, opkt); /* GET or REGET, etc */
521     }
522     if (x < 0) {                        /* If command was too long */
523         if (!srimsg)
524           srimsg = "Error sending string";
525         errpkt((CHAR *)srimsg);         /* cancel both sides. */
526         success = 0;
527         RESUME;
528     } else if (x > 0) {                 /* Need to send more O-Packets */
529         BEGIN ssopkt;
530     } else {
531         rtimer();                       /* Reset the elapsed seconds timer. */
532 #ifdef GFTIMER
533         rftimer();
534 #endif /* GFTIMER */
535         winlo = 0;                      /* Window back to 0, again. */
536         debug(F101,"<ipkt>Y vstate","",vstate);
537         nakstate = 1;                   /* Can send NAKs from here. */
538         BEGIN vstate;                   /* Switch to desired state */
539     }
540 }
541
542 <ssopkt>Y {                             /* Got ACK to O-Packet */
543     debug(F100,"CPCPRO <ssopkt>Y","",0);
544     x = sopkt();
545     debug(F101,"CPCPRO <ssopkt>Y x","",x);
546     if (x < 0) {                        /* If error */
547         errpkt((CHAR *)srimsg);         /* cancel both sides. */
548         success = 0;
549         RESUME;
550     } else if (x == 0) {                /* This was the last O-Packet */
551         rtimer();                       /* Reset the elapsed seconds timer. */
552 #ifdef GFTIMER
553         rftimer();
554 #endif /* GFTIMER */
555         winlo = 0;                      /* Window back to 0, again. */
556         debug(F101,"<ssopkt>Y winlo","",winlo);
557         nakstate = 1;                   /* Can send NAKs from here. */
558         BEGIN vstate;                   /* Switch to desired state */
559     }
560     debug(F101,"CPCPRO <ssopkt>Y not changing state","",x);
561 }
562
563 <ipkt>E {                               /* Ignore Error reply to I packet */
564     int x = 0;
565     winlo = 0;                          /* Set window-low back to zero */
566     debug(F101,"<ipkt>E winlo","",winlo);
567     if (vcmd) {                         /* In case other Kermit doesn't */
568         if (tinit(0) < 0) return(-9);
569         x = scmd(vcmd,(CHAR *)cmarg);   /* understand I-packets. */
570         if (x >= 0) x = 0;              /* (because of O-Packet) */
571         vcmd = 0;                       /* Otherwise act as above... */
572     } else if (vstate == get) x = srinit(reget, retrieve, opkt);
573     if (x < 0) {                        /* If command was too long */
574         errpkt((CHAR *)srimsg);         /* cancel both sides. */
575         success = 0;
576         RESUME;
577     } else if (x > 0) {                 /* Need to send more O-Packets */
578         BEGIN ssopkt;
579     } else {
580         freerpkt(winlo);                /* Discard the Error packet. */
581         debug(F101,"<ipkt>E winlo","",winlo);
582         winlo = 0;                      /* Back to packet 0 again. */
583         nakstate = 1;                   /* Can send NAKs from here. */
584         BEGIN vstate;
585     }
586 }
587
588 <get>Y {                /* Resend of previous I-pkt ACK, same seq number */
589     freerpkt(0);                        /* Free the ACK's receive buffer */
590     resend(0);                          /* Send the GET packet again. */
591 }
592
593 /* States in which we're being a server */
594
595 <serve,get>I {                          /* Get I-packet */
596 #ifndef NOSERVER
597     spar(rdatap);                       /* Set parameters from it */
598     ack1(rpar());                       /* Respond with our own parameters */
599 #ifdef COMMENT
600     pktinit();                          /* Reinitialize packet numbers */
601 #else
602 #ifdef COMMENT
603     /* This can't be right - it undoes the stuff we just negotiated */
604     x = justone;
605     tinit(1);                           /* Reinitialize EVERYTHING */
606     justone = x;                        /* But this... */
607 #else
608     tinit(0);                           /* Initialize most things */
609 #endif /* COMMENT */
610 #endif /* COMMENT */
611 #endif /* NOSERVER */
612     cancel = 0;                         /* Reset cancellation counter */
613 }
614
615 <serve>R {                              /* GET */
616 #ifndef NOSERVER
617     if (x_login && !x_logged) {
618         errpkt((CHAR *)"Login required");
619         SERVE;
620     } else if (sgetinit(0,0) < 0) {
621         RESUME;
622     } else {
623 #ifdef CKSYSLOG
624         if (ckxsyslog >= SYSLG_PR && ckxlogging)
625           cksyslog(SYSLG_PR, 1, "server", "GET", (char *)srvcmd);
626 #endif /* CKSYSLOG */
627         BEGIN ssinit;
628     }
629 #endif /* NOSERVER */
630 }
631
632 <serve>H {                              /* GET /DELETE (RETRIEVE) */
633 #ifndef NOSERVER
634     if (x_login && !x_logged) {
635         errpkt((CHAR *)"Login required");
636         RESUME;
637     } else if (!ENABLED(en_del)) {
638         errpkt((CHAR *)"Deleting files is disabled");
639         RESUME;
640     } else if (sgetinit(0,0) < 0) {
641         RESUME;
642     } else {
643         moving = 1;
644 #ifdef CKSYSLOG
645         if (ckxsyslog >= SYSLG_PR && ckxlogging)
646           cksyslog(SYSLG_PR, 1, "server", "GET /DELETE", (char *)srvcmd);
647 #endif /* CKSYSLOG */
648         BEGIN ssinit;
649     }
650 #endif /* NOSERVER */
651 }
652
653 <serve>V {                              /* GET /RECURSIVE */
654 #ifndef NOSERVER
655     recursive = 1;                      /* Set these before sgetinit() */
656     if (fnspath == PATH_OFF)
657       fnspath = PATH_REL;               /* Don't worry, they will be */
658     if (x_login && !x_logged) {         /* reset next time through. */
659         errpkt((CHAR *)"Login required");
660         RESUME;
661     } else if (sgetinit(0,0) < 0) {
662         RESUME;
663     } else {
664 #ifdef CKSYSLOG
665         if (ckxsyslog >= SYSLG_PR && ckxlogging)
666           cksyslog(SYSLG_PR, 1, "server", "GET /RECURSIVE", (char *)srvcmd);
667 #endif /* CKSYSLOG */
668         BEGIN ssinit;
669     }
670 #endif /* NOSERVER */
671 }
672
673 <serve>W {                              /* GET /RECURSIVE /DELETE */
674 #ifndef NOSERVER
675     recursive = 1;                      /* Set these before sgetinit() */
676     if (fnspath == PATH_OFF)
677       fnspath = PATH_REL;               /* Don't worry, they will be */
678     moving = 1;                         /* reset next time through. */
679     if (x_login && !x_logged) {
680         errpkt((CHAR *)"Login required");
681         RESUME;
682     } else if (!ENABLED(en_del)) {
683         errpkt((CHAR *)"Deleting files is disabled");
684         RESUME;
685     } else if (sgetinit(0,0) < 0) {
686         RESUME;
687     } else {
688 #ifdef CKSYSLOG
689         if (ckxsyslog >= SYSLG_PR && ckxlogging)
690           cksyslog(SYSLG_PR,1,"server",
691                    "GET /RECURSIVE /DELETE",(char *)srvcmd);
692 #endif /* CKSYSLOG */
693         BEGIN ssinit;
694     }
695 #endif /* NOSERVER */
696 }
697
698 <serve>J {                              /* GET /RECOVER (REGET) */
699 #ifndef NOSERVER
700     if (x_login && !x_logged) {
701         errpkt((CHAR *)"Login required");
702         SERVE;
703     } else if (sgetinit(1,0) < 0) {
704         RESUME;
705     } else {
706 #ifdef CKSYSLOG
707         if (ckxsyslog >= SYSLG_PR && ckxlogging)
708           cksyslog(SYSLG_PR, 1, "server", "GET /RECOVER", (char *)srvcmd);
709 #endif /* CKSYSLOG */
710         BEGIN ssinit;
711     }
712 #endif /* NOSERVER */
713 }
714
715 <serve>O {                              /* Extended GET */
716 #ifndef NOSERVER
717     if (x_login && !x_logged) {         /* (any combination of options) */
718         errpkt((CHAR *)"Login required");
719         SERVE;
720     } else if ((x = sgetinit(0,1)) < 0) {
721         debug(F101,"CKCPRO <serve>O sgetinit fail","",x);
722         RESUME;
723     } else if (x == 0) {
724         debug(F101,"CKCPRO <serve>O sgetinit done","",x);
725 #ifdef CKSYSLOG
726         if (ckxsyslog >= SYSLG_PR && ckxlogging)
727           cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
728 #endif /* CKSYSLOG */
729         BEGIN ssinit;
730     } else {                            /* Otherwise stay in this state */
731         debug(F101,"CKCPRO <serve>O sgetinit TBC","",x);
732         ack();
733         BEGIN ropkt;
734     }
735 #endif /* NOSERVER */
736 }
737
738 <ropkt>O {
739 #ifndef NOSERVER
740     if (x_login && !x_logged) {         /* (any combination of options) */
741         errpkt((CHAR *)"Login required");
742         SERVE;
743     } else if ((x = sgetinit(0,1)) < 0) {
744         debug(F101,"CKCPRO <ropkt>O sgetinit fail","",x);
745         RESUME;
746     } else if (x == 0) {
747         debug(F101,"CKCPRO <ropkt>O sgetinit done","",x);
748 #ifdef CKSYSLOG
749         if (ckxsyslog >= SYSLG_PR && ckxlogging)
750           cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
751 #endif /* CKSYSLOG */
752         BEGIN ssinit;
753     } else {                            /* Otherwise stay in this state */
754         debug(F101,"CKCPRO <ropkt>O sgetinit TBC","",x);
755         ack();
756     }
757 #endif /* NOSERVER */
758 }
759
760 <serve>G {                              /* Generic server command */
761 #ifndef NOSERVER
762     srvptr = srvcmd;                    /* Point to command buffer */
763     decode(rdatap,putsrv,0);            /* Decode packet data into it */
764     putsrv(NUL);                        /* Insert a couple nulls */
765     putsrv(NUL);                        /* for termination */
766     if (srvcmd[0]) {
767         sstate = srvcmd[0];             /* Set requested start state */
768         if (x_login && !x_logged &&     /* Login required? */
769             /* Login, Logout, and Help are allowed when not logged in */
770             sstate != 'I' && sstate != 'L' && sstate != 'H') {
771             errpkt((CHAR *)"Login required");
772             SERVE;
773         } else {
774             nakstate = 0;               /* Now I'm the sender. */
775             what = W_REMO;              /* Doing a REMOTE command. */
776 #ifdef STREAMING
777             if (!streaming)
778 #endif /* STREAMING */
779               if (timint < 1)
780                 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
781             binary = XYFT_T;            /* Switch to text mode */
782             BEGIN generic;              /* Switch to generic command state */
783         }
784     } else {
785         errpkt((CHAR *)"Badly formed server command"); /* report error */
786         RESUME;                 /* & go back to server command wait */
787     }
788 #endif /* NOSERVER */
789 }
790
791 <serve>C {                              /* Receive Host command */
792 #ifndef NOSERVER
793     if (x_login && !x_logged) {
794         errpkt((CHAR *)"Login required");
795         SERVE;
796     } else if (!ENABLED(en_hos)) {
797         errpkt((CHAR *)"REMOTE HOST disabled");
798         RESUME;
799     } else if (nopush) {
800         errpkt((CHAR *)"HOST commands not available");
801         RESUME;
802     } else {
803         srvptr = srvcmd;                /* Point to command buffer */
804         decode(rdatap,putsrv,0);        /* Decode command packet into it */
805         putsrv(NUL);                    /* Null-terminate */
806         nakstate = 0;                   /* Now sending, not receiving */
807         binary = XYFT_T;                /* Switch to text mode */
808         if (syscmd((char *)srvcmd,"")) { /* Try to execute the command */
809             what = W_REMO;              /* Doing a REMOTE command. */
810 #ifdef STREAMING
811             if (!streaming)
812 #endif /* STREAMING */
813               if (timint < 1)
814                 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
815 #ifdef CKSYSLOG
816             if (ckxsyslog >= SYSLG_PR && ckxlogging)
817               cksyslog(SYSLG_PR, 1, "server", "REMOTE HOST", (char *)srvcmd);
818 #endif /* CKSYSLOG */
819             BEGIN ssinit;               /* If OK, send back its output */
820         } else {                        /* Otherwise */
821             errpkt((CHAR *)"Can't do system command"); /* report error */
822             RESUME;                     /* & go back to server command wait */
823         }
824     }
825 #endif /* NOSERVER */
826 }
827
828 <serve>q {                              /* Interrupted or connection lost */
829     rc = srv_timeout();
830     debug(F101,"srv_timeout","",rc);
831     if (rc > -1) return(rc);            /* (see below) */
832 }
833
834 <serve>N {                              /* Server got a NAK in command-wait */
835 #ifndef NOSERVER
836     errpkt((CHAR *)"Did you say RECEIVE instead of GET?");
837     RESUME;
838 #endif /* NOSERVER */
839 }
840
841 <serve>. {                              /* Any other command in this state */
842 #ifndef NOSERVER
843     if (c != ('E' - SP) && c != ('Y' - SP)) /* except E and Y packets. */
844       errpkt((CHAR *)"Unimplemented server function");
845     /* If we answer an E with an E, we get an infinite loop. */
846     /* A Y (ACK) can show up here if we sent back a short-form reply to */
847     /* a G packet and it was echoed.  ACKs can be safely ignored here. */
848     RESUME;                             /* Go back to server command wait. */
849 #endif /* NOSERVER */
850 }
851
852 <generic>I {                            /* Login/Out */
853     rc = srv_login();
854     debug(F101,"<generic>I srv_login","",rc);
855     if (rc > -1) return(rc);            /* (see below) */
856 }
857
858 <generic>C {                            /* Got REMOTE CD command */
859 #ifndef NOSERVER
860 #ifdef CKSYSLOG
861     if (ckxsyslog >= SYSLG_PR && ckxlogging)
862       cksyslog(SYSLG_PR, 1, "server", "REMOTE CD", (char *)srvcmd);
863 #endif /* CKSYSLOG */
864     if (!ENABLED(en_cwd)) {
865         errpkt((CHAR *)"REMOTE CD disabled");
866         RESUME;
867     } else {
868         char * p = NULL;
869         x = cwd((char *)(srvcmd+1));    /* Try to change directory */
870 #ifdef IKSDB
871         if (ikdbopen) slotstate(what,"REMOTE CD", (char *)(srvcmd+2), "");
872 #endif /* IKSDB */
873         if (!x) {                       /* Failed */
874             errpkt((CHAR *)"Can't change directory");
875             RESUME;                     /* Back to server command wait */
876         } else if (x == 2) {            /* User wants message */
877             if (!ENABLED(en_typ)) {     /* Messages (REMOTE TYPE) disabled? */
878                 errpkt((CHAR *)"REMOTE TYPE disabled");
879                 RESUME;
880             } else {                    /* TYPE is enabled */
881                 int i;
882                 for (i = 0; i < 8; i++) {
883                     if (zchki(cdmsgfile[i]) > -1) {
884                         break;
885                     }
886                 }
887                 binary = XYFT_T;        /* Use text mode for this. */
888                 if (i < 8 && sndtype(cdmsgfile[i])) { /* Have readme file? */
889                     BEGIN ssinit;       /* OK */
890                 } else {                /* not OK */
891                     p = zgtdir();
892                     if (!p) p = "";
893                     success = (*p) ? 1 : 0;
894                     ack1((CHAR *)p);    /* ACK with new directory name */
895                     success = 1;
896                     RESUME;             /* wait for next server command */
897                 }
898             }
899         } else {                        /* User doesn't want message */
900             p = zgtdir();
901             if (!p) p = "";
902             success = (*p) ? 1 : 0;
903             ack1((CHAR *)p);
904             success = 1;
905             RESUME;                     /* Wait for next server command */
906         }
907     }
908 #endif /* NOSERVER */
909 }
910
911 <generic>A {                            /* Got REMOTE PWD command */
912 #ifndef NOSERVER
913 #ifdef CKSYSLOG
914     if (ckxsyslog >= SYSLG_PR && ckxlogging)
915       cksyslog(SYSLG_PR, 1, "server", "REMOTE PWD", NULL);
916 #endif /* CKSYSLOG */
917     if (!ENABLED(en_cwd)) {
918         errpkt((CHAR *)"REMOTE CD disabled");
919         RESUME;
920     } else {
921         if (encstr((CHAR *)zgtdir()) > -1) { /* Encode current directory */
922             ack1(data);                 /* If it fits, send it back in ACK */
923             success = 1;
924         } else {                        /* Failed */
925             ack();                      /* Send empty ACK */
926             success = 0;                /* and indicate failure locally */
927         }
928         RESUME;                         /* Back to server command wait */
929     }
930 #endif /* NOSERVER */
931 }
932
933 <generic>D {                            /* REMOTE DIRECTORY command */
934 #ifndef NOSERVER
935     char *n2;
936 #ifdef CKSYSLOG
937     if (ckxsyslog >= SYSLG_PR && ckxlogging)
938       cksyslog(SYSLG_PR, 1, "server", "REMOTE DIRECTORY", (char *)srvcmd);
939 #endif /* CKSYSLOG */
940     if (!ENABLED(en_dir)) {             /* If DIR is disabled, */
941         errpkt((CHAR *)"REMOTE DIRECTORY disabled"); /* refuse. */
942         RESUME;
943     } else {                            /* DIR is enabled. */
944 #ifdef IKSDB
945         if (ikdbopen) slotstate(what,"REMOTE DIR", (char *)(srvcmd+2), "");
946 #endif /* IKSDB */
947         if (!ENABLED(en_cwd)) {         /* But CWD is disabled */
948             zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
949             if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
950                 errpkt((CHAR *)"Access denied");
951                 RESUME;                 /* Remember, this is not a goto! */
952             }
953         }
954         if (state == generic) {                 /* It's OK to go ahead. */
955 #ifdef COMMENT
956             n2 = (*(srvcmd+2)) ? DIRCMD : DIRCM2;
957             if (syscmd(n2,(char *)(srvcmd+2)))  /* If it can be done */
958 #else
959             int x;
960             if ((x = snddir((char*)(srvcmd+2))) > 0)
961 #endif /* COMMENT */
962             {
963                 BEGIN ssinit;           /* send the results back; */
964             } else {                    /* otherwise */
965                 if (x < 0)
966                   errpkt((CHAR *)"No files match");
967                 else
968                   errpkt((CHAR *)"Can't list directory");
969                 RESUME;                 /* return to server command wait */
970             }
971         }
972     }
973 #endif /* NOSERVER */
974 }
975
976 <generic>E {                            /* REMOTE DELETE (Erase) */
977 #ifndef NOSERVER
978     char *n2;
979 #ifdef CKSYSLOG
980     if (ckxsyslog >= SYSLG_PR && ckxlogging)
981       cksyslog(SYSLG_PR, 1, "server", "REMOTE DELETE", (char *)srvcmd);
982 #endif /* CKSYSLOG */
983     if (!ENABLED(en_del)) {
984         errpkt((CHAR *)"REMOTE DELETE disabled");
985         RESUME;
986     } else {                            /* DELETE is enabled */
987 #ifdef IKSDB
988         if (ikdbopen) slotstate(what,"REMOTE DELETE", (char *)(srvcmd+2), "");
989 #endif /* IKSDB */
990         if (!ENABLED(en_cwd)) {         /* but CWD is disabled */
991             zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
992             if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
993                 errpkt((CHAR *)"Access denied");
994                 RESUME;                 /* Remember, this is not a goto! */
995             }
996         } else if (isdir((char *)(srvcmd+2))) { /* A directory name? */
997             errpkt((CHAR *)"It's a directory");
998             RESUME;
999         }
1000         if (state == generic) {         /* It's OK to go ahead. */
1001             int x;
1002             if ((x = snddel((char*)(srvcmd+2))) > 0) {
1003                 BEGIN ssinit;           /* If OK send results back */
1004             } else {                    /* otherwise */
1005                 if (x < 0)
1006                   errpkt((CHAR *)"File not found"); /* report failure */
1007                 else
1008                   errpkt((CHAR *)"DELETE failed");
1009                 RESUME;                 /* & return to server command wait */
1010             }
1011         }
1012     }
1013 #endif /* NOSERVER */
1014 }
1015
1016 <generic>F {                            /* FINISH */
1017 #ifndef NOSERVER
1018 #ifdef CKSYSLOG
1019     if (ckxsyslog >= SYSLG_PR && ckxlogging)
1020       cksyslog(SYSLG_PR, 1, "server", "FINISH", NULL);
1021 #endif /* CKSYSLOG */
1022 #ifdef IKSDB
1023     if (ikdbopen) slotstate(what,"SERVER FINISH", "", "");
1024 #endif /* IKSDB */
1025     if (!ENABLED(en_fin)) {
1026         errpkt((CHAR *)"FINISH disabled");
1027         RESUME;
1028     } else {
1029         ack();                          /* Acknowledge */
1030         xxscreen(SCR_TC,0,0L,"");       /* Display */
1031         success = 1;
1032         return(0);                      /* Done */
1033     }
1034 #endif /* NOSERVER */
1035 }
1036
1037 <generic>X {                            /* EXIT */
1038 #ifndef NOSERVER
1039 #ifdef CKSYSLOG
1040     if (ckxsyslog >= SYSLG_PR && ckxlogging)
1041       cksyslog(SYSLG_PR, 1, "server", "REMOTE EXIT", NULL);
1042 #endif /* CKSYSLOG */
1043 #ifdef IKSDB
1044     if (ikdbopen) slotstate(what,"REMOTE EXIT", "", "");
1045 #endif /* IKSDB */
1046     if (!ENABLED(en_xit)) {
1047         errpkt((CHAR *)"EXIT disabled");
1048         RESUME;
1049     } else {
1050         ack();                          /* Acknowledge */
1051         xxscreen(SCR_TC,0,0L,"");       /* Display */
1052         doexit(GOOD_EXIT,xitsta);
1053     }
1054 #endif /* NOSERVER */
1055 }
1056
1057 <generic>L {                            /* BYE (Logout) */
1058 #ifndef NOSERVER
1059 #ifdef CKSYSLOG
1060     if (ckxsyslog >= SYSLG_PR && ckxlogging)
1061       cksyslog(SYSLG_PR, 1, "server", "BYE", NULL);
1062 #endif /* CKSYSLOG */
1063 #ifdef IKSDB
1064     if (ikdbopen) slotstate(what,"SERVER BYE", "", "");
1065 #endif /* IKSDB */
1066     if (!ENABLED(en_bye)) {
1067         errpkt((CHAR *)"BYE disabled");
1068         RESUME;
1069     } else {
1070         ack();                          /* Acknowledge */
1071         success = 1;
1072         msleep(750);                    /* Give the ACK time to get out */
1073         if (local)
1074           ttres();                      /* Reset the terminal */
1075         xxscreen(SCR_TC,0,0L,"");       /* Display */
1076         doclean(1);                     /* Clean up files, etc */
1077 #ifdef DEBUG
1078         debug(F100,"C-Kermit BYE - Logging out...","",0);
1079         zclose(ZDFILE);
1080 #endif /* DEBUG */
1081 #ifdef IKSD
1082 #ifdef CK_LOGIN
1083         if (inserver)
1084           ckxlogout();
1085         else
1086 #endif /* CK_LOGIN */
1087 #endif /* IKSD */
1088 #ifdef TCPSOCKET
1089 #ifndef NOLISTEN
1090           if (network && tcpsrfd > 0 && !inserver)
1091             doexit(GOOD_EXIT,xitsta);
1092         else
1093 #endif /* NOLISTEN */
1094 #endif /* TCPSOCKET */
1095           return(zkself());             /* Try to log self out */
1096     }
1097 #endif /* NOSERVER */
1098 }
1099
1100 <generic>H {                            /* REMOTE HELP */
1101 #ifdef CKSYSLOG
1102     if (ckxsyslog >= SYSLG_PR && ckxlogging)
1103       cksyslog(SYSLG_PR, 1, "server", "REMOTE HELP", NULL);
1104 #endif /* CKSYSLOG */
1105 #ifdef IKSDB
1106     if (ikdbopen) slotstate(what,"REMOTE HELP", "", "");
1107 #endif /* IKSDB */
1108 #ifndef NOSERVER
1109     if (sndhlp()) {
1110         BEGIN ssinit;                   /* try to send it */
1111     } else {                            /* If not ok, */
1112         errpkt((CHAR *)"Can't send help"); /* send error message instead */
1113         RESUME;                         /* and return to server command wait */
1114     }
1115 #endif /* NOSERVER */
1116 }
1117
1118 <generic>R {                            /* REMOTE RENAME */
1119     rc = srv_rename();
1120     debug(F101,"srv_rename","",rc);
1121     if (rc > -1) return(rc);            /* (see below) */
1122 }
1123
1124 <generic>K {                            /* REMOTE COPY */
1125     rc = srv_copy();
1126     debug(F101,"srv_copy","",rc);
1127     if (rc > -1) return(rc);            /* (see below) */
1128 }
1129
1130 <generic>S {                            /* REMOTE SET */
1131 #ifdef CKSYSLOG
1132     if (ckxsyslog >= SYSLG_PR && ckxlogging)
1133       cksyslog(SYSLG_PR, 1, "server", "REMOTE SET", (char *)srvcmd);
1134 #endif /* CKSYSLOG */
1135 #ifndef NOSERVER
1136 #ifdef IKSDB
1137     if (ikdbopen) slotstate(what,"REMOTE SET", (char *)(srvcmd+1), "");
1138 #endif /* IKSDB */
1139     if (!ENABLED(en_set)) {
1140         errpkt((CHAR *)"REMOTE SET disabled");
1141         RESUME;
1142     } else {
1143         if (remset((char *)(srvcmd+1))) { /* Try to do what they ask */
1144             success = 1;
1145             ack();                      /* If OK, then acknowledge */
1146         } else                          /* Otherwise */
1147           errpkt((CHAR *)"Unknown REMOTE SET parameter"); /* give error msg */
1148         RESUME;                         /* Return to server command wait */
1149     }
1150 #endif /* NOSERVER */
1151 }
1152
1153 <generic>T {                            /* REMOTE TYPE */
1154 #ifndef NOSERVER
1155     char *n2;
1156 #ifdef CKSYSLOG
1157     if (ckxsyslog >= SYSLG_PR && ckxlogging)
1158       cksyslog(SYSLG_PR, 1, "server", "REMOTE TYPE", (char *)srvcmd);
1159 #endif /* CKSYSLOG */
1160     if (!ENABLED(en_typ)) {
1161         errpkt((CHAR *)"REMOTE TYPE disabled");
1162         RESUME;
1163     } else {
1164 #ifdef IKSDB
1165         if (ikdbopen) slotstate(what,"REMOTE TYPE", (char *)(srvcmd+2), "");
1166 #endif /* IKSDB */
1167         if (!ENABLED(en_cwd)) {         /* If CWD disabled */
1168             zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
1169             if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */
1170                 errpkt((CHAR *)"Access denied");
1171                 RESUME;                 /* Remember, this is not a goto! */
1172             }
1173         }
1174         if (state == generic) {         /* It's OK to go ahead. */
1175             binary = XYFT_T;            /* Use text mode for this. */
1176             if (                        /* (RESUME didn't change state) */
1177 #ifdef COMMENT
1178               syscmd(TYPCMD,(char *)(srvcmd+2)) /* Old way */
1179 #else
1180               sndtype((char *)(srvcmd+2)) /* New way */
1181 #endif /* COMMENT */
1182                 )
1183               BEGIN ssinit;             /* OK */
1184             else {                      /* not OK */
1185                 errpkt((CHAR *)"Can't type file"); /* give error message */
1186                 RESUME;                 /* wait for next server command */
1187             }
1188         }
1189     }
1190 #endif /* NOSERVER */
1191 }
1192
1193 <generic>m {                            /* REMOTE MKDIR */
1194 #ifndef NOSERVER
1195 #ifdef CK_MKDIR
1196 #ifdef CKSYSLOG
1197     if (ckxsyslog >= SYSLG_PR && ckxlogging)
1198       cksyslog(SYSLG_PR, 1, "server", "REMOTE MKDIR", (char *)srvcmd);
1199 #endif /* CKSYSLOG */
1200 #ifdef IKSDB
1201     if (ikdbopen) slotstate(what,"REMOTE MKDIR", (char *)(srvcmd+2), "");
1202 #endif /* IKSDB */
1203     if (!ENABLED(en_mkd)) {
1204         errpkt((CHAR *)"REMOTE MKDIR disabled");
1205         RESUME;
1206     } else if (!ENABLED(en_cwd)) {      /* If CWD disabled */
1207         errpkt((CHAR *)"Directory access restricted");
1208         RESUME;                         /* Remember, this is not a goto! */
1209     }
1210     if (state == generic) {             /* OK to go ahead. */
1211         char *p = NULL;
1212         x = ckmkdir(0,(char *)(srvcmd+2),&p,0,1); /* Make the directory */
1213         if (!p) p = "";
1214         if (x > -1) {
1215             encstr((CHAR *)p);          /* OK - encode the name */
1216             ack1(data);                 /* Send short-form response */
1217             success = 1;
1218             RESUME;
1219         } else {                        /* not OK */
1220             if (!*p) p = "Directory creation failure";
1221             errpkt((CHAR *)p);          /* give error message */
1222             RESUME;                     /* Wait for next server command */
1223         }
1224     }
1225 #else
1226     errpkt((CHAR *)"REMOTE MKDIR not available");
1227     RESUME;
1228 #endif /* CK_MKDIR */
1229 #endif /* NOSERVER */
1230 }
1231
1232 <generic>d {                            /* REMOTE RMDIR */
1233 #ifndef NOSERVER
1234 #ifdef CK_MKDIR
1235 #ifdef CKSYSLOG
1236     if (ckxsyslog >= SYSLG_PR && ckxlogging)
1237       cksyslog(SYSLG_PR, 1, "server", "REMOTE RMDIR", (char *)srvcmd);
1238 #endif /* CKSYSLOG */
1239 #ifdef IKSDB
1240     if (ikdbopen) slotstate(what,"REMOTE RMDIR", (char *)(srvcmd+2), "");
1241 #endif /* IKSDB */
1242     if (!ENABLED(en_rmd)) {
1243         errpkt((CHAR *)"REMOTE RMDIR disabled");
1244         RESUME;
1245     } else if (!ENABLED(en_cwd)) {      /* If CWD disabled */
1246         errpkt((CHAR *)"Directory access restricted");
1247         RESUME;                         /* Remember, this is not a goto! */
1248     }
1249     if (state == generic) {             /* OK to go ahead. */
1250         char *p = NULL;
1251         x = ckmkdir(1,(char *)(srvcmd+2),&p,0,1);
1252         if (!p) p = "";
1253         if (x > -1) {
1254             encstr((CHAR *)p);          /* OK - encode the name */
1255             ack1(data);                 /* Send short-form response */
1256             success = 1;
1257             RESUME;
1258         } else {                        /* not OK */
1259             if (!*p) p = "Directory removal failure";
1260             errpkt((CHAR *)p);          /* give error message */
1261             RESUME;                     /* Wait for next server command */
1262         }
1263     }
1264 #else
1265     errpkt((CHAR *)"REMOTE RMDIR not available");
1266     RESUME;
1267 #endif /* CK_MKDIR */
1268 #endif /* NOSERVER */
1269 }
1270
1271 <generic>U {                            /* REMOTE SPACE */
1272 #ifndef NOSERVER
1273 #ifdef CKSYSLOG
1274     if (ckxsyslog >= SYSLG_PR && ckxlogging)
1275       cksyslog(SYSLG_PR, 1, "server", "REMOTE SPACE", (char *)srvcmd);
1276 #endif /* CKSYSLOG */
1277     if (!ENABLED(en_spa)) {
1278         errpkt((CHAR *)"REMOTE SPACE disabled");
1279         RESUME;
1280     } else {
1281         x = srvcmd[1];                  /* Get area to check */
1282         x = ((x == NUL) || (x == SP)
1283 #ifdef OS2
1284              || (x == '!') || (srvcmd[3] == ':')
1285 #endif /* OS2 */
1286              );
1287 #ifdef IKSDB
1288         if (ikdbopen) slotstate(what,
1289                               "REMOTE SPACE",
1290                               (x ? "" : (char *)srvcmd),
1291                               ""
1292                               );
1293 #endif /* IKSDB */
1294         if (!x && !ENABLED(en_cwd)) {   /* CWD disabled */
1295             errpkt((CHAR *)"Access denied"); /* and non-default area given, */
1296             RESUME;                     /* refuse. */
1297         } else {
1298 #ifdef OS2
1299 _PROTOTYP(int sndspace,(int));
1300             if (sndspace(x ? toupper(srvcmd[2]) : 0)) {
1301                 BEGIN ssinit;           /* send the report. */
1302             } else {                    /* If not ok, */
1303                 errpkt((CHAR *)"Can't send space"); /* send error message */
1304                 RESUME;                 /* and return to server command wait */
1305             }
1306 #else
1307             if (nopush)
1308               x = 0;
1309             else
1310               x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,(char *)(srvcmd+2)));
1311             if (x) {                    /* If we got the info */
1312                 BEGIN ssinit;           /* send it */
1313             } else {                    /* otherwise */
1314                 errpkt((CHAR *)"Can't check space"); /* send error message */
1315                 RESUME;                 /* and await next server command */
1316             }
1317 #endif /* OS2 */
1318         }
1319     }
1320 #endif /* NOSERVER */
1321 }
1322
1323 <generic>W {                            /* REMOTE WHO */
1324 #ifndef NOSERVER
1325 #ifdef CKSYSLOG
1326     if (ckxsyslog >= SYSLG_PR && ckxlogging)
1327       cksyslog(SYSLG_PR, 1, "server", "REMOTE WHO", (char *)srvcmd);
1328 #endif /* CKSYSLOG */
1329 #ifdef IKSDB
1330     if (ikdbopen) slotstate(what,"REMOTE WHO", (char *)(srvcmd+2), "");
1331 #endif /* IKSDB */
1332     if (!ENABLED(en_who)) {
1333         errpkt((CHAR *)"REMOTE WHO disabled");
1334         RESUME;
1335     } else {
1336 #ifdef OS2
1337 _PROTOTYP(int sndwho,(char *));
1338             if (sndwho((char *)(srvcmd+2))) {
1339                 BEGIN ssinit;           /* try to send it */
1340             } else {                    /* If not ok, */
1341                 errpkt((CHAR *)"Can't do who command"); /* send error msg */
1342                 RESUME;                 /* and return to server command wait */
1343             }
1344 #else
1345         if (syscmd(WHOCMD,(char *)(srvcmd+2))) {
1346             BEGIN ssinit;
1347         } else {
1348             errpkt((CHAR *)"Can't do who command");
1349             RESUME;
1350         }
1351 #endif /* OS2 */
1352     }
1353 #endif /* NOSERVER */
1354 }
1355
1356 <generic>V {                            /* Variable query or set */
1357     rc = srv_query();
1358     debug(F101,"srv_query","",rc);
1359     if (rc > -1) return(rc);
1360 }
1361
1362 <generic>M {                            /* REMOTE MESSAGE command */
1363 #ifndef NOSERVER
1364     debug(F110,"RMSG",(char *)srvcmd+2,0);
1365     xxscreen(SCR_MS,0,0L,(char *)(srvcmd+2));
1366     ack();
1367     RESUME;
1368 #endif  /* NOSERVER */
1369 }
1370
1371 <generic>q {                            /* Interrupted or connection lost */
1372 #ifndef NOSERVER
1373     if (fatalio) {                      /* Connection lost */
1374 #ifdef CKSYSLOG
1375         if (ckxsyslog >= SYSLG_PR && ckxlogging)
1376           cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
1377 #endif /* CKSYSLOG */
1378         success = 0;
1379         xitsta |= (what & W_KERMIT);
1380         QUIT;
1381     } else if (interrupted) {
1382         if (!ENABLED(en_fin)) {         /* Ctrl-C typed */
1383             errpkt((CHAR *)"QUIT disabled");
1384             RESUME;
1385         } else {
1386 #ifdef CKSYSLOG
1387             if (ckxsyslog >= SYSLG_PR && ckxlogging)
1388               cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
1389 #endif /* CKSYSLOG */
1390             success = 0;
1391             xitsta |= (what & W_KERMIT);
1392             QUIT;
1393         }
1394     } else {                            /* Shouldn't happen */
1395         debug(F100,"SERVER (generic) GOT UNEXPECTED 'q'","",0);
1396         QUIT;
1397     }
1398 #endif /* NOSERVER */
1399 }
1400
1401 <generic>. {                            /* Anything else in this state... */
1402 #ifndef NOSERVER
1403     errpkt((CHAR *)"Unimplemented REMOTE command"); /* Complain */
1404     RESUME;                             /* and return to server command wait */
1405 #endif /* NOSERVER */
1406 }
1407
1408 <rgen>q {                               /* Sent BYE and connection broken */
1409     if (bye_active && ttchk() < 0) {
1410         msleep(500);
1411         bye_active = 0;
1412         ttclos(0);                      /* Close our end of the connection */
1413         clsof(0);
1414         return(success = 1);
1415     } else {                            /* Other generic command */
1416         return(success = 0);            /* or connection not broken */
1417     }
1418 }
1419
1420 <rgen>Y {                               /* Short-Form reply */
1421     rc = rcv_shortreply();
1422     debug(F101,"<rgen>Y rcv_shortreply","",rc);
1423     if (rc > -1) return(rc);
1424 }
1425
1426 <rgen,rfile>F {                         /* File header */
1427     /* char *n2; */
1428     extern int rsn;
1429     debug(F101,"<rfile>F winlo 1","",winlo);
1430     xflg = 0;                           /* Not screen data */
1431     if (!czseen)
1432       cancel = 0;                       /* Reset cancellation counter */
1433 #ifdef CALIBRATE
1434     if (dest == DEST_N)
1435       calibrate = 1;
1436 #endif /* CALIBRATE */
1437     if (!rcvfil(filnam)) {              /* Figure out local filename */
1438         errpkt((CHAR *)rf_err);         /* Trouble */
1439         RESUME;
1440     } else {                            /* Real file, OK to receive */
1441         char * fnp;
1442         debug(F111,"<rfile>F winlo 2",fspec,winlo);
1443         if (filcnt == 1)                /* rcvfil set this to 1 for 1st file */
1444           crc16 = 0L;                   /* Clear file CRC */
1445         fnp = fspec;                    /* This is the full path */
1446         if (server && !ENABLED(en_cwd) || /* if DISABLE CD */
1447             !fackpath                     /* or F-ACK-PATH OFF */
1448             ) {
1449             zstrip(fspec,&fnp);         /* don't send back full path */
1450         }
1451         encstr((CHAR *)fnp);
1452         if (fackbug)
1453           ack();
1454         else
1455           ack1(data);                   /* Send it back in ACK */
1456         initattr(&iattr);               /* Clear file attribute structure */
1457         streamon();
1458         if (window(wslotn) < 0) {       /* Allocate negotiated window slots */
1459             errpkt((CHAR *)"Can't open window");
1460             RESUME;
1461         }
1462 #ifdef IKSDB
1463         if (ikdbopen) slotstate(what,
1464                               server ? "SERVER" : "",
1465                               "RECEIVE",
1466                               fspec
1467                               );
1468 #endif /* IKSDB */
1469         BEGIN rattr;                    /* Now expect Attribute packets */
1470     }
1471 }
1472
1473 <rgen,rfile>X {                         /* X-packet instead of file header */
1474     xflg = 1;                           /* Screen data */
1475     if (!czseen)
1476       cancel = 0;                       /* Reset cancellation counter */
1477     ack();                              /* Acknowledge the X-packet */
1478     initattr(&iattr);                   /* Initialize attribute structure */
1479     streamon();
1480     if (window(wslotn) < 0) {           /* allocate negotiated window slots */
1481         errpkt((CHAR *)"Can't open window");
1482         RESUME;
1483     }
1484 #ifndef NOSPL
1485     if (query) {                        /* If this is the response to */
1486         qbufp = querybuf;               /* a query that we sent, initialize */
1487         qbufn = 0;                      /* the response buffer */
1488         querybuf[0] = NUL;
1489     }
1490 #endif /* NOSPL */
1491     what = W_REMO;                      /* we're doing a REMOTE command */
1492 #ifdef IKSDB
1493     if (ikdbopen) slotstate(what,
1494                           server ? "SERVER" : "",
1495                           "RECEIVE",
1496                           fspec
1497                           );
1498 #endif /* IKSDB */
1499     BEGIN rattr;                        /* Expect Attribute packets */
1500 }
1501
1502 <rattr>A {                              /* Attribute packet */
1503     if (gattr(rdatap,&iattr) == 0) {    /* Read into attribute structure */
1504 #ifdef CK_RESEND
1505         ack1((CHAR *)iattr.reply.val);  /* Reply with data */
1506 #else
1507         ack();                          /* If OK, acknowledge */
1508 #endif /* CK_RESEND */
1509     } else {                            /* Otherwise */
1510         extern long fsize;
1511         char *r;
1512         r = getreason(iattr.reply.val);
1513         ack1((CHAR *)iattr.reply.val);  /* refuse to accept the file */
1514         xxscreen(SCR_ST,ST_REFU,0L,r);  /* reason */
1515 #ifdef TLOG
1516         if (tralog && !tlogfmt)
1517           doxlog(what,filnam,fsize,binary,1,r);
1518 #endif /* TLOG */
1519     }
1520 }
1521
1522 <rattr>D {                              /* First data packet */
1523     debug(F100,"<rattr> D firstdata","",0);
1524     rc = rcv_firstdata();
1525     debug(F101,"rcv_firstdata rc","",rc);
1526     if (rc > -1) return(rc);            /* (see below) */
1527 }
1528
1529 <rfile>B {                              /* EOT, no more files */
1530     ack();                              /* Acknowledge the B packet */
1531     reot();                             /* Do EOT things */
1532 #ifdef CK_TMPDIR
1533 /* If we were cd'd temporarily to another device or directory ... */
1534     if (f_tmpdir) {
1535         int x;
1536         x = zchdir((char *) savdir);    /* ... restore previous directory */
1537         f_tmpdir = 0;                   /* and remember we did it. */
1538         debug(F111,"ckcpro.w B tmpdir restoring",savdir,x);
1539     }
1540 #endif /* CK_TMPDIR */
1541     RESUME;                             /* and quit */
1542 }
1543
1544 <rdpkt>D {                              /* Got Data packet */
1545     debug(F101,"<rdpkt>D cxseen","",cxseen);
1546     debug(F101,"<rdpkt>D czseen","",czseen);
1547     if (cxseen || czseen || discard) {  /* If file or group interruption */
1548         CHAR * msg;
1549         msg = czseen ? (CHAR *)"Z" : (CHAR *)"X";
1550 #ifdef STREAMING
1551         if (streaming) {                /* Need to cancel */
1552             debug(F111,"<rdpkt>D streaming cancel",msg,cancel);
1553             if (cancel++ == 0) {        /* Only do this once */
1554                 ack1(msg);              /* Put "X" or "Z" in ACK */
1555             } else if (czseen) {
1556                 errpkt((CHAR *)"User canceled");
1557                 RESUME;
1558             } else {
1559                 fastack();
1560             }
1561         } else
1562 #endif /* STREAMING */
1563           ack1(msg);
1564     } else {                            /* No interruption */
1565         int rc, qf;
1566 #ifndef NOSPL
1567         qf = query;
1568 #else
1569         qf = 0;
1570 #endif /* NOSPL */
1571 #ifdef CKTUNING
1572         rc = (binary && !parity) ?
1573           bdecode(rdatap,putfil):
1574             decode(rdatap, qf ? puttrm : putfil, 1);
1575 #else
1576         rc = decode(rdatap, qf ? puttrm : putfil, 1);
1577 #endif /* CKTUNING */
1578         if (rc < 0) {
1579             discard = (keep == 0 || (keep == SET_AUTO && binary != XYFT_T));
1580             errpkt((CHAR *)"Error writing data"); /* If failure, */
1581             RESUME;
1582         } else                          /* Data written OK, send ACK */
1583 #ifdef STREAMING
1584           if (streaming)
1585             fastack();
1586         else
1587 #endif /* STREAMING */
1588           ack();
1589     }
1590 }
1591
1592 <rattr>Z {                              /* EOF immediately after A-Packet. */
1593     rf_err = "Can't create file";
1594     timint = s_timint;
1595     if (discard) {                      /* Discarding a real file... */
1596         x = 1;
1597     } else if (xflg) {                  /* If screen data */
1598         if (remfile) {                  /* redirected to file */
1599             if (rempipe)                /* or pipe */
1600               x = openc(ZOFILE,remdest); /* Pipe: start command */
1601             else
1602               x = opena(remdest,&iattr); /* File: open with attributes */
1603         } else {                        /* otherwise */
1604             x = opent(&iattr);          /* "open" the screen */
1605         }
1606 #ifdef CALIBRATE
1607     } else if (calibrate) {             /* If calibration run */
1608         x = ckopenx(&iattr);            /* do this */
1609 #endif /* CALIBRATE */
1610     } else {                            /* otherwise */
1611         x = opena(filnam,&iattr);       /* open the file, with attributes */
1612         if (x == -17) {                 /* REGET skipped because same size */
1613             discard = 1;
1614             rejection = 1;
1615         }
1616     }
1617     if (!x || reof(filnam, &iattr) < 0) { /* Close output file */
1618         errpkt((CHAR *) rf_err);        /* If problem, send error msg */
1619         RESUME;                         /* and quit */
1620     } else {                            /* otherwise */
1621         if (x == -17)
1622           xxscreen(SCR_ST,ST_SKIP,SKP_RES,"");
1623         ack();                          /* acknowledge the EOF packet */
1624         BEGIN rfile;                    /* and await another file */
1625     }
1626 }
1627
1628 <rdpkt>q {                              /* Ctrl-C or connection loss. */
1629     timint = s_timint;
1630     window(1);                          /* Set window size back to 1... */
1631     cxseen = 1;
1632     x = clsof(1);                       /* Close file */
1633     return(success = 0);                /* Failed */
1634 }
1635
1636 <rdpkt>Z {                              /* End Of File (EOF) Packet */
1637 /*  wslots = 1; */                      /* (don't set) Window size back to 1 */
1638 #ifndef COHERENT /* Coherent compiler blows up on this switch() statement. */
1639     x = reof(filnam, &iattr);           /* Handle the EOF packet */
1640     switch (x) {                        /* reof() sets the success flag */
1641       case -5:                          /* Handle problems */
1642         errpkt((CHAR *)"RENAME failed"); /* Fatal */
1643         RESUME;
1644         break;
1645       case -4:
1646         errpkt((CHAR *)"MOVE failed");  /* Fatal */
1647         RESUME;
1648         break;
1649       case -3:                          /* If problem, send error msg */
1650         errpkt((CHAR *)"Can't print file"); /* Fatal */
1651         RESUME;
1652         break;
1653       case -2:
1654         errpkt((CHAR *)"Can't mail file"); /* Fatal */
1655         RESUME;
1656         break;
1657       case 2:                           /* Not fatal */
1658       case 3:
1659         xxscreen(SCR_EM,0,0L,"Receiver can't delete temp file");
1660         RESUME;
1661         break;
1662       default:
1663         if (x < 0) {                    /* Fatal */
1664             errpkt((CHAR *)"Can't close file");
1665             RESUME;
1666         } else {                        /* Success */
1667 #ifndef NOSPL
1668             if (query)                  /* Query reponses generally */
1669               conoll("");               /* don't have line terminators */
1670 #endif /* NOSPL */
1671             if (czseen) {               /* Batch canceled? */
1672                 if (cancel++ == 0) {    /* If we haven't tried this yet */
1673                     ack1((CHAR *)"Z");  /* Try it once */
1674                 } else {                /* Otherwise */
1675                     errpkt((CHAR *)"User canceled"); /* quite with Error */
1676                     RESUME;
1677                 }
1678             } else
1679               ack();                    /* Acknowledge the EOF packet */
1680             BEGIN rfile;                /* and await another file */
1681         }
1682     }
1683 #else
1684     if (reof(filnam, &iattr) < 0) {     /* Close the file */
1685         errpkt((CHAR *)"Error at end of file");
1686         RESUME;
1687     } else {                            /* reof() sets success flag */
1688         ack();
1689         BEGIN rfile;
1690     }
1691 #endif /* COHERENT */
1692 }
1693
1694 <ssinit>Y {                             /* ACK for Send-Init */
1695     spar(rdatap);                       /* set parameters from it */
1696     cancel = 0;
1697     if (bctf) {
1698         bctu = 3;
1699         bctl = 3;
1700     } else {
1701         bctu = bctr;                    /* switch to agreed-upon block check */
1702         bctl = (bctu == 4) ? 2 : bctu;  /* Set block-check length */
1703     }
1704
1705 #ifdef CK_RESEND
1706     if ((sendmode == SM_RESEND) && (!atcapu || !rscapu)) { /* RESEND */
1707         errpkt((CHAR *) "RESEND capabilities not negotiated");
1708         RESUME;
1709     } else {
1710 #endif /* CK_RESEND */
1711         what = W_SEND;                  /* Remember we're sending */
1712         lastxfer = W_SEND;
1713         x = sfile(xflg);                /* Send X or F header packet */
1714         cancel = 0;                     /* Reset cancellation counter */
1715         if (x) {                        /* If the packet was sent OK */
1716             if (!xflg && filcnt == 1)   /* and it's a real file */
1717               crc16 = 0L;               /* Clear the file CRC */
1718             resetc();                   /* reset per-transaction counters */
1719             rtimer();                   /* reset timers */
1720 #ifdef GFTIMER
1721             rftimer();
1722 #endif /* GFTIMER */
1723             streamon();                 /* turn on streaming */
1724 #ifdef IKSDB
1725             if (ikdbopen) slotstate(what,
1726                                   (server ? "SERVER" : ""),
1727                                   "SEND",
1728                                   filnam
1729                                   );
1730 #endif /* IKSDB */
1731             BEGIN ssfile;               /* and switch to receive-file state */
1732         } else {                        /* otherwise send error msg & quit */
1733             s = xflg ? "Can't execute command" : (char *)epktmsg;
1734             if (!*s) s = "Can't open file";
1735             errpkt((CHAR *)s);
1736             RESUME;
1737         }
1738 #ifdef CK_RESEND
1739     }
1740 #endif /* CK_RESEND */
1741 }
1742
1743 /*
1744   These states are necessary to handle the case where we get a server command
1745   packet (R, G, or C) reply with an S packet, but the client retransmits the
1746   command packet.  The input() function doesn't catch this because the packet
1747   number is still zero.
1748 */
1749 <ssinit>R {                             /* R packet was retransmitted. */
1750     xsinit();                           /* Resend packet 0 */
1751 }
1752
1753 <ssinit>G {                             /* Same deal if G packet comes again */
1754     xsinit();
1755 }
1756
1757 /* should probably add cases for O, W, V, H, J, ... */
1758
1759 <ssinit>C {                             /* Same deal if C packet comes again */
1760     xsinit();
1761 }
1762
1763 <ssfile>Y {                             /* ACK for F or X packet */
1764     srvptr = srvcmd;                    /* Point to string buffer */
1765     decode(rdatap,putsrv,0);            /* Decode data field, if any */
1766     putsrv(NUL);                        /* Terminate with null */
1767     ffc = 0L;                           /* Reset file byte counter */
1768     debug(F101,"<ssfile>Y cxseen","",cxseen);
1769     if (*srvcmd) {                      /* If remote name was recorded */
1770         if (sendmode != SM_RESEND) {
1771             if (fdispla == XYFD_C || fdispla == XYFD_S)
1772               xxscreen(SCR_AN,0,0L,(char *)srvcmd);
1773             tlog(F110," remote name:",(char *) srvcmd,0L);
1774             makestr(&psrfspec,(char *)srvcmd);
1775         }
1776     }
1777     if (cxseen||czseen) {               /* Interrupted? */
1778         debug(F101,"<ssfile>Y canceling","",0);
1779         x = clsif();                    /* Close input file */
1780         sxeof(1);                       /* Send EOF(D) */
1781         BEGIN sseof;                    /* and switch to EOF state. */
1782     } else if (atcapu) {                /* If attributes are to be used */
1783         if (sattr(xflg | stdinf, 1) < 0) { /* send them */
1784             errpkt((CHAR *)"Can't send attributes"); /* if problem, say so */
1785             RESUME;                     /* and quit */
1786         } else BEGIN ssattr;            /* if ok, switch to attribute state */
1787     } else {                            /* Attributes not negotiated */
1788         if (window(wslotn) < 0) {       /* Open window */
1789             errpkt((CHAR *)"Can't open window");
1790             RESUME;
1791         } else if ((x = sdata()) == -2) { /* Send first data packet data */
1792             window(1);                  /* Connection lost, reset window */
1793             x = clsif();                /* Close input file */
1794             return(success = 0);        /* Return failure */
1795         } else if (x == -9) {           /* User interrupted */
1796             errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1797             window(1);                  /* Set window size back to 1... */
1798             timint = s_timint;          /* Restore timeout */
1799             return(success = 0);        /* Failed */
1800         } else if (x < 0) {             /* EOF (empty file) or interrupted */
1801             window(1);                  /* put window size back to 1, */
1802             debug(F101,"<ssfile>Y cxseen","",cxseen);
1803             x = clsif();                /* If not ok, close input file, */
1804             if (x < 0)                  /* treating failure as interruption */
1805               cxseen = 1;               /* Send EOF packet */
1806             seof(cxseen||czseen);
1807             BEGIN sseof;                /* and switch to EOF state. */
1808         } else {                        /* First data sent OK */
1809             BEGIN ssdata;               /* All ok, switch to send-data state */
1810         }
1811     }
1812 }
1813
1814 <ssattr>Y {                             /* Got ACK to A packet */
1815     ffc = 0L;                           /* Reset file byte counter */
1816     debug(F101,"<ssattr>Y cxseen","",cxseen);
1817     if (cxseen||czseen) {               /* Interrupted? */
1818         debug(F101,"<sattr>Y canceling","",0);
1819         x = clsif();                    /* Close input file */
1820         sxeof(1);                       /* Send EOF(D) */
1821         BEGIN sseof;                    /* and switch to EOF state. */
1822     } else if (rsattr(rdatap) < 0) {    /* Was the file refused? */
1823         discard = 1;                    /* Set the discard flag */
1824         clsif();                        /* Close the file */
1825         sxeof(1);                       /* send EOF with "discard" code */
1826         BEGIN sseof;                    /* switch to send-EOF state */
1827     } else if ((x = sattr(xflg | stdinf, 0)) < 0) { /* Send more? */
1828         errpkt((CHAR *)"Can't send attributes"); /* Trouble... */
1829         RESUME;
1830     } else if (x == 0) {                /* No more to send so now the data */
1831         if (window(wslotn) < 0) {       /* Allocate negotiated window slots */
1832             errpkt((CHAR *)"Can't open window");
1833             RESUME;
1834         }
1835         if ((x = sdata()) == -2) {      /* File accepted, send first data */
1836             window(1);                  /* Connection broken */
1837             x = clsif();                /* Close file */
1838             return(success = 0);        /* Return failure */
1839         } else if (x == -9) {           /* User interrupted */
1840             errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1841             window(1);                  /* Set window size back to 1... */
1842             timint = s_timint;          /* Restore timeout */
1843             return(success = 0);        /* Failed */
1844         } else if (x < 0) {             /* If data was not sent */
1845             window(1);                  /* put window size back to 1, */
1846             debug(F101,"<ssattr>Y cxseen","",cxseen);
1847             if (clsif() < 0)            /* Close input file */
1848               cxseen = 1;               /* Send EOF packet */
1849             seof(cxseen||czseen);
1850             BEGIN sseof;                /* and switch to EOF state. */
1851         } else {
1852             BEGIN ssdata;               /* All ok, switch to send-data state */
1853         }
1854     }
1855 }
1856
1857 <ssdata>q {                             /* Ctrl-C or connection loss. */
1858     window(1);                          /* Set window size back to 1... */
1859     cxseen = 1;                         /* To indicate interruption */
1860     x = clsif();                        /* Close file */
1861     return(success = 0);                /* Failed */
1862 }
1863
1864 <ssdata>Y {                             /* Got ACK to Data packet */
1865     canned(rdatap);                     /* Check if file transfer cancelled */
1866     debug(F111,"<ssdata>Y cxseen",rdatap,cxseen);
1867     debug(F111,"<ssdata>Y czseen",rdatap,czseen);
1868     if ((x = sdata()) == -2) {          /* Try to send next data */
1869         window(1);                      /* Connection lost, reset window */
1870         x = clsif();                    /* Close file */
1871         return(success = 0);            /* Failed */
1872     } else if (x == -9) {               /* User interrupted */
1873         errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1874         window(1);                      /* Set window size back to 1... */
1875         timint = s_timint;              /* Restore original timeout */
1876         return(success = 0);            /* Failed */
1877     } else if (x < 0) {                 /* EOF - finished sending data */
1878         debug(F101,"<ssdata>Y cxseen","",cxseen);
1879         window(1);                      /* Set window size back to 1... */
1880         if (clsif() < 0)                /* Close input file */
1881           cxseen = 1;                   /* Send EOF packet */
1882         debug(F101,"<ssdata>Y CALLING SEOF()","",cxseen);
1883         seof(cxseen||czseen);
1884         BEGIN sseof;                    /* and enter send-eof state */
1885     }
1886     /* NOTE: If x == 0 it means we're draining: see sdata()! */
1887 }
1888
1889 <sseof>Y {                              /* Got ACK to EOF */
1890     int g, xdiscard;
1891     canned(rdatap);                     /* Check if file transfer cancelled */
1892     debug(F111,"<sseof>Y cxseen",rdatap,cxseen);
1893     debug(F111,"<sseof>Y czseen",rdatap,czseen);
1894     debug(F111,"<sseof>Y discard",rdatap,discard);
1895     xdiscard = discard;
1896     discard = 0;
1897     success = (cxseen == 0 && czseen == 0); /* Transfer status... */
1898     debug(F101,"<sseof>Y success","",success);
1899     if (success && rejection > 0)           /* If rejected, succeed if */
1900       if (rejection != '#' &&               /* reason was date */
1901           rejection != 1 && rejection != '?') /* or name; */
1902         success = 0;                        /* fail otherwise. */
1903     cxseen = 0;                         /* This goes back to zero. */
1904     if (success) {                      /* Only if transfer succeeded... */
1905         xxscreen(SCR_ST,ST_OK,0L,"");
1906         if (!xdiscard) {
1907             makestr(&sfspec,psfspec);   /* Record filenames for WHERE */
1908             makestr(&srfspec,psrfspec);
1909         }
1910         if (moving) {                   /* If MOVE'ing */
1911             x = zdelet(filnam);         /* Try to delete the source file */
1912 #ifdef TLOG
1913             if (tralog) {
1914                 if (x > -1) {
1915                     tlog(F110," deleted",filnam,0);
1916                 } else {
1917                     tlog(F110," delete failed:",ck_errstr(),0);
1918                 }
1919             }
1920 #endif /* TLOG */
1921         } else if (snd_move) {          /* Or move it */
1922             int x;
1923             x = zrename(filnam,snd_move);
1924 #ifdef TLOG
1925             if (tralog) {
1926                 if (x > -1) {
1927                     tlog(F110," moved to ",snd_move,0);
1928                 } else {
1929                     tlog(F110," move failed:",ck_errstr(),0);
1930                 }
1931             }
1932 #endif /* TLOG */
1933         } else if (snd_rename) {        /* Or rename it */
1934             char *s = snd_rename;       /* Renaming string */
1935 #ifndef NOSPL
1936             int y;                      /* Pass it thru the evaluator */
1937             extern int cmd_quoting;     /* for \v(filename) */
1938             if (cmd_quoting) {          /* But only if cmd_quoting is on */
1939                 y = MAXRP;
1940                 s = (char *)srvcmd;
1941                 zzstring(snd_rename,&s,&y);
1942                 s = (char *)srvcmd;
1943             }
1944 #endif /* NOSPL */
1945             if (s) if (*s) {
1946                 int x;
1947                 x = zrename(filnam,s);
1948 #ifdef TLOG
1949             if (tralog) {
1950                 if (x > -1) {
1951                     tlog(F110," renamed to",s,0);
1952                 } else {
1953                     tlog(F110," rename failed:",ck_errstr(),0);
1954                 }
1955             }
1956 #endif /* TLOG */
1957 #ifdef COMMENT
1958                 *s = NUL;
1959 #endif /* COMMENT */
1960             }
1961         }
1962     }
1963     if (czseen) {                       /* Check group interruption flag */
1964         g = 0;                          /* No more files if interrupted */
1965     } else {                            /* Otherwise... */
1966 #ifdef COMMENT
1967         /* This code makes any open error fatal to a file-group transfer. */
1968         g = gnfile();
1969         debug(F111,"<sseof>Y gnfile",filnam,g);
1970         if (g > 0) {                    /* Any more files to send? */
1971             if (sfile(xflg))            /* Yes, try to send next file header */
1972               BEGIN ssfile;             /* if ok, enter send-file state */
1973             else {                      /* otherwise */
1974                 s = xflg ? "Can't execute command" : (char *)epktmsg;
1975                 if (!*s) s = "Can't open file";
1976                 errpkt((CHAR *)s);      /* send error message */
1977                 RESUME;                 /* and quit */
1978             }
1979         } else {                        /* No next file */
1980             tsecs = gtimer();           /* get statistics timers */
1981 #ifdef GFTIMER
1982             fptsecs = gftimer();
1983 #endif /* GFTIMER */
1984             seot();                     /* send EOT packet */
1985             BEGIN sseot;                /* enter send-eot state */
1986         }
1987 #else  /* COMMENT */
1988         while (1) {                     /* Keep trying... */
1989             g = gnfile();               /* Get next file */
1990             debug(F111,"<sseof>Y gnfile",filnam,g);
1991             if (g == 0 && gnferror == 0) /* No more, stop trying */
1992               break;
1993             if (g > 0) {                /* Have one */
1994                 if (sfile(xflg)) {      /* Try to open and send F packet */
1995                     BEGIN ssfile;       /* If OK, enter send-file state */
1996                     break;              /* and break out of loop. */
1997                 }
1998             } /* Otherwise keep trying to get one we can send... */
1999         }
2000     }
2001     if (g == 0) {
2002         debug(F101,"<sseof>Y no more files","",czseen);
2003         tsecs = gtimer();               /* Get statistics timers */
2004 #ifdef GFTIMER
2005         fptsecs = gftimer();
2006 #endif /* GFTIMER */
2007         seot();                         /* Send EOT packet */
2008         BEGIN sseot;                    /* Enter send-eot state */
2009     }
2010 #endif /* COMMENT */
2011 }
2012
2013 <sseot>Y {                              /* Got ACK to EOT */
2014     debug(F101,"sseot justone","",justone);
2015     RESUME;                             /* All done, just quit */
2016 }
2017
2018 E {                                     /* Got Error packet, in any state */
2019     char *s = "";
2020     window(1);                          /* Close window */
2021     timint = s_timint;                  /* Restore original timeout */
2022     if (*epktmsg)                       /* Message from Error packet */
2023       s = (char *)epktmsg;
2024     if (!*s) {                          /* If not there then maybe here */
2025         s = (char *)rdatap;
2026         ckstrncpy((char *)epktmsg,(char *)rdatap,PKTMSGLEN);
2027     }
2028     if (!*s)                            /* Hopefully we'll never see this. */
2029       s = "Unknown error";
2030     success = 0;                        /* For IF SUCCESS/FAIL. */
2031     debug(F101,"ckcpro.w justone at E pkt","",justone);
2032
2033     success = 0;                        /* Transfer failed */
2034     xferstat = success;                 /* Remember transfer status */
2035     if (!epktsent) {
2036         x = quiet; quiet = 1;           /* Close files silently, */
2037         epktrcvd = 1;                   /* Prevent messages from clsof() */
2038         clsif();
2039         clsof(1);                       /* discarding any output file. */
2040         ermsg(s);                       /* Issue the message (calls screen). */
2041         quiet = x;                      /* Restore quiet state */
2042     }
2043     tstats();                           /* Get stats */
2044 /*
2045   If we are executing commands from a command file or macro, let the command
2046   file or macro decide whether to exit, based on SET { TAKE, MACRO } ERROR.
2047 */
2048     if (
2049 #ifndef NOICP
2050         !xcmdsrc &&
2051 #endif /* NOICP */
2052         backgrd && !server)
2053       fatal("Protocol error");
2054     xitsta |= (what & W_KERMIT);        /* Save this for doexit(). */
2055 #ifdef CK_TMPDIR
2056 /* If we were cd'd temporarily to another device or directory ... */
2057     if (f_tmpdir) {
2058         int x;
2059         x = zchdir((char *) savdir);    /* ... restore previous directory */
2060         f_tmpdir = 0;                   /* and remember we did it. */
2061         debug(F111,"ckcpro.w E tmpdir restored",savdir,x);
2062     }
2063 #endif /* CK_TMPDIR */
2064 #ifdef IKSDB
2065     if (ikdbopen) slotstate(what,"ERROR", (char *)epktmsg, "");
2066 #endif /* IKSDB */
2067     RESUME;
2068 }
2069
2070 q { success = 0; QUIT; }                /* Ctrl-C or connection loss. */
2071
2072 . {                                     /* Anything not accounted for above */
2073     errpkt((CHAR *)"Unexpected packet type"); /* Give error message */
2074     window(1);
2075     xitsta |= (what & W_KERMIT);        /* Save this for doexit(). */
2076     RESUME;                             /* and quit */
2077 }
2078
2079 %%
2080
2081 /*
2082   From here down to proto() are routines that were moved out of the state
2083   table switcher because the resulting switch() had become too large.
2084   To move the contents of a state-table case to a routine:
2085     1. Add a prototype to the list above the state table switcher.
2086     2. Make a routine with an appropriate name, returning int.
2087     3. Move the code into it.
2088     4. Put a call to the new routine in the former spot:
2089          rc = name_of_routine();
2090          if (rc > -1) return(rc);
2091     5. Add "return(-1);" after every RESUME, SERVE, or BEGIN macro and
2092        at the end if the code is open-ended.
2093 */
2094 static int
2095 rcv_firstdata() {
2096     extern int dispos;
2097     debug(F101,"rcv_firstdata","",dispos);
2098
2099     if (discard) {                      /* if we're discarding the file */
2100         ack1((CHAR *)"X");              /* just ack the data like this. */
2101         cancel++;                       /* and count it */
2102         BEGIN rdpkt;                    /* and wait for more data packets. */
2103         return(-1);
2104     } else {                            /* Not discarding. */
2105         rf_err = "Can't open file";
2106         if (xflg) {                     /* If screen data */
2107             if (remfile) {              /* redirected to file */
2108                 if (rempipe)            /* or pipe */
2109                   x = openc(ZOFILE,remdest); /* Pipe: start command */
2110                 else
2111                   x = opena(remdest,&iattr); /* File: open with attributes */
2112             } else {                    /* otherwise */
2113                 x = opent(&iattr);      /* "open" the screen */
2114             }
2115         } else {                        /* otherwise */
2116 #ifdef CALIBRATE
2117             if (calibrate) {            /* If calibration run */
2118                 x = ckopenx(&iattr);    /* open nothing */
2119 #ifdef STREAMING
2120                 if (streaming)          /* Streaming */
2121                   fastack();            /* ACK without ACKing. */
2122                 else
2123 #endif /* STREAMING */
2124                   ack();                /* Send real ACK */
2125                 BEGIN rdpkt;            /* Proceed to next state */
2126                 return(-1);
2127             } else
2128 #endif /* CALIBRATE */
2129 #ifdef UNIX
2130 /*
2131   In UNIX we can pipe the file data into the mail program, which is to be
2132   preferred to writing it out to a temp file and then mailing it afterwards.
2133   This depends rather heavily on all UNIXes having a mail command that
2134   accepts '-s "subject"' on the command line.  MAILCMD (e.g. mail, Mail, mailx)
2135   is defined in ckufio.c.
2136 */
2137             if (dispos == 'M') {        /* Mail... */
2138                 char *s;
2139                 char * tmp = NULL;
2140                 int n = 0;
2141                 extern char *MAILCMD;
2142                 s = iattr.disp.val + 1;
2143                 n = (int)strlen(MAILCMD) +    /* Mail command */
2144                   (int)strlen(s) +            /* address */
2145                   (int)strlen(ofilnam) + 32;  /* subject */
2146                 if (tmp = (char *)malloc(n)) {
2147                     ckmakxmsg(tmp,n,
2148                               MAILCMD," -s \"",ofilnam,"\" ",s,
2149                               NULL,NULL,NULL,NULL,NULL,NULL,NULL);
2150                     debug(F111,"rcv_firsdata mail",tmp,(int)strlen(tmp));
2151                     x = openc(ZOFILE,(char *)tmp);
2152                     free(tmp);
2153                 } else
2154                   x = 0;
2155             } else if (dispos == 'P') { /* Ditto for print */
2156                 char * tmp = NULL;
2157                 int n;
2158                 extern char *PRINTCMD;
2159                 n = (int)strlen(PRINTCMD) + (int)strlen(iattr.disp.val+1) + 4;
2160                 if (tmp = (char *)malloc(n)) {
2161                     sprintf(tmp,        /* safe (prechecked) */
2162                             "%s %s", PRINTCMD, iattr.disp.val + 1);
2163                     x = openc(ZOFILE,(char *)tmp);
2164                     free(tmp);
2165                 } else
2166                   x = 0;
2167             } else
2168 #endif /* UNIX */
2169               x = opena(filnam,&iattr); /* open the file, with attributes */
2170         }
2171         if (x) {                        /* If file was opened ok */
2172             int rc, qf;
2173 #ifndef NOSPL
2174             qf = query;
2175 #else
2176             qf = 0;
2177 #endif /* NOSPL */
2178
2179 #ifdef CKTUNING
2180             rc = (binary && !parity) ?
2181               bdecode(rdatap,putfil):
2182                decode(rdatap, qf ? puttrm : putfil, 1);
2183 #else
2184             rc = decode(rdatap, qf ? puttrm : putfil, 1);
2185 #endif /* CKTUNING */
2186             if (rc < 0) {
2187                 errpkt((CHAR *)"Error writing data");
2188                 RESUME;
2189                 return(-1);
2190             }
2191 #ifdef STREAMING
2192             if (streaming)              /* Streaming was negotiated */
2193               fastack();                /* ACK without ACKing. */
2194             else
2195 #endif /* STREAMING */
2196               ack();                    /* acknowledge it */
2197             BEGIN rdpkt;                /* and switch to receive-data state */
2198             return(-1);
2199         } else {                        /* otherwise */
2200             errpkt((CHAR *) rf_err);    /* send error packet */
2201             RESUME;                     /* and quit. */
2202             return(-1);
2203         }
2204     }
2205 }
2206
2207 static int
2208 rcv_shortreply() {
2209 #ifdef PKTZEROHACK
2210     success = 0;
2211     debug(F111,"rcv_shortreply",rdatap,ipktlen);
2212     if (ipktack[0] && !strncmp(ipktack,(char *)rdatap,ipktlen)) {
2213         /* No it's the ACK to the I packet again */
2214         x = scmd(vcmd,(CHAR *)cmarg);   /* So send the REMOTE command again */
2215         /* Maybe this should be resend() */
2216         debug(F110,"IPKTZEROHACK",ipktack,x);
2217         if (x < 0) {
2218             errpkt((CHAR *)srimsg);
2219             RESUME;
2220             return(-1);
2221         }
2222     } else {
2223         ipktack[0] = NUL;
2224 #endif /* PKTZEROHACK */
2225         urserver = 1;
2226 #ifndef NOSERVER
2227 #ifndef NOSPL
2228         if (query) {                    /* If to query, */
2229             qbufp = querybuf;           /*  initialize query response buffer */
2230             qbufn = 0;
2231             querybuf[0] = NUL;
2232         }
2233 #endif /* NOSPL */
2234         x = 1;
2235         if (remfile) {                  /* Response redirected to file */
2236             rf_err = "Can't open file";
2237             if (rempipe)                /* or pipe */
2238               x =
2239 #ifndef NOPUSH
2240                 zxcmd(ZOFILE,remdest)   /* Pipe: Start command */
2241 #else
2242                 0
2243 #endif /* NOPUSH */
2244                 ;
2245             else
2246               x = opena(remdest,&iattr); /* File: Open with attributes */
2247             debug(F111,"rcv_shortreply remfile",remdest,x);
2248         } else {
2249             x = opent(&iattr);          /* "open" the screen */
2250         }
2251         if (x) {                        /* If file was opened ok */
2252             if (decode(rdatap,
2253 #ifndef NOSPL
2254                        (query || !remfile) ? puttrm :
2255 #else
2256                        !remfile ? puttrm :
2257 #endif /* NOSPL */
2258                        zputfil, 1) < 0) { /* Note: zputfil, not putfil. */
2259                 errpkt((CHAR *)"Error writing data");
2260                 RESUME;
2261                 return(-1);
2262             } else {
2263                 if (rdatap)             /* If we had data */
2264                   if (*rdatap)          /* add a line terminator */
2265                     if (remfile) {      /* to file */
2266                         zsoutl(ZOFILE,"");
2267                     } else {            /* or to screen. */
2268 #ifndef NOICP
2269                         if (!query || !xcmdsrc)
2270 #endif /* NOICP */
2271                           if (!(quiet && rcdactive))
2272                             conoll("");
2273                     }
2274                 if (bye_active && network) { /* I sent BYE or REMOTE LOGOUT */
2275                     msleep(500);        /* command and got the ACK... */
2276                     bye_active = 0;
2277                     ttclos(0);
2278                 }
2279                 clsof(0);
2280                 if (!epktsent && !epktrcvd) /* If no error packet... */
2281                   success = 1;          /* success. */
2282                 RESUME;
2283                 return(-1);
2284             }
2285         } else {                        /* File not opened OK */
2286             errpkt((CHAR *) rf_err);    /* send error message */
2287             RESUME;                     /* and quit. */
2288             return(-1);
2289         }
2290 #endif /* NOSERVER */
2291 #ifdef PKTZEROHACK
2292     }
2293 #endif /* PKTZEROHACK */
2294     debug(F101,"rcv_shortreply fallthru","",success);
2295     return(-1);
2296 }
2297
2298
2299 static int
2300 srv_query() {
2301 #ifndef NOSERVER
2302 #ifndef NOSPL
2303     char c;
2304 #ifdef CKSYSLOG
2305     if (ckxsyslog >= SYSLG_PR && ckxlogging)
2306       cksyslog(SYSLG_PR, 1, "server", "REMOTE QUERY", (char *)srvcmd);
2307 #endif /* CKSYSLOG */
2308 #ifdef IKSDB
2309     if (ikdbopen) slotstate(what,"REMOTE QUERY", (char *)(srvcmd+2), "");
2310 #endif /* IKSDB */
2311     c = *(srvcmd+2);                    /* Q = Query, S = Set */
2312     if (c == 'Q') {                     /* Query */
2313         if (!ENABLED(en_que)) { /* Security */
2314             errpkt((CHAR *)"REMOTE QUERY disabled");
2315             RESUME;
2316             return(-1);
2317         } else {                        /* Query allowed */
2318             int n; char *p, *q;
2319             qbufp = querybuf;           /* Wipe out old stuff */
2320             qbufn = 0;
2321             querybuf[0] = NUL;
2322             p = (char *) srvcmd + 3;    /* Pointer for making wrapper */
2323             n = strlen((char *)srvcmd); /* Position of end */
2324             c = *(srvcmd+4);            /* Which type of variable */
2325
2326             if (*(srvcmd+6) == CMDQ) {  /* Starts with command quote? */
2327                 p = (char *) srvcmd + 6; /* Take it literally */
2328                 if (*p == CMDQ) p++;
2329             } else {                    /* They played by the rules */
2330                 if (c == 'K') {         /* Kermit variable */
2331                     int k;
2332                     k = (int) strlen(p);
2333                     if (k > 0 && p[k-1] == ')') {
2334                         p = (char *)(srvcmd + 4);
2335                         *(srvcmd+4) = CMDQ;
2336                         *(srvcmd+5) = 'f'; /* Function, so make it \f...() */
2337                     } else {
2338                         *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
2339                         *(srvcmd+4) = 'v';  /* Variable, so make it \v(...) */
2340                         *(srvcmd+5) = '(';  /* around variable name */
2341                         *(srvcmd+n) = ')';
2342                         *(srvcmd+n+1) = NUL;
2343                     }
2344                 } else {
2345                     *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
2346                     *(srvcmd+4) = 'v'; /*  Variable, so make it \v(...) */
2347                     *(srvcmd+5) = '(';  /* around variable name */
2348                     *(srvcmd+n) = ')';
2349                     *(srvcmd+n+1) = NUL;
2350                     if (c == 'S') {     /* System variable */
2351                         *(srvcmd+4) = '$'; /*  so it's \$(...) */
2352                     } else if (c == 'G') { /* Non-\ Global variable */
2353                         *(srvcmd+4) = 'm'; /*  so wrap it in \m(...) */
2354                     }
2355                 }
2356             }                           /* Now evaluate it */
2357             n = QBUFL;                  /* Max length */
2358             q = querybuf;               /* Where to put it */
2359             if (zzstring(p,&q,&n) < 0) {
2360                 errpkt((n > 0) ? (CHAR *)"Can't get value"
2361                                : (CHAR *)"Value too long"
2362                        );
2363                 RESUME;
2364                 return(-1);
2365             } else {
2366                 if (encstr((CHAR *)querybuf) > -1) { /* Encode it */
2367                     ack1(data);         /* If it fits, send it back in ACK */
2368                     success = 1;
2369                     RESUME;
2370                     return(-1);
2371                 } else if (sndstring(querybuf)) { /* Long form response */
2372                     BEGIN ssinit;
2373                     return(-1);
2374                 } else {                /* sndhlp() fails */
2375                     errpkt((CHAR *)"Can't send value");
2376                     RESUME;
2377                     return(-1);
2378                 }
2379             }
2380         }
2381     } else if (c == 'S') {              /* Set (assign) */
2382         if (!ENABLED(en_asg)) {         /* Security */
2383             errpkt((CHAR *)"REMOTE ASSIGN disabled");
2384             RESUME;
2385             return(-1);
2386         } else {                        /* OK */
2387             int n;
2388             n = xunchar(*(srvcmd+3));   /* Length of name */
2389             n = 3 + n + 1;              /* Position of length of value */
2390             *(srvcmd+n) = NUL;          /* Don't need it */
2391             if (addmac((char *)(srvcmd+4),(char *)(srvcmd+n+1)) < 0)
2392               errpkt((CHAR *)"REMOTE ASSIGN failed");
2393             else {
2394                 ack();
2395                 success = 1;
2396             }
2397             RESUME;
2398             return(-1);
2399         }
2400     } else {
2401         errpkt((CHAR *)"Badly formed server command");
2402         RESUME;
2403         return(-1);
2404     }
2405 #else
2406     errpkt((CHAR *)"Variable query/set not available");
2407     RESUME;
2408     return(-1);
2409 #endif /* NOSPL */
2410 #endif /* NOSERVER */
2411 }
2412
2413 static int
2414 srv_copy() {
2415 #ifndef NOSERVER
2416 #ifdef CKSYSLOG
2417     if (ckxsyslog >= SYSLG_PR && ckxlogging)
2418       cksyslog(SYSLG_PR, 1, "server", "REMOTE COPY", (char *)srvcmd);
2419 #endif /* CKSYSLOG */
2420 #ifdef ZCOPY
2421     if (!ENABLED(en_cpy)) {
2422         errpkt((CHAR *)"REMOTE COPY disabled");
2423         RESUME;
2424         return(-1);
2425     } else {
2426         char *str1, *str2, f1[256], f2[256];
2427         int  len1, len2;
2428         len1 = xunchar(srvcmd[1]);      /* Separate the parameters */
2429         len2 = xunchar(srvcmd[2+len1]);
2430         strncpy(f1,(char *)(srvcmd+2),len1);
2431         f1[len1] = NUL;
2432         strncpy(f2,(char *)(srvcmd+3+len1),len2);
2433         f2[len2] = NUL;
2434 #ifdef IKSDB
2435         if (ikdbopen) slotstate(what,"REMOTE COPY", f1, f2);
2436 #endif /* IKSDB */
2437         if (!ENABLED(en_cwd)) {         /* If CWD is disabled */
2438             zstrip(f1,&str1);           /* and they included a pathname, */
2439             zstrip(f2,&str2);
2440             if (strcmp(f1,str1) || strcmp(f2,str2)) { /* Refuse. */
2441                 errpkt((CHAR *)"Access denied");
2442                 RESUME;                 /* Remember, this is not a goto! */
2443                 return(-1);
2444             }
2445         }
2446         if (state == generic) {         /* It's OK to go ahead. */
2447             if (zcopy(f1,f2)) {         /* Try */
2448                 errpkt((CHAR *)"Can't copy file"); /* give error message */
2449             } else {
2450                 success = 1;
2451                 ack();
2452             }
2453             RESUME;                     /* wait for next server command */
2454             return(-1);
2455         }
2456     }
2457     return(-1);
2458 #else /* no ZCOPY */
2459     errpkt((CHAR *)"REMOTE COPY not available"); /* give error message */
2460     RESUME;                             /* wait for next server command */
2461     return(-1);
2462 #endif /* ZCOPY */
2463 #endif /* NOSERVER */
2464 }
2465
2466 static int
2467 srv_rename() {
2468 #ifndef NOSERVER
2469 #ifdef CKSYSLOG
2470     if (ckxsyslog >= SYSLG_PR && ckxlogging)
2471       cksyslog(SYSLG_PR, 1, "server", "REMOTE RENAME", (char *)srvcmd);
2472 #endif /* CKSYSLOG */
2473 #ifdef ZRENAME
2474     if (!ENABLED(en_ren)) {
2475         errpkt((CHAR *)"REMOTE RENAME disabled");
2476         RESUME;
2477         return(-1);
2478     } else {                            /* RENAME is enabled */
2479         char *str1, *str2, f1[256], f2[256];
2480         int len1, len2;
2481         len1 = xunchar(srvcmd[1]);      /* Separate the parameters */
2482         len2 = xunchar(srvcmd[2+len1]);
2483         strncpy(f1,(char *)(srvcmd+2),len1);
2484         f1[len1] = NUL;
2485         strncpy(f2,(char *)(srvcmd+3+len1),len2);
2486         f2[len2] = NUL;
2487         len2 = xunchar(srvcmd[2+len1]);
2488         strncpy(f1,(char *)(srvcmd+2),len1);
2489         f1[len1] = NUL;
2490         strncpy(f2,(char *)(srvcmd+3+len1),len2);
2491         f2[len2] = NUL;
2492 #ifdef IKSDB
2493         if (ikdbopen) slotstate(what,"REMOTE RENAME", f1, f2);
2494 #endif /* IKSDB */
2495         if (!ENABLED(en_cwd)) {         /* If CWD is disabled */
2496             zstrip(f1,&str1);           /* and they included a pathname, */
2497             zstrip(f2,&str2);
2498             if ( strcmp(f1,str1) || strcmp(f2,str2) ) { /* refuse. */
2499                 errpkt((CHAR *)"Access denied");
2500                 RESUME;                 /* Remember, this is not a goto! */
2501                 return(-1);
2502             }
2503         }
2504         if (state == generic) {         /* It's OK to go ahead. */
2505             if (zrename(f1,f2)) {       /* Try */
2506                 errpkt((CHAR *)"Can't rename file"); /* Give error msg */
2507             } else {
2508                 success = 1;
2509                 ack();
2510             }
2511             RESUME;                     /* Wait for next server command */
2512             return(-1);
2513         }
2514     }
2515     return(-1);
2516 #else /* no ZRENAME */
2517     /* Give error message */
2518     errpkt((CHAR *)"REMOTE RENAME not available");
2519     RESUME;                             /* Wait for next server command */
2520     return(-1);
2521 #endif /* ZRENAME */
2522 #endif /* NOSERVER */
2523 }
2524
2525 static int
2526 srv_login() {
2527 #ifndef NOSERVER
2528     char f1[LOGINLEN+1], f2[LOGINLEN+1], f3[LOGINLEN+1];
2529     CHAR *p;
2530     int len, i;
2531
2532     debug(F101,"REMOTE LOGIN x_login","",x_login);
2533     debug(F101,"REMOTE LOGIN x_logged","",x_logged);
2534
2535     f1[0] = NUL; f2[0] = NUL; f3[0] = NUL;
2536     len = 0;
2537     if (srvcmd[1])                      /* First length field */
2538       len = xunchar(srvcmd[1]);         /* Separate the parameters */
2539
2540     if (x_login) {                      /* Login required */
2541         if (x_logged) {                 /* And already logged in */
2542             if (len > 0) {              /* Logging in again */
2543                 errpkt((CHAR *)"Already logged in.");
2544             } else {                    /* Logging out */
2545                 debug(F101,"REMOTE LOGOUT","",x_logged);
2546 #ifdef CKSYSLOG
2547                 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2548                   cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGOUT", NULL);
2549 #endif /* CKSYSLOG */
2550 #ifdef IKSDB
2551                 if (ikdbopen) slotstate(what,"REMOTE LOGOUT", "", "");
2552 #endif /* IKSDB */
2553                 tlog(F110,"Logged out",x_user,0);
2554                 ack1((CHAR *)"Logged out");
2555                 success = 1;
2556                 msleep(500);
2557 #ifdef CK_LOGIN
2558                 x_logged = 0;
2559 #ifdef IKSD
2560                 if (inserver)
2561                   ckxlogout();
2562 #endif /* IKSD */
2563 #endif /* CK_LOGIN */
2564             }
2565         } else {                        /* Not logged in yet */
2566             debug(F101,"REMOTE LOGIN len","",len);
2567             if (len > 0) {              /* Have username */
2568 #ifdef CKSYSLOG
2569                 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2570                   cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGIN", NULL);
2571 #endif /* CKSYSLOG */
2572                 if (len > LOGINLEN) {
2573                     errpkt((CHAR *)"Username too long");
2574                 }
2575                 p = srvcmd + 2;         /* Point to it */
2576                 for (i = 0; i < len; i++) /* Copy it */
2577                   f1[i] = p[i];
2578                 f1[len] = NUL;          /* Terminate it */
2579                 p += len;               /* Point to next length field */
2580                 if (*p) {               /* If we have one */
2581                     len = xunchar(*p++); /* decode it */
2582                     if (len > 0 && len <= LOGINLEN) {
2583                         for (i = 0; i < len; i++) /* Same deal for password */
2584                           f2[i] = p[i];
2585                         f2[len] = NUL;
2586                         p += len;       /* And account */
2587                         if (*p) {
2588                             len = xunchar(*p++);
2589                             if (len > 0 && len <= LOGINLEN) {
2590                                 for (i = 0; i < len; i++)
2591                                   f3[i] = p[i]; /* Set but never used */
2592                                 f3[len] = NUL; /* (because account not used) */
2593                             }
2594                         }
2595                     }
2596                 }
2597                 debug(F101,"REMOTE LOGIN 1","",x_logged);
2598 #ifdef IKSD
2599 #ifdef CK_LOGIN
2600                 if (inserver) {         /* Log in to system for real */
2601                     x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
2602                     debug(F101,"REMOTE LOGIN 2","",x_logged);
2603                     if (x_logged) {     /* Count attempts */
2604                         logtries = 0;
2605                         justone = 1;
2606                     } else {
2607                         logtries++;
2608                         sleep(logtries);
2609                     }
2610                 } else
2611 #endif /* CK_LOGIN */
2612 #endif /* IKSD */
2613                   if (x_user && x_passwd) { /* User and password must match */
2614                       if (!strcmp(x_user,f1)) /* SET SERVER LOGIN */
2615                         if (!strcmp(x_passwd,f2))
2616                           x_logged = 1;
2617                       debug(F101,"REMOTE LOGIN 3","",x_logged);
2618                   } else if (x_user) {  /* Only username given, no password */
2619                       if (!strcmp(x_user,f1)) /* so only username must match */
2620                         x_logged = 1;
2621                       debug(F101,"REMOTE LOGIN 4","",x_logged);
2622                   }
2623 #ifdef CK_LOGIN 
2624                 else {
2625                     x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
2626                     debug(F101,"REMOTE LOGIN 5","",x_logged);
2627                 }
2628 #endif /* CK_LOGIN */
2629                 if (x_logged) {         /* Logged in? */
2630                     tlog(F110,"Logged in", x_user, 0);
2631                     if (isguest)
2632                       ack1((CHAR *)"Logged in as guest - restrictions apply");
2633                     else
2634                       ack1((CHAR *)"Logged in");
2635                     success = 1;
2636                 } else {
2637                     tlog(F110,"Login failed", f1, 0);
2638                     errpkt((CHAR *)"Access denied.");
2639 #ifdef IKSD
2640 #ifdef CK_LOGIN
2641                     if (inserver && logtries > 2)
2642                       ckxlogout();
2643 #endif /* CK_LOGIN */
2644 #endif /* IKSD */
2645                 }
2646             } else {                    /* LOGOUT */
2647                 errpkt((CHAR *)"Logout ignored");
2648             }
2649         }
2650     } else {                            /* Login not required */
2651         if (len > 0)
2652           errpkt((CHAR *)"Login ignored.");
2653         else
2654           errpkt((CHAR *)"Logout ignored.");
2655     }
2656 #endif /* NOSERVER */
2657     RESUME;
2658     return(-1);
2659 }
2660
2661 static int
2662 srv_timeout() {
2663     /* K95 does this its own way */
2664     if (idletmo) {
2665 #ifdef IKSD
2666         if (inserver) {
2667            printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", srvidl);
2668            doexit(GOOD_EXIT,xitsta);
2669         }
2670 #endif /* IKSD */
2671         idletmo = 0;
2672         printf("\r\nSERVER IDLE TIMEOUT: %d sec\r\n", srvidl);
2673         xitsta |= (what & W_KERMIT);
2674         QUIT;
2675     }
2676 #ifndef NOSERVER
2677     else if (fatalio) {                 /* Connection lost */
2678 #ifdef CKSYSLOG
2679           if (ckxsyslog >= SYSLG_PR && ckxlogging)
2680             cksyslog(SYSLG_PR, 1, "server", "Connection lost", NULL);
2681 #endif /* CKSYSLOG */
2682 #ifdef IKSDB
2683           if (ikdbopen) slotstate(what,"SERVER DISCONNECT",(char *)srvcmd, "");
2684 #endif /* IKSDB */
2685         xitsta |= what;
2686         QUIT;
2687     } else if (interrupted) {           /* Interrupted by hand */
2688         if (!ENABLED(en_fin)) {
2689             errpkt((CHAR *)"QUIT disabled");
2690             RESUME;
2691             return(-1);
2692         } else {
2693             if (what == W_SEND || what == W_RECV || what == W_REMO) {
2694                 success = 0;
2695 #ifdef CKSYSLOG
2696                 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2697                   cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
2698 #endif /* CKSYSLOG */
2699             } else if (what == W_NOTHING && filcnt == 0) {
2700                 success = 1;
2701             } /* Otherwise leave success alone */
2702             xitsta |= (what & W_KERMIT);
2703             QUIT;
2704         }
2705     } else {                            /* Shouldn't happen */
2706         debug(F100,"SERVER (top) GOT UNEXPECTED 'q'","",0);
2707         QUIT;
2708     }
2709 #endif /* NOSERVER */
2710 }
2711
2712 static int
2713 rcv_s_pkt() {
2714 #ifndef NOSERVER
2715     if (state == rgen)
2716       urserver = 1;
2717     if (/* state == serve && */ x_login && !x_logged) {
2718         errpkt((CHAR *)"Login required");
2719         SERVE;
2720     } else
2721 #endif /* NOSERVER */
2722       if (state == serve && !ENABLED(en_sen)) { /* Not in server mode */
2723         errpkt((CHAR *)"SEND disabled"); /* when SEND is disabled. */
2724         RESUME;
2725         return(-1);
2726     } else {                            /* OK to go ahead. */
2727 #ifdef CK_TMPDIR
2728         if (dldir && !f_tmpdir) {       /* If they have a download directory */
2729             debug(F110,"receive download dir",dldir,0);
2730             if (s = zgtdir()) {         /* Get current directory */
2731                 debug(F110,"receive current dir",s,0);
2732                 if (zchdir(dldir)) {    /* Change to download directory */
2733                     debug(F100,"receive zchdir ok","",0);
2734                     ckstrncpy(savdir,s,TMPDIRLEN);
2735                     f_tmpdir = 1;       /* Remember that we did this */
2736                 } else
2737                   debug(F100,"receive zchdir failed","",0);
2738             }
2739         }
2740 #endif /* CK_TMPDIR */
2741         nakstate = 1;                   /* Can send NAKs from here. */
2742         rinit(rdatap);                  /* Set parameters */
2743         if (bctf) {
2744             bctu = 3;
2745             bctl = 3;
2746         } else {
2747             bctu = bctr;               /* switch to agreed-upon block check */
2748             bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
2749         }
2750         what = W_RECV;                  /* Remember we're receiving */
2751         lastxfer = W_RECV;
2752         resetc();                       /* Reset counters */
2753         rtimer();                       /* Reset timer */
2754 #ifdef GFTIMER
2755         rftimer();
2756 #endif /* GFTIMER */
2757         streamon();
2758         BEGIN rfile;                    /* Go into receive-file state */
2759     }
2760     return(-1);
2761 }
2762
2763
2764 /* END OF ROUTINES MOVED OUT OF STATE MACHINE */
2765
2766
2767 /*  P R O T O  --  Protocol entry function  */
2768
2769 static int is_tn = 0;                   /* It's a Telnet connection */
2770
2771 #ifdef CK_SPEED
2772 int f_ctlp = 0;                         /* Control-character prefix table */
2773 #ifdef COMMENT
2774 short s_ctlp[256];
2775 #endif /* COMMENT */
2776 #endif /* CK_SPEED */
2777
2778 /*
2779   This is simply a wrapper for the real protocol function just below,
2780   that saves any items that might be changed automatically by protocol
2781   negotiations and then restores them upon exit from protocol mode.
2782 */
2783 VOID
2784 proto() {
2785     extern int b_save, f_save, c_save, ss_save, slostart, reliable, urclear;
2786 #ifndef NOCSETS
2787     extern int fcharset, fcs_save, tcharset, tcs_save;
2788 #endif /* NOCSETS */
2789
2790 #ifdef PIPESEND
2791     extern int pipesend;
2792 #endif /* PIPESEND */
2793 #ifndef NOLOCAL
2794 #ifdef OS2
2795     extern int cursorena[], cursor_save, term_io;
2796     extern BYTE vmode;
2797     extern int display_demo;
2798     int term_io_save;
2799 #endif /* OS2 */
2800 #endif /* NOLOCAL */
2801 #ifdef TNCODE
2802     int _u_bin=0, _me_bin = 0;
2803 #ifdef IKS_OPTION
2804     int /* _u_start=0, */ _me_start = 0;
2805 #endif /* IKS_OPTION */
2806 #endif /* TNCODE */
2807 #ifdef PATTERNS
2808     int pa_save;
2809     int i;
2810 #endif /* PATTERNS */
2811     int scan_save;
2812
2813 #ifdef PATTERNS
2814     pa_save = patterns;
2815 #endif /* PATTERNS */
2816     scan_save = filepeek;
2817
2818     myjob = sstate;
2819
2820 #ifdef CK_LOGIN
2821     if (isguest) {                      /* If user is anonymous */
2822         en_pri = 0;                     /* disable printing */
2823         en_mai = 0;                     /* and disable email */
2824         en_del = 0;                     /* and file deletion */
2825     }
2826 #endif /* CK_LOGIN */
2827
2828 #ifndef NOLOCAL
2829 #ifdef OS2
2830     cursor_save = cursorena[vmode];
2831     cursorena[vmode] = 0;
2832     term_io_save = term_io;
2833     term_io = 0;
2834 #endif /* OS2 */
2835 #endif /* NOLOCAL */
2836     b_save = binary;                    /* SET FILE TYPE */
2837     f_save = fncnv;                     /* SET FILE NAMES */
2838     c_save = bctr;
2839     p_save = fnspath;
2840     r_save = recursive;
2841     s_timint = timint;
2842     ss_save = slostart;
2843 #ifndef NOCSETS
2844     fcs_save = fcharset;
2845     tcs_save = tcharset;
2846 #endif /* NOCSETS */
2847
2848 #ifdef COMMENT
2849 /* Don't do this because then user can never find out what happened. */
2850 #ifdef CK_SPEED
2851     for (i = 0; i < 256; i++)
2852       s_ctlp[i] = ctlp[i];
2853     f_ctlp = 1;
2854 #endif /* CK_SPEED */
2855 #endif /* COMMENT */
2856     if (reliable == SET_ON)
2857       slostart = 0;
2858     is_tn = (!local && sstelnet)
2859 #ifdef TNCODE
2860       || (local && network && ttnproto == NP_TELNET)
2861 #endif /* TNCODE */
2862         ;
2863 #ifdef TNCODE
2864     if (is_tn) {
2865         if (tn_b_xfer && !(sstelnet || inserver)) {
2866             /* Save the current state of Telnet Binary */
2867             _u_bin = TELOPT_U(TELOPT_BINARY);
2868             _me_bin = TELOPT_ME(TELOPT_BINARY);
2869
2870             /* If either direction is not Binary attempt to negotiate it */
2871             if (!_u_bin && TELOPT_U_MODE(TELOPT_BINARY) != TN_NG_RF) {
2872                 tn_sopt(DO,TELOPT_BINARY);
2873                 TELOPT_UNANSWERED_DO(TELOPT_BINARY) = 1;
2874             }
2875             if (!_me_bin && TELOPT_ME_MODE(TELOPT_BINARY) != TN_NG_RF) {
2876                 tn_sopt(WILL,TELOPT_BINARY);
2877                 TELOPT_UNANSWERED_WILL(TELOPT_BINARY) = 1;
2878             }
2879             if (!(_me_bin && _u_bin))
2880               tn_wait("proto set binary mode");
2881         }
2882 #ifdef IKS_OPTION
2883 #ifdef CK_XYZ
2884         if (protocol != PROTO_K) {      /* Non-Kermit protocol selected */
2885             if (TELOPT_U(TELOPT_KERMIT) &&
2886                 TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2887                 iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
2888                 /* _u_start = 1; */
2889             }
2890             if (TELOPT_ME(TELOPT_KERMIT) &&
2891                 TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2892                 tn_siks(KERMIT_STOP);   /* I'm not servering */
2893                 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2894                 _me_start = 1;
2895             }
2896         } else
2897 #endif /* CK_XYZ */
2898         if (sstate == 'x' || sstate == 'v') { /* Responding to a request */
2899             if (!inserver && TELOPT_U(TELOPT_KERMIT) &&
2900                 TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2901                 iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
2902                 /* _u_start = 1; */
2903             }
2904             if (TELOPT_ME(TELOPT_KERMIT) &&
2905                 !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2906                 tn_siks(KERMIT_START);  /* Send Kermit-Server Start */
2907                 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1;
2908             }
2909         } else {                        /* Initiating a request */
2910             if (TELOPT_ME(TELOPT_KERMIT) &&
2911                 TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2912                 tn_siks(KERMIT_STOP);   /* I'm not servering */
2913                 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2914                 _me_start = 1;
2915             }
2916             if (TELOPT_U(TELOPT_KERMIT) &&
2917                 !TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2918                 /* Send Req-Server-Start */
2919                 if (!iks_wait(KERMIT_REQ_START,0)) {
2920                     if (sstate != 's') {
2921                         success = 0;    /* Other Kermit refused to serve */
2922                         if (local)
2923                           printf("A Kermit Server is not available\r\n");
2924                         debug(F110,"proto()",
2925                              "A Kermit Server is not available",0);
2926                         tlog(F110,"IKS client/server failure",
2927                              "A Kermit Server is not available",0);
2928                         goto xxprotox;
2929                     }
2930                 }
2931             }
2932         }
2933 #endif /* IKS_OPTION */
2934 #ifdef CK_ENCRYPTION
2935         if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
2936             ck_tn_enc_stop();
2937         }
2938 #endif /* CK_ENCRYPTION */
2939     }
2940 #endif /* TNCODE */
2941
2942     if (!xfrint) connoi();
2943     xxproto();                          /* Call the real protocol function */
2944
2945 #ifdef IKS_OPTION
2946   xxprotox:
2947 #endif /* IKS_OPTION */
2948     xferstat = success;                 /* Remember transfer status */
2949     kactive = 0;
2950
2951 #ifdef TNCODE
2952 #ifdef CK_ENCRYPTION
2953         if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
2954             ck_tn_enc_start();
2955         }
2956 #endif /* CK_ENCRYPTION */
2957 #ifdef IKS_OPTION
2958     if (TELOPT_ME(TELOPT_KERMIT) &&
2959         TELOPT_SB(TELOPT_KERMIT).kermit.me_start && !_me_start) {
2960         tn_siks(KERMIT_STOP);           /* Server is stopped */
2961         TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2962     }
2963 #endif /* IKS_OPTION */
2964     if (is_tn && tn_b_xfer && !(sstelnet || inserver)) {
2965         /* if we negotiated Binary mode try to reset it */
2966         if (!_u_bin) {
2967             /* Check to see if the state changed during the transfer */
2968             if (TELOPT_U(TELOPT_BINARY)) {
2969                 tn_sopt(DONT,TELOPT_BINARY);
2970                 TELOPT_UNANSWERED_DONT(TELOPT_BINARY) = 1;
2971             } else
2972               _u_bin = 1;               /* So we don't call tn_wait() */
2973         }
2974         if (!_me_bin) {
2975             /* Check to see if the state changed during the transfer */
2976             if (TELOPT_ME(TELOPT_BINARY)) {
2977                 tn_sopt(WONT,TELOPT_BINARY);
2978                 TELOPT_UNANSWERED_WONT(TELOPT_BINARY) = 1;
2979             } else
2980               _me_bin = 1;              /* So we don't call tn_wait() */
2981         }
2982         if (!(_me_bin && _u_bin))
2983           tn_wait("proto reset binary mode");
2984     }
2985 #endif /* TNCODE */
2986
2987 #ifdef PATTERNS
2988     patterns = pa_save;
2989 #endif /* PATTERNS */
2990     filepeek = scan_save;
2991
2992 #ifdef STREAMING
2993     streaming = 0;
2994     /* streamok = 0; */
2995 #endif /* STREAMING */
2996 #ifdef COMMENT
2997 #ifdef CK_SPEED
2998     for (i = 0; i < 256; i++)
2999       ctlp[i] = s_ctlp[i];
3000     f_ctlp = 0;
3001 #endif /* CK_SPEED */
3002 #endif /* COMMENT */
3003     urclear = 0;
3004     if (!success) {
3005         xitsta |= (what & W_KERMIT);
3006         tlog(F110," failed:",(char *)epktmsg,0);
3007     }
3008     debug(F111,"proto xferstat",epktmsg,xferstat);
3009     slostart = ss_save;
3010     if (s_timint > -1) {                /* Because of REMOTE SET */
3011         timint = s_timint;
3012         s_timint = -1;
3013     }
3014     recursive = r_save;
3015     fnspath = p_save;
3016     if (c_save > -1) {                  /* Because of REMOTE SET */
3017         bctr = c_save;
3018         c_save = -1;
3019     }
3020     fncnv   = f_save;
3021     binary  = b_save;
3022 #ifdef PIPESEND
3023     pipesend = 0;                       /* Next time might not be pipesend */
3024 #endif /* PIPESEND */
3025 #ifndef NOLOCAL
3026 #ifdef OS2
3027     cursorena[vmode] = cursor_save;
3028     term_io = term_io_save;
3029     display_demo = 1;
3030 #endif /* OS2 */
3031 #endif /* NOLOCAL */
3032 }
3033
3034 static VOID
3035 xxproto() {
3036     int x;
3037     long lx;
3038 #ifdef CK_XYZ
3039 #ifdef XYZ_INTERNAL
3040 _PROTOTYP( int pxyz, (int) );
3041 #endif /* XYZ_INTERNAL */
3042 #endif /* CK_XYZ */
3043
3044     char xss[2];                        /* String representation of sstate */
3045     xss[0] = sstate;
3046     xss[1] = NUL;
3047     s_timint = timint;
3048
3049     debug(F101,"xxproto entry justone","",justone);
3050     success = 0;
3051
3052     retrieve = 0;                       /* Reset these ... */
3053     reget = 0;
3054     opkt = 0;
3055
3056     if (local && ttchk() < 0) {         /* Giving BYE or FIN */
3057         if (bye_active) {               /* but there is no connection */
3058             ttclos(0);
3059             success = 1;
3060             return;
3061         }
3062         /* Ditto for any REMOTE command */
3063         if (sstate == 'g' && cmarg ) {
3064             if (*cmarg == 'L' || *cmarg == 'F' || *cmarg == 'X')
3065               success = 1;
3066             else
3067               printf("?No connection\r\n");
3068             return;
3069         }
3070     }
3071
3072 /* Set up the communication line for file transfer. */
3073 /* NOTE: All of the xxscreen() calls prior to the wart() invocation */
3074 /* could just as easily be printf's or, for that matter, hints. */
3075
3076     if (local && (speed < 0L) && (network == 0)) {
3077         xxscreen(SCR_EM,0,0L,"Sorry, you must 'set speed' first");
3078         return;
3079     }
3080     x = -1;
3081     if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {
3082         debug(F111,"failed: proto ttopen local",ttname,local);
3083         xxscreen(SCR_EM,0,0L,"Can't open line");
3084         return;
3085     }
3086     if (x > -1) local = x;
3087     debug(F111,"proto ttopen local",ttname,local);
3088
3089     lx = (local && !network) ? speed : -1;
3090 #ifdef NETCONN
3091 #ifdef CK_SPEED
3092     if (is_tn) {
3093         ctlp[(unsigned)255] = ctlp[CR] = 1;
3094         if (parity == 'e' || parity == 'm') ctlp[127] = 1;
3095         if (flow == FLO_XONX) {         /* Also watch out for Xon/Xoff */
3096             ctlp[17] = ctlp[19] = 1;
3097             ctlp[17+128] = ctlp[19+128] = 1;
3098         }
3099     }
3100 #endif /* CK_SPEED */
3101 #endif /* NETCONN */
3102     if (ttpkt(lx,flow,parity) < 0) {    /* Put line in packet mode, */
3103         xxscreen(SCR_EM,0,0L,"Can't condition line");
3104         return;
3105     }
3106     if (local && !network && carrier != CAR_OFF) {
3107         int x;                          /* Serial connection */
3108         x = ttgmdm();                   /* with carrier checking */
3109         if (x > -1) {
3110             if (!(x & BM_DCD)) {
3111                 debug(F101,"proto ttgmdm","",0);
3112                 xxscreen(SCR_EM,0,0L,"Carrier required but not detected");
3113                 return;
3114             }
3115         }
3116     }
3117     /* Send remote side's "receive" or "server" startup string, if any */
3118     if (local && ckindex((char *)xss,"srgcjhk",0,0,1)) {
3119         char *s = NULL;
3120         if (
3121 #ifdef IKS_OPTION
3122             /* Don't send auto-blah string if we know other side is serving */
3123             !TELOPT_U(TELOPT_KERMIT) ||
3124             !TELOPT_SB(TELOPT_KERMIT).kermit.u_start
3125 #else
3126             1
3127 #endif /* IKS_OPTION */
3128             ) {
3129             if (sstate == 's') {        /* Sending file(s) */
3130                 s = binary ? ptab[protocol].h_b_init : ptab[protocol].h_t_init;
3131             } else if (protocol == PROTO_K) { /* Command for server */
3132                 s = ptab[protocol].h_x_init;
3133             }
3134         }
3135 #ifdef CK_SPEED
3136 #ifndef UNPREFIXZERO
3137         if (protocol == PROTO_K)        /* Because of C-strings... */
3138           ctlp[0] = 1;
3139 #endif /* UNPREFIXZERO */
3140 #endif /* CK_SPEED */
3141         if (s) if (*s) {                /* If we have a command to send... */
3142             char tmpbuf[356];
3143             int tmpbufsiz = 356;
3144             int stuff = -1, stuff2 = -1, len = 0;
3145             extern int tnlm;
3146             if (sstate == 's') {        /* Sending file(s) */
3147 #ifdef CK_XYZ
3148                 if (protocol == PROTO_X) {
3149                     char * s2;
3150                     s2 = cmarg2[0] ? cmarg2 : cmarg;
3151                     if ((int)strlen(s) + (int)strlen(s2) + 4 < 356)
3152                       sprintf(tmpbuf, s, s2);
3153                     else
3154                       tmpbuf[0] = NUL;
3155                 } else {
3156 #endif /* CK_XYZ */
3157                     ckmakmsg(tmpbuf, 356, s, NULL, NULL, NULL);
3158 #ifdef CK_XYZ
3159                 }
3160 #endif /* CK_XYZ */
3161             } else {                    /* Command for server */
3162                 ckstrncpy(tmpbuf,s,356);
3163             }
3164             ckstrncat(tmpbuf, "\015",sizeof(tmpbuf));
3165             if (tnlm)                   /* TERMINAL NEWLINE ON */
3166               stuff = LF;               /* Stuff LF */
3167 #ifdef TNCODE
3168             /* TELNET NEWLINE MODE */
3169             if (is_tn) {
3170                 switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) {
3171                   case TNL_CR:
3172                     break;
3173                   case TNL_CRNUL:
3174                     break;
3175                   case TNL_CRLF:
3176                     stuff2 = stuff;
3177                     stuff = LF;
3178                     break;
3179                 }
3180             }
3181 #endif /* TNCODE */
3182
3183 #ifdef NETCONN
3184 #ifdef TCPSOCKET
3185 #ifdef RLOGCODE
3186             if (network && ttnproto == NP_RLOGIN) {
3187                 switch (tn_b_nlm) { /* Always BINARY */
3188                   case TNL_CR:
3189                     break;
3190                   case TNL_CRNUL:
3191                     stuff2 = stuff;
3192                     stuff  = NUL;
3193                     break;
3194                   case TNL_CRLF:
3195                     stuff2 = stuff;
3196                     stuff = LF;
3197                     break;
3198                 }
3199             }
3200 #endif /* RLOGCODE */
3201 #endif /* TCPSOCKET */
3202 #endif /* NETCONN */
3203
3204             len = strlen(tmpbuf);
3205             if (stuff >= 0 && len < tmpbufsiz - 1) {
3206                 tmpbuf[len++] = stuff;
3207                 if (stuff2 >= 0 && len < tmpbufsiz - 1)
3208                   tmpbuf[len++] = stuff2;
3209                 tmpbuf[len] = NUL;
3210             }
3211             ttol((CHAR *)tmpbuf,len);
3212             if (protocol == PROTO_K)    /* Give remote Kermit time to start */
3213               msleep(400);
3214         }
3215     }
3216
3217 #ifdef CK_XYZ
3218     if (protocol != PROTO_K) {          /* Non-Kermit protocol selected */
3219         char tmpbuf[356];
3220         int tmpbufsiz = 356;
3221         char * s = "";
3222
3223 #ifdef CK_TMPDIR
3224         if (sstate == 'v') {            /* If receiving and... */
3225             if (dldir && !f_tmpdir) {   /* if they have a download directory */
3226                 if (s = zgtdir()) {     /* Get current directory */
3227                     if (zchdir(dldir)) { /* Change to download directory */
3228                         ckstrncpy(savdir,s,TMPDIRLEN);
3229                         f_tmpdir = 1;   /* Remember that we did this */
3230                     }
3231                 }
3232             }
3233         }
3234 #endif /* CK_TMPDIR */
3235
3236 #ifdef XYZ_INTERNAL                     /* Internal */
3237         success = !pxyz(sstate);
3238 #else
3239 #ifdef CK_REDIR                         /* External */
3240         switch (sstate) {
3241           case 's':                     /* 'Tis better to SEND... */
3242             s = binary ? ptab[protocol].p_b_scmd : ptab[protocol].p_t_scmd;
3243             break;
3244           case 'v':                     /* ... than RECEIVE */
3245             s = binary ? ptab[protocol].p_b_rcmd : ptab[protocol].p_t_rcmd;
3246             break;
3247         }
3248         if (!s) s = "";
3249         if (*s) {
3250             if (sstate == 's') {        /* Sending */
3251                 extern int xfermode;
3252                 int k = 0, x = 0, b = binary;
3253                 /*
3254                   If just one file we can scan it to set the xfer mode.
3255                   Otherwise it's up to the external protocol program.
3256                 */
3257                 if (patterns && xfermode == XMODE_A && !iswild(fspec)) {
3258                     extern int nscanfile;
3259                     k = scanfile(fspec,&x,nscanfile);
3260                     if (k > -1) {
3261                         b = (k == FT_BIN) ? XYFT_B : XYFT_T;
3262                         s = b ?
3263                             ptab[protocol].p_b_scmd :
3264                             ptab[protocol].p_t_scmd;
3265                     }
3266                 }
3267                 if ((int)strlen(s) + (int)strlen(fspec) < tmpbufsiz) {
3268                     sprintf(tmpbuf,s,fspec); /* safe (prechecked) */
3269                     tlog(F110,"Sending",fspec,0L);
3270                 }
3271             } else {                    /* Receiving */
3272                 if ((int)strlen(s) + (int)strlen(cmarg2) < tmpbufsiz) {
3273                     sprintf(tmpbuf,s,cmarg2); /* safe (prechecked) */
3274                     tlog(F110,"Receiving",cmarg2,0L);
3275                 }
3276             }
3277             tlog(F110," via external protocol:",tmpbuf,0);
3278             debug(F110,"ckcpro ttruncmd",tmpbuf,0);
3279             success = ttruncmd(tmpbuf);
3280             tlog(F110," status:",success ? "OK" : "FAILED", 0);
3281         } else {
3282             printf("?Sorry, no external protocol defined for %s\r\n",
3283                    ptab[protocol].p_name
3284                    );
3285         }
3286 #else
3287         printf(
3288 "Sorry, only Kermit protocol is supported in this version of Kermit\n"
3289                );
3290 #endif /* CK_REDIR */
3291 #endif /* XYZ_INTERNAL */
3292         return;
3293     }
3294 #endif /* CK_XYZ */
3295
3296 #ifdef NTSIGX
3297     conraw();
3298     connoi();
3299 #else
3300     if (!local)
3301       connoi();                         /* No console interrupts if remote */
3302 #endif /* NTSIG */
3303
3304     kactive = 1;
3305     if (sstate == 'x') {                /* If entering server mode, */
3306         extern int howcalled;
3307         server = 1;                     /* set flag, */
3308         debug(F101,"server backgrd","",backgrd);
3309         debug(F101,"server quiet","",quiet);
3310         debug(F100,"SHOULD NOT SEE THIS IF IN BACKGROUND!","",0);
3311         if (howcalled == I_AM_SSHSUB) { /* and issue appropriate message. */
3312             ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
3313         } else if (!local) {
3314             if (!quiet && !backgrd
3315 #ifdef IKS_OPTION
3316                 && !TELOPT_ME(TELOPT_KERMIT) /* User was told by negotiation */
3317 #endif /* IKS_OPTION */
3318                 ) {
3319                 conoll(srvtxt);
3320                 conoll("KERMIT READY TO SERVE...");
3321             }
3322         } else {
3323             conol("Entering server mode on ");
3324             conoll(ttname);
3325             conoll("Type Ctrl-C to quit.");
3326             if (srvdis) intmsg(-1L);
3327 #ifdef TCPSOCKET
3328 #ifndef NOLISTEN
3329             if (network && tcpsrfd > 0)
3330               ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
3331 #endif /* NOLISTEN */
3332 #endif /* TCPSOCKET */
3333         }
3334     } else
3335       server = 0;
3336 #ifdef VMS
3337     if (!quiet && !backgrd)    /* So message doesn't overwrite prompt */
3338       conoll("");
3339     if (local) conres();       /* So Ctrl-C will work */
3340 #endif /* VMS */
3341 /*
3342   If in remote mode, not shushed, not in background, and at top command level,
3343   issue a helpful message telling what to do...
3344 */
3345     if (!local && !quiet && !backgrd) {
3346         if (sstate == 'v') {
3347             conoll("Return to your local Kermit and give a SEND command.");
3348             conoll("");
3349             conoll("KERMIT READY TO RECEIVE...");
3350         } else if (sstate == 's') {
3351             conoll("Return to your local Kermit and give a RECEIVE command.");
3352             conoll("");
3353             conoll("KERMIT READY TO SEND...");
3354         } else if ( sstate == 'g' || sstate == 'r' || sstate == 'h' ||
3355                     sstate == 'j' || sstate == 'c' ) {
3356             conoll("Return to your local Kermit and give a SERVER command.");
3357             conoll("");
3358             conoll((sstate == 'r' || sstate == 'j' || sstate == 'h') ?
3359                    "KERMIT READY TO GET..." :
3360                    "KERMIT READY TO SEND SERVER COMMAND...");
3361         }
3362     }
3363 #ifdef COMMENT
3364     if (!local) sleep(1);
3365 #endif /* COMMENT */
3366 /*
3367   The 'wart()' function is generated by the wart program.  It gets a
3368   character from the input() routine and then based on that character and
3369   the current state, selects the appropriate action, according to the state
3370   table above, which is transformed by the wart program into a big case
3371   statement.  The function is active for one transaction.
3372 */
3373     rtimer();                           /* Reset elapsed-time timer */
3374 #ifdef GFTIMER
3375     rftimer();
3376 #endif /* GFTIMER */
3377     resetc();                           /* & other per-transaction counters. */
3378
3379     debug(F101,"proto calling wart, justone","",justone);
3380
3381     wart();                             /* Enter the state table switcher. */
3382 /*
3383   Note: the following is necessary in case we have just done a remote-mode
3384   file transfer, in which case the controlling terminal modes have been
3385   changed by ttpkt().  In particular, special characters like Ctrl-C and
3386   Ctrl-\ might have been turned off (see ttpkt).  So this call to ttres() is
3387   essential.  IMPORTANT: restore interrupt handlers first, otherwise any
3388   terminal interrupts that occur before this is done in the normal place
3389   later will cause a crash.
3390 */
3391 #ifdef OS2
3392     ttres();                            /* Reset the communication device */
3393 #else
3394     if (!local) {
3395         setint();                       /* Arm interrupt handlers FIRST */
3396         msleep(500);
3397         ttres();                        /* Then restore terminal. */
3398     }
3399 #endif /* OS2 */
3400     xxscreen(SCR_TC,0,0L,"");           /* Transaction complete */
3401     x = quiet;
3402     quiet=1;
3403     clsif();                            /* Failsafe in case we missed */
3404     clsof(1);                           /* a case in the state machine. */
3405     quiet = x;
3406
3407     if (server) {                       /* Back from packet protocol. */
3408         if (!quiet && !backgrd
3409 #ifdef IKSD
3410             && !inserver
3411 #endif /* IKSD */
3412             ) {                         /* Give appropriate message */
3413             conoll("");
3414             conoll("C-Kermit server done");
3415         }
3416         server = 0;                     /* Not a server any more */
3417     }
3418 }
3419
3420 /*  S G E T I N I T  --  Handle incoming GET-Class packets  */
3421
3422 /*
3423   Returns:
3424    -1: On error
3425     0: GET packet processed OK - ready to Send.
3426     1: Extended GET processed OK - wait for another.
3427 */
3428 static int
3429 sgetinit(reget,xget) int reget, xget; { /* Server end of GET command */
3430     char * fs = NULL;                   /* Pointer to filespec */
3431     int i, n, done = 0;
3432 #ifdef PIPESEND
3433     extern int usepipes, pipesend;
3434 #endif /* PIPESEND */
3435     extern int nolinks;
3436
3437     if (!ENABLED(en_get)) {             /* Only if not disabled!  */
3438         errpkt((CHAR *)"GET disabled");
3439         return(-1);
3440     }
3441
3442     /* OK to proceed */
3443
3444     nolinks = recursive;
3445     filcnt = 0;
3446
3447 #ifdef WHATAMI
3448     /* If they are alike this was already done in whoarewe() */
3449     debug(F101,"sgetinit whatru","",whatru);
3450     if (whatru & WMI_FLAG) {            /* Did we get WHATAMI info? */
3451         debug(F101,"sgetinit binary (1)","",binary);
3452 #ifdef VMS
3453         if (binary != XYFT_I && binary != XYFT_L)
3454 #else
3455 #ifdef OS2
3456           if (binary != XYFT_L)
3457 #endif /* OS2 */
3458 #endif /* VMS */
3459             binary = (whatru & WMI_FMODE) ? /* Yes, set file type */
3460               XYFT_B : XYFT_T;  /* automatically */
3461         debug(F101,"sgetinit binary (2)","",binary);
3462         if (!wearealike)
3463           fncnv = (whatru & WMI_FNAME) ? 1 : 0; /* And name conversion */
3464     }
3465 #endif /* WHATAMI */
3466
3467     fs = (char *)srvcmd;
3468     srvptr = srvcmd;                    /* Point to server command buffer */
3469     decode(rdatap,putsrv,0);            /* Decode the GET command into it */
3470     /* Accept multiple filespecs */
3471     cmarg2 = "";                        /* Don't use cmarg2 */
3472     cmarg = "";                         /* Don't use cmarg */
3473
3474     done = 1;                           /* Only 1 packet needed... */
3475     if (xget) {                         /* Special decoding for Extended GET */
3476         char L, next, c;                /* PLV items */
3477         int len, val;                   /* More PLV items */
3478         char * p = (char *)srvcmd;      /* String to decode */
3479
3480         done = 0;                       /* Maybe more packets needed */
3481         fs = NULL;                      /* We don't know the filespec yet */
3482         c = *p++;                       /* Get first parameter */
3483
3484         while (c) {                     /* For all parameters... */
3485             debug(F000,"sgetinit c","",c);
3486             L = *p++;                   /* Get length */
3487             if (L >= SP)                /* Decode length */
3488               len = xunchar(L);
3489             else if (c == '@') {        /* Allow missing EOP length field */
3490                 len = 0;
3491             } else {
3492                 len = (xunchar(*p++) * 95);
3493                 len += xunchar(*p++);
3494             }
3495             debug(F101,"sgetinit len","",len);
3496             next = *(p+len);            /* Get next parameter */
3497             *(p+len) = NUL;             /* Zero it out to terminal value */
3498             debug(F110,"sgetinit p",p,0);
3499             switch (c) {                /* Do the parameter */
3500               case 'O':                 /* GET Options */
3501                 val = atoi(p);          /* Convert to int */
3502                 debug(F101,"sgetinit O val","",val);
3503                 if (val & GOPT_DEL) moving = 1;
3504                 if (val & GOPT_RES) reget = 1;
3505                 if (val & GOPT_REC) {
3506                     recursive = 1;
3507                     nolinks = 2;
3508                     if (fnspath == PATH_OFF)
3509                       fnspath = PATH_REL;
3510                 }
3511                 break;
3512               case 'M':                 /* Transfer Mode */
3513                 val = atoi(p);
3514                 debug(F101,"sgetinit M val","",val);
3515                 if (val < 1)
3516                   break;
3517                 patterns = 0;           /* Takes precedence over patterns */
3518                 filepeek = 0;           /* and FILE SCAN */
3519                 if (val == GMOD_TXT) binary = XYFT_T; /* Text */
3520                 if (val == GMOD_BIN) binary = XYFT_B; /* Binary */
3521                 if (val == GMOD_LBL) binary = XYFT_L; /* Labeled */
3522                 break;
3523               case 'F':                 /* Filename */
3524                 fs = p;
3525                 debug(F110,"sgetinit filename",fs,0);
3526                 break;
3527               case '@':                 /* End Of Parameters */
3528                 done = 1;
3529                 debug(F100,"sgetinit EOP","",0);
3530                 break;
3531               default:
3532                 errpkt((CHAR *)"Unknown GET Parameter");
3533                 debug(F100,"sgetinit unknown parameter","",0);
3534                 return(-1);
3535             }
3536             p += (len + 1);
3537             c = next;
3538         }
3539     }
3540     if (!fs) fs = "";                   /* A filename is required */
3541     if (*fs) {
3542         havefs = 1;
3543         n = 0;                          /* Check for quoted name */
3544         if ((n = strlen(fs)) > 1) {
3545             /* Note: this does not allow for multiple quoted names */
3546             if ((fs[0] == '{' && fs[n-1] == '}') ||
3547                 (fs[0] == '"' && fs[n-1] == '"')) {
3548                 fs[n-1] = '\0';
3549                 fs++;
3550                 debug(F111,"sgetinit unquoted filename",fs,n);
3551             } else
3552               n = 0;                    /* This means no quoting */
3553         }
3554
3555 #ifdef PIPESEND
3556         debug(F111,"sgetinit",fs,usepipes);
3557         if (usepipes && ENABLED(en_hos) && *fs == '!') {
3558             cmarg = fs + 1;             /* Point past the bang */
3559             *fs = NUL;
3560             nfils = -1;
3561             pipesend = 1;
3562             debug(F111,"sgetinit pipesend",cmarg,pipesend);
3563         }
3564         if (!pipesend) {                /* If it's not a pipe */
3565 #endif /* PIPESEND */
3566             if (n == 0) {               /* If the name was not quoted */
3567 #ifndef NOMSEND
3568                 nfils = fnparse(fs);    /* Allow it to be a list of names */
3569                 debug(F111,"sgetinit A",fs,nfils);
3570 #ifdef COMMENT
3571 /* This doesn't work if a GET-PATH is set. */
3572                 if (nfils == 1 && !iswild(fs)) { /* Single file */
3573                     char * m;
3574                     if ((x = zchki(fs)) < 0) { /* Check if it's sendable */
3575                         switch (x) {
3576                           case -1: m = "File not found"; break;
3577                           case -2: m = "Not a regular file"; break;
3578                           case -3: m = "Read access denied"; break;
3579                         }
3580                         errpkt((CHAR *)m);
3581                         return(-1);
3582                     }
3583                 }
3584 #endif /* COMMENT */
3585             } else {                    /* If it was quoted */
3586 #endif /* NOMSEND */
3587                 nzxopts = 0;
3588 #ifdef UNIXOROSK
3589                 if (matchdot)  nzxopts |= ZX_MATCHDOT;
3590 #endif /* UNIXOROSK */
3591                 if (recursive) nzxopts |= ZX_RECURSE;
3592                 /* Treat as a single filespec */
3593                 nfils = 0 - nzxpand(fs,nzxopts);
3594                 debug(F111,"sgetinit B",fs,nfils);
3595                 cmarg = fs;
3596             }
3597 #ifdef PIPESEND
3598         }
3599 #endif /* PIPESEND */
3600     }
3601     if (!done) {                        /* Need more O packets... */
3602         debug(F100,"sgetinit O-Packet TBC","",0); /* To Be Continued */
3603         return(1);
3604     }
3605     debug(F100,"sgetinit O-Packet done - havefs","",havefs);
3606     if (!havefs) {                      /* Done - make sure we have filename */
3607         errpkt((CHAR *)"GET without filename");
3608         return(-1);
3609     }
3610     freerpkt(winlo);
3611     winlo = 0;                          /* Back to packet 0 again. */
3612     debug(F101,"sgetinit winlo","",winlo);
3613     nakstate = 0;                       /* Now I'm the sender! */
3614     if (reget) sendmode = SM_RESEND;
3615     if (sinit() > 0) {                  /* Send Send-Init */
3616 #ifdef STREAMING
3617         if (!streaming)
3618 #endif /* STREAMING */
3619           timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
3620         return(0);                      /* If successful, switch state */
3621     } else return(-1);                  /* Else back to server command wait */
3622 }
3623
3624 #else  /* NOXFER */
3625
3626 #include "ckcdeb.h"
3627
3628 VOID
3629 proto() {
3630     extern int success;
3631     success = 0;
3632 }
3633 #endif /* NOXFER */