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