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