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