1 char *protv = /* -*-C-*- */
2 "C-Kermit Protocol Module 8.0.158, 11 Sep 2002";
4 int kactive = 0; /* Kermit protocol is active */
8 /* C K C P R O -- C-Kermit Protocol Module, in Wart preprocessor notation. */
10 Author: Frank da Cruz <fdc@columbia.edu>,
11 Columbia University Academic Information Systems, New York City.
13 Copyright (C) 1985, 2004,
14 Trustees of Columbia University in the City of New York.
15 All rights reserved. See the C-Kermit COPYING.TXT file or the
16 copyright text in the ckcmai.c module for disclaimer and permissions.
26 #define INCL_VIO /* Needed for ckocon.h */
34 Note -- This file may also be preprocessed by the UNIX Lex program, but
35 you must indent the above #include statements before using Lex, and then
36 restore them to the left margin in the resulting C program before compilation.
37 Also, the invocation of the "wart()" function below must be replaced by an
38 invocation of the "yylex()" function. It might also be necessary to remove
39 comments in the (%)(%)...(%)(%) section.
42 /* State definitions for Wart (or Lex) */
43 %states ipkt rfile rattr rdpkt ssinit ssfile ssattr ssdata sseof sseot
44 %states serve generic get rgen ssopkt ropkt
46 _PROTOTYP(static VOID xxproto,(void));
47 _PROTOTYP(static VOID wheremsg,(void));
48 _PROTOTYP(int wart,(void));
49 _PROTOTYP(static int sgetinit,(int,int));
50 _PROTOTYP(int sndspace,(int));
52 /* External C-Kermit variable declarations */
53 extern char *versio, *srvtxt, *cmarg, *cmarg2, **cmlist, *rf_err;
54 extern char * rfspec, * sfspec, * srfspec, * rrfspec;
55 extern char * prfspec, * psfspec, * psrfspec, * prrfspec;
56 extern char *cdmsgfile[];
57 extern char * snd_move, * snd_rename, * srimsg;
58 extern char filnam[], ofilnam[], fspec[], ttname[], ofn1[];
59 extern CHAR sstate, *srvptr, *data;
60 extern int timint, rtimo, nfils, hcflg, xflg, flow, mdmtyp, network;
61 extern int oopts, omode, oname, opath, nopush, isguest, xcmdsrc, rcdactive;
62 extern int rejection, moving, fncact, bye_active, urserver, fatalio;
63 extern int protocol, prefixing, filcnt, carrier, fnspath, interrupted;
64 extern int recursive, inserver, nzxopts, idletmo, srvidl, xfrint;
65 extern struct ck_p ptab[];
66 extern int remfile, rempipe, xferstat, filestatus, wearealike, fackpath;
67 extern int patterns, filepeek, gnferror;
68 extern char * remdest;
72 static char ipktack[PKTZEROLEN];
73 static int ipktlen = 0;
74 #endif /* PKTZEROHACK */
76 static int s_timint = -1; /* For saving timeout value */
78 static int havefs = 0;
80 static int logtries = 0;
83 static int cancel = 0;
87 extern int streaming, streamok;
92 debug(F100,"streamon","",0);
94 timint = 0; /* No timeouts while streaming. */
98 #ifdef COMMENT /* (not used) */
102 debug(F100,"streamoff","",0);
104 timint = s_timint; /* Restore timeout */
108 #else /* STREAMING */
111 #endif /* STREAMING */
114 _PROTOTYP( int addmac, (char *, char *) );
115 _PROTOTYP( int zzstring, (char *, char **, int *) );
118 _PROTOTYP( int cmdsrc, (void) );
122 extern char * x_user, * x_passwd, * x_acct;
123 extern int x_login, x_logged;
124 #endif /* NOSERVER */
129 extern int ttnproto; /* Network protocol */
133 extern short ctlp[]; /* Control-character prefix table */
134 #endif /* CK_SPEED */
137 extern int tn_b_nlm, tn_b_xfer, tn_nlm;
139 extern int tn_no_encrypt_xfer;
140 #endif /* CK_ENCRYPTION */
146 #endif /* NOLISTEN */
147 #endif /* TCPSOCKET */
149 extern int cxseen, czseen, server, srvdis, local, displa, bctu, bctr, bctl;
150 extern int quiet, tsecs, parity, backgrd, nakstate, atcapu, wslotn, winlo;
151 extern int wslots, success, xitsta, rprintf, discard, cdtimo, keep, fdispla;
152 extern int timef, stdinf, rscapu, sendmode, epktflg, epktrcvd, epktsent;
153 extern int binary, fncnv;
154 extern long speed, ffc, crc16, calibrate, dest;
156 extern char *TYPCMD, *DIRCMD, *DIRCM2;
159 extern char *SPACMD, *SPACM2, *WHOCMD;
162 extern struct zattr iattr;
169 extern CKFLOAT fptsecs;
173 extern CHAR *epktmsg;
176 extern int f_tmpdir; /* Directory changed temporarily */
177 extern char savdir[]; /* For saving current directory */
179 #endif /* CK_TMPDIR */
181 extern int query; /* Query-active flag */
184 char querybuf[QBUFL+1] = { NUL, NUL }; /* QUERY response buffer */
185 char *qbufp = querybuf; /* Pointer to it */
186 int qbufn = 0; /* Length of data in it */
195 If the following flag is nonzero when the protocol module is entered,
196 then server mode persists for exactly one transaction, rather than
197 looping until BYE or FINISH is received.
201 static int r_save = -1;
202 static int p_save = -1;
204 /* Function to let remote-mode user know where their file(s) went */
206 int whereflg = 1; /* Unset with SET XFER REPORT */
210 extern int quiet, filrej;
213 debug(F101,"wheremsg n","",n);
215 debug(F110,"wheremsg prfspec",prfspec,0);
216 debug(F110,"wheremsg rfspec",rfspec,0);
217 debug(F110,"wheremsg psfspec",psfspec,0);
218 debug(F110,"wheremsg sfspec",sfspec,0);
220 debug(F110,"wheremsg prrfspec",prrfspec,0);
221 debug(F110,"wheremsg rrfspec",rrfspec,0);
222 debug(F110,"wheremsg psrfspec",psrfspec,0);
223 debug(F110,"wheremsg srfspec",srfspec,0);
225 if (!quiet && !local) {
230 printf(" SENT: [%s]",sfspec);
232 printf(" To: [%s]",srfspec);
233 printf(" (%s)\n", success ? "OK" : "FAILED");
239 printf(" RCVD: [%s]",rrfspec);
241 printf(" To: [%s]",rfspec);
242 printf(" (%s)\n", success ? "OK" : "FAILED");
249 printf(" SENT: (%d files)",n);
251 printf(" Last: [%s]",srfspec);
252 printf(" (%s)\n", success ? "OK" : "FAILED");
258 printf(" RCVD: (%d files)",n);
260 printf(" Last: [%s]",rfspec);
261 printf(" (%s)\n", success ? "OK" : "FAILED");
266 printf(" SENT: (0 files) \n");
267 else if (myjob == 'r' || myjob == 'v')
268 printf(" RCVD: (0 files) \n");
276 debug(F111,"RESUME","server=1",justone);
278 debug(F111,"RESUME","server=0",justone);
281 /* Flags for the ENABLE and DISABLE commands */
283 en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri,
284 en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, en_ret, en_xit,
287 extern int en_asg, en_que;
289 extern int what, lastxfer;
291 /* Global variables declared here */
293 int whatru = 0; /* What are you. */
294 int whatru2 = 0; /* What are you, cont'd. */
296 /* Local variables */
298 static char vstate = 0; /* Saved State */
299 static char vcmd = 0; /* Saved Command */
300 static int reget = 0; /* Flag for executing REGET */
301 static int retrieve = 0; /* Flag for executing RETRIEVE */
302 static int opkt = 0; /* Send Extended GET packet */
304 static int x; /* General-purpose integer */
305 static char *s; /* General-purpose string pointer */
307 /* Macros - Note, BEGIN is predefined by Wart (and Lex) as "state = ", */
308 /* BEGIN is NOT a GOTO! */
309 #define TINIT if (tinit(1) < 0) return(-9)
310 #define SERVE { TINIT; resetc(); nakstate=1; what=W_NOTHING; cmarg2=""; \
311 sendmode=SM_SEND; havefs=0; recursive=r_save; fnspath=p_save; BEGIN serve; }
312 #define RESUME { rdebug(); if (!server) { wheremsg(); return(0); } else \
313 if (justone) { justone=0; wheremsg(); return(0); } else { SERVE; } }
316 #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); \
317 fptsecs=gftimer(); quiet=x; return(success)
319 #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); quiet=x; \
324 By late 1999, the big switch() statement generated from the following state
325 table began choking even gcc, so here we extract the code from the larger
326 states into static routines to reduce the size of the cases and the
327 switch() overall. The routines follow the state table; the prototypes are
328 here. Each of these routines simply contains the text from the
329 corresponding case, but with return(-1) added in appropriate places; see
330 instructions after the state table switcher.
332 static int rc; /* Return code for these routines */
333 static int rcv_s_pkt(); /* Received an S packet */
334 static int rcv_firstdata(); /* Received first Data packet */
335 static int rcv_shortreply(); /* Short reply to a REMOTE command */
336 static int srv_query(); /* Server answers an query */
337 static int srv_copy(); /* Server executes REMOTE COPY */
338 static int srv_rename(); /* Server executes REMOTE RENAME */
339 static int srv_login(); /* Server executes REMOTE LOGIN */
340 static int srv_timeout(); /* Server times out */
345 Protocol entry points, one for each start state (sstate).
346 The lowercase letters are internal "inputs" from the user interface.
347 NOTE: The start state letters that appear on the left margin immediately
348 below can NOT be used as packet types OR as G-packet subcodes.
351 s { TINIT; /* Send file(s) */
352 if (sinit() > 0) BEGIN ssinit;
355 v { TINIT; nakstate = 1; BEGIN get; } /* Receive file(s) */
357 r { /* Client sends a GET command */
366 #endif /* PKTZEROHACK */
373 h { /* Client sends a RETRIEVE command */
385 j { /* Client sends a REGET command */
397 o { /* Client sends Extended GET Packet */
400 reget = oopts & GOPT_RES;
401 retrieve = oopts & GOPT_DEL;
409 c { /* Client sends a Host command */
418 k { TINIT; /* Client sends a Kermit command */
426 g { /* Client sends a REMOTE command */
435 x { /* Enter server mode */
438 if (!ENABLED(en_del)) { /* If DELETE is disabled */
439 if (fncact == XYFX_B || /* undo any file collision action */
440 fncact == XYFX_U || /* that could result in deletion or */
441 fncact == XYFX_A || /* modification of existing files. */
445 g_fncact = fncact; /* Save current setting */
447 fncact = XYFX_R; /* Change to RENAME */
448 debug(F101,"server DELETE disabled so fncact RENAME","",fncact);
451 SERVE; /* tinit() clears justone... */
454 if (ikdbopen) slotstate(what, "SERVER", "", "");
460 if (!data) TINIT; /* "ABEND" -- Tell other side. */
462 if (epktflg) { /* If because of E-PACKET command */
463 b1 = bctl; b2 = bctu; /* Save block check type */
464 bctl = bctu = 1; /* set it to 1 */
467 errpkt((CHAR *)"User cancelled"); /* Send the packet */
469 if (epktflg) { /* Restore the block check */
471 bctl = b1; bctu = b2;
475 return(0); /* Return from protocol. */
479 Dynamic states: <current-states>input-character { action }
480 nakstate != 0 means we're in a receiving state, in which we send ACKs & NAKs.
483 <rgen,get,serve,ropkt>S { /* Receive Send-Init packet. */
485 cancel = 0; /* Reset cancellation counter */
486 debug(F101,"rcv_s_pkt","",rc);
487 if (rc > -1) return(rc); /* (see below) */
490 /* States in which we get replies back from commands sent to a server. */
491 /* Complicated because direction of protocol changes, packet number */
492 /* stays at zero through I-G-S sequence, and complicated even more by */
493 /* sliding windows buffer allocation. */
495 <ipkt>Y { /* Get ack for I-packet */
498 ckstrncpy(ipktack,(char *)rdatap,PKTZEROLEN); /* Save a copy of the ACK */
499 ipktlen = strlen(ipktack);
500 #endif /* PKTZEROHACK */
501 spar(rdatap); /* Set parameters */
503 winlo = 0; /* Set window-low back to zero */
504 debug(F101,"<ipkt>Y winlo","",winlo);
505 urserver = 1; /* So I know I'm talking to a server */
506 if (vcmd) { /* If sending a generic command */
507 if (tinit(0) < 0) return(-9); /* Initialize many things */
508 x = scmd(vcmd,(CHAR *)cmarg); /* Do that */
509 if (x >= 0) x = 0; /* (because of O-Packet) */
510 debug(F101,"proto G packet scmd","",x);
511 vcmd = 0; /* and then un-remember it. */
512 } else if (vstate == get) {
513 debug(F101,"REGET sstate","",sstate);
514 x = srinit(reget, retrieve, opkt); /* GET or REGET, etc */
516 if (x < 0) { /* If command was too long */
518 srimsg = "Error sending string";
519 errpkt((CHAR *)srimsg); /* cancel both sides. */
522 } else if (x > 0) { /* Need to send more O-Packets */
525 rtimer(); /* Reset the elapsed seconds timer. */
529 winlo = 0; /* Window back to 0, again. */
530 debug(F101,"<ipkt>Y vstate","",vstate);
531 nakstate = 1; /* Can send NAKs from here. */
532 BEGIN vstate; /* Switch to desired state */
536 <ssopkt>Y { /* Got ACK to O-Packet */
537 debug(F100,"CPCPRO <ssopkt>Y","",0);
539 debug(F101,"CPCPRO <ssopkt>Y x","",x);
540 if (x < 0) { /* If error */
541 errpkt((CHAR *)srimsg); /* cancel both sides. */
544 } else if (x == 0) { /* This was the last O-Packet */
545 rtimer(); /* Reset the elapsed seconds timer. */
549 winlo = 0; /* Window back to 0, again. */
550 debug(F101,"<ssopkt>Y winlo","",winlo);
551 nakstate = 1; /* Can send NAKs from here. */
552 BEGIN vstate; /* Switch to desired state */
554 debug(F101,"CPCPRO <ssopkt>Y not changing state","",x);
557 <ipkt>E { /* Ignore Error reply to I packet */
559 winlo = 0; /* Set window-low back to zero */
560 debug(F101,"<ipkt>E winlo","",winlo);
561 if (vcmd) { /* In case other Kermit doesn't */
562 if (tinit(0) < 0) return(-9);
563 x = scmd(vcmd,(CHAR *)cmarg); /* understand I-packets. */
564 if (x >= 0) x = 0; /* (because of O-Packet) */
565 vcmd = 0; /* Otherwise act as above... */
566 } else if (vstate == get) x = srinit(reget, retrieve, opkt);
567 if (x < 0) { /* If command was too long */
568 errpkt((CHAR *)srimsg); /* cancel both sides. */
571 } else if (x > 0) { /* Need to send more O-Packets */
574 freerpkt(winlo); /* Discard the Error packet. */
575 debug(F101,"<ipkt>E winlo","",winlo);
576 winlo = 0; /* Back to packet 0 again. */
577 nakstate = 1; /* Can send NAKs from here. */
582 <get>Y { /* Resend of previous I-pkt ACK, same seq number */
583 freerpkt(0); /* Free the ACK's receive buffer */
584 resend(0); /* Send the GET packet again. */
587 /* States in which we're being a server */
589 <serve,get>I { /* Get I-packet */
591 spar(rdatap); /* Set parameters from it */
592 ack1(rpar()); /* Respond with our own parameters */
594 pktinit(); /* Reinitialize packet numbers */
597 /* This can't be right - it undoes the stuff we just negotiated */
599 tinit(1); /* Reinitialize EVERYTHING */
600 justone = x; /* But this... */
602 tinit(0); /* Initialize most things */
605 #endif /* NOSERVER */
606 cancel = 0; /* Reset cancellation counter */
611 if (x_login && !x_logged) {
612 errpkt((CHAR *)"Login required");
614 } else if (sgetinit(0,0) < 0) {
618 if (ckxsyslog >= SYSLG_PR && ckxlogging)
619 cksyslog(SYSLG_PR, 1, "server", "GET", (char *)srvcmd);
620 #endif /* CKSYSLOG */
623 #endif /* NOSERVER */
626 <serve>H { /* GET /DELETE (RETRIEVE) */
628 if (x_login && !x_logged) {
629 errpkt((CHAR *)"Login required");
631 } else if (!ENABLED(en_del)) {
632 errpkt((CHAR *)"Deleting files is disabled");
634 } else if (sgetinit(0,0) < 0) {
639 if (ckxsyslog >= SYSLG_PR && ckxlogging)
640 cksyslog(SYSLG_PR, 1, "server", "GET /DELETE", (char *)srvcmd);
641 #endif /* CKSYSLOG */
644 #endif /* NOSERVER */
647 <serve>V { /* GET /RECURSIVE */
649 recursive = 1; /* Set these before sgetinit() */
650 if (fnspath == PATH_OFF)
651 fnspath = PATH_REL; /* Don't worry, they will be */
652 if (x_login && !x_logged) { /* reset next time through. */
653 errpkt((CHAR *)"Login required");
655 } else if (sgetinit(0,0) < 0) {
659 if (ckxsyslog >= SYSLG_PR && ckxlogging)
660 cksyslog(SYSLG_PR, 1, "server", "GET /RECURSIVE", (char *)srvcmd);
661 #endif /* CKSYSLOG */
664 #endif /* NOSERVER */
667 <serve>W { /* GET /RECURSIVE /DELETE */
669 recursive = 1; /* Set these before sgetinit() */
670 if (fnspath == PATH_OFF)
671 fnspath = PATH_REL; /* Don't worry, they will be */
672 moving = 1; /* reset next time through. */
673 if (x_login && !x_logged) {
674 errpkt((CHAR *)"Login required");
676 } else if (!ENABLED(en_del)) {
677 errpkt((CHAR *)"Deleting files is disabled");
679 } else if (sgetinit(0,0) < 0) {
683 if (ckxsyslog >= SYSLG_PR && ckxlogging)
684 cksyslog(SYSLG_PR,1,"server",
685 "GET /RECURSIVE /DELETE",(char *)srvcmd);
686 #endif /* CKSYSLOG */
689 #endif /* NOSERVER */
692 <serve>J { /* GET /RECOVER (REGET) */
694 if (x_login && !x_logged) {
695 errpkt((CHAR *)"Login required");
697 } else if (sgetinit(1,0) < 0) {
701 if (ckxsyslog >= SYSLG_PR && ckxlogging)
702 cksyslog(SYSLG_PR, 1, "server", "GET /RECOVER", (char *)srvcmd);
703 #endif /* CKSYSLOG */
706 #endif /* NOSERVER */
709 <serve>O { /* Extended GET */
711 if (x_login && !x_logged) { /* (any combination of options) */
712 errpkt((CHAR *)"Login required");
714 } else if ((x = sgetinit(0,1)) < 0) {
715 debug(F101,"CKCPRO <serve>O sgetinit fail","",x);
718 debug(F101,"CKCPRO <serve>O sgetinit done","",x);
720 if (ckxsyslog >= SYSLG_PR && ckxlogging)
721 cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
722 #endif /* CKSYSLOG */
724 } else { /* Otherwise stay in this state */
725 debug(F101,"CKCPRO <serve>O sgetinit TBC","",x);
729 #endif /* NOSERVER */
734 if (x_login && !x_logged) { /* (any combination of options) */
735 errpkt((CHAR *)"Login required");
737 } else if ((x = sgetinit(0,1)) < 0) {
738 debug(F101,"CKCPRO <ropkt>O sgetinit fail","",x);
741 debug(F101,"CKCPRO <ropkt>O sgetinit done","",x);
743 if (ckxsyslog >= SYSLG_PR && ckxlogging)
744 cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
745 #endif /* CKSYSLOG */
747 } else { /* Otherwise stay in this state */
748 debug(F101,"CKCPRO <ropkt>O sgetinit TBC","",x);
751 #endif /* NOSERVER */
754 <serve>G { /* Generic server command */
756 srvptr = srvcmd; /* Point to command buffer */
757 decode(rdatap,putsrv,0); /* Decode packet data into it */
758 putsrv(NUL); /* Insert a couple nulls */
759 putsrv(NUL); /* for termination */
761 sstate = srvcmd[0]; /* Set requested start state */
762 if (x_login && !x_logged && /* Login required? */
763 /* Login, Logout, and Help are allowed when not logged in */
764 sstate != 'I' && sstate != 'L' && sstate != 'H') {
765 errpkt((CHAR *)"Login required");
768 nakstate = 0; /* Now I'm the sender. */
769 what = W_REMO; /* Doing a REMOTE command. */
772 #endif /* STREAMING */
774 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
775 binary = XYFT_T; /* Switch to text mode */
776 BEGIN generic; /* Switch to generic command state */
779 errpkt((CHAR *)"Badly formed server command"); /* report error */
780 RESUME; /* & go back to server command wait */
782 #endif /* NOSERVER */
785 <serve>C { /* Receive Host command */
787 if (x_login && !x_logged) {
788 errpkt((CHAR *)"Login required");
790 } else if (!ENABLED(en_hos)) {
791 errpkt((CHAR *)"REMOTE HOST disabled");
794 errpkt((CHAR *)"HOST commands not available");
797 srvptr = srvcmd; /* Point to command buffer */
798 decode(rdatap,putsrv,0); /* Decode command packet into it */
799 putsrv(NUL); /* Null-terminate */
800 nakstate = 0; /* Now sending, not receiving */
801 binary = XYFT_T; /* Switch to text mode */
802 if (syscmd((char *)srvcmd,"")) { /* Try to execute the command */
803 what = W_REMO; /* Doing a REMOTE command. */
806 #endif /* STREAMING */
808 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
810 if (ckxsyslog >= SYSLG_PR && ckxlogging)
811 cksyslog(SYSLG_PR, 1, "server", "REMOTE HOST", (char *)srvcmd);
812 #endif /* CKSYSLOG */
813 BEGIN ssinit; /* If OK, send back its output */
814 } else { /* Otherwise */
815 errpkt((CHAR *)"Can't do system command"); /* report error */
816 RESUME; /* & go back to server command wait */
819 #endif /* NOSERVER */
822 <serve>q { /* Interrupted or connection lost */
824 debug(F101,"srv_timeout","",rc);
825 if (rc > -1) return(rc); /* (see below) */
828 <serve>N { /* Server got a NAK in command-wait */
830 errpkt((CHAR *)"Did you say RECEIVE instead of GET?");
832 #endif /* NOSERVER */
835 <serve>. { /* Any other command in this state */
837 if (c != ('E' - SP) && c != ('Y' - SP)) /* except E and Y packets. */
838 errpkt((CHAR *)"Unimplemented server function");
839 /* If we answer an E with an E, we get an infinite loop. */
840 /* A Y (ACK) can show up here if we sent back a short-form reply to */
841 /* a G packet and it was echoed. ACKs can be safely ignored here. */
842 RESUME; /* Go back to server command wait. */
843 #endif /* NOSERVER */
846 <generic>I { /* Login/Out */
848 debug(F101,"<generic>I srv_login","",rc);
849 if (rc > -1) return(rc); /* (see below) */
852 <generic>C { /* Got REMOTE CD command */
855 if (ckxsyslog >= SYSLG_PR && ckxlogging)
856 cksyslog(SYSLG_PR, 1, "server", "REMOTE CD", (char *)srvcmd);
857 #endif /* CKSYSLOG */
858 if (!ENABLED(en_cwd)) {
859 errpkt((CHAR *)"REMOTE CD disabled");
863 x = cwd((char *)(srvcmd+1)); /* Try to change directory */
865 if (ikdbopen) slotstate(what,"REMOTE CD", (char *)(srvcmd+2), "");
867 if (!x) { /* Failed */
868 errpkt((CHAR *)"Can't change directory");
869 RESUME; /* Back to server command wait */
870 } else if (x == 2) { /* User wants message */
871 if (!ENABLED(en_typ)) { /* Messages (REMOTE TYPE) disabled? */
872 errpkt((CHAR *)"REMOTE TYPE disabled");
874 } else { /* TYPE is enabled */
876 for (i = 0; i < 8; i++) {
877 if (zchki(cdmsgfile[i]) > -1) {
881 binary = XYFT_T; /* Use text mode for this. */
882 if (i < 8 && sndtype(cdmsgfile[i])) { /* Have readme file? */
883 BEGIN ssinit; /* OK */
884 } else { /* not OK */
887 success = (*p) ? 1 : 0;
888 ack1((CHAR *)p); /* ACK with new directory name */
890 RESUME; /* wait for next server command */
893 } else { /* User doesn't want message */
896 success = (*p) ? 1 : 0;
899 RESUME; /* Wait for next server command */
902 #endif /* NOSERVER */
905 <generic>A { /* Got REMOTE PWD command */
908 if (ckxsyslog >= SYSLG_PR && ckxlogging)
909 cksyslog(SYSLG_PR, 1, "server", "REMOTE PWD", NULL);
910 #endif /* CKSYSLOG */
911 if (!ENABLED(en_cwd)) {
912 errpkt((CHAR *)"REMOTE CD disabled");
915 if (encstr((CHAR *)zgtdir()) > -1) { /* Encode current directory */
916 ack1(data); /* If it fits, send it back in ACK */
918 } else { /* Failed */
919 ack(); /* Send empty ACK */
920 success = 0; /* and indicate failure locally */
922 RESUME; /* Back to server command wait */
924 #endif /* NOSERVER */
927 <generic>D { /* REMOTE DIRECTORY command */
931 if (ckxsyslog >= SYSLG_PR && ckxlogging)
932 cksyslog(SYSLG_PR, 1, "server", "REMOTE DIRECTORY", (char *)srvcmd);
933 #endif /* CKSYSLOG */
934 if (!ENABLED(en_dir)) { /* If DIR is disabled, */
935 errpkt((CHAR *)"REMOTE DIRECTORY disabled"); /* refuse. */
937 } else { /* DIR is enabled. */
939 if (ikdbopen) slotstate(what,"REMOTE DIR", (char *)(srvcmd+2), "");
941 if (!ENABLED(en_cwd)) { /* But CWD is disabled */
942 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
943 if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
944 errpkt((CHAR *)"Access denied");
945 RESUME; /* Remember, this is not a goto! */
948 if (state == generic) { /* It's OK to go ahead. */
950 n2 = (*(srvcmd+2)) ? DIRCMD : DIRCM2;
951 if (syscmd(n2,(char *)(srvcmd+2))) /* If it can be done */
954 if ((x = snddir((char*)(srvcmd+2))) > 0)
957 BEGIN ssinit; /* send the results back; */
958 } else { /* otherwise */
960 errpkt((CHAR *)"No files match");
962 errpkt((CHAR *)"Can't list directory");
963 RESUME; /* return to server command wait */
967 #endif /* NOSERVER */
970 <generic>E { /* REMOTE DELETE (Erase) */
974 if (ckxsyslog >= SYSLG_PR && ckxlogging)
975 cksyslog(SYSLG_PR, 1, "server", "REMOTE DELETE", (char *)srvcmd);
976 #endif /* CKSYSLOG */
977 if (!ENABLED(en_del)) {
978 errpkt((CHAR *)"REMOTE DELETE disabled");
980 } else { /* DELETE is enabled */
982 if (ikdbopen) slotstate(what,"REMOTE DELETE", (char *)(srvcmd+2), "");
984 if (!ENABLED(en_cwd)) { /* but CWD is disabled */
985 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
986 if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
987 errpkt((CHAR *)"Access denied");
988 RESUME; /* Remember, this is not a goto! */
990 } else if (isdir((char *)(srvcmd+2))) { /* A directory name? */
991 errpkt((CHAR *)"It's a directory");
994 if (state == generic) { /* It's OK to go ahead. */
996 if ((x = snddel((char*)(srvcmd+2))) > 0) {
997 BEGIN ssinit; /* If OK send results back */
998 } else { /* otherwise */
1000 errpkt((CHAR *)"File not found"); /* report failure */
1002 errpkt((CHAR *)"DELETE failed");
1003 RESUME; /* & return to server command wait */
1007 #endif /* NOSERVER */
1010 <generic>F { /* FINISH */
1013 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1014 cksyslog(SYSLG_PR, 1, "server", "FINISH", NULL);
1015 #endif /* CKSYSLOG */
1017 if (ikdbopen) slotstate(what,"SERVER FINISH", "", "");
1019 if (!ENABLED(en_fin)) {
1020 errpkt((CHAR *)"FINISH disabled");
1023 ack(); /* Acknowledge */
1024 xxscreen(SCR_TC,0,0L,""); /* Display */
1026 return(0); /* Done */
1028 #endif /* NOSERVER */
1031 <generic>X { /* EXIT */
1034 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1035 cksyslog(SYSLG_PR, 1, "server", "REMOTE EXIT", NULL);
1036 #endif /* CKSYSLOG */
1038 if (ikdbopen) slotstate(what,"REMOTE EXIT", "", "");
1040 if (!ENABLED(en_xit)) {
1041 errpkt((CHAR *)"EXIT disabled");
1044 ack(); /* Acknowledge */
1045 xxscreen(SCR_TC,0,0L,""); /* Display */
1046 doexit(GOOD_EXIT,xitsta);
1048 #endif /* NOSERVER */
1051 <generic>L { /* BYE (Logout) */
1054 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1055 cksyslog(SYSLG_PR, 1, "server", "BYE", NULL);
1056 #endif /* CKSYSLOG */
1058 if (ikdbopen) slotstate(what,"SERVER BYE", "", "");
1060 if (!ENABLED(en_bye)) {
1061 errpkt((CHAR *)"BYE disabled");
1064 ack(); /* Acknowledge */
1066 msleep(750); /* Give the ACK time to get out */
1068 ttres(); /* Reset the terminal */
1069 xxscreen(SCR_TC,0,0L,""); /* Display */
1070 doclean(1); /* Clean up files, etc */
1072 debug(F100,"C-Kermit BYE - Loggin out...","",0);
1080 #endif /* CK_LOGIN */
1084 if (network && tcpsrfd > 0 && !inserver)
1085 doexit(GOOD_EXIT,xitsta);
1087 #endif /* NOLISTEN */
1088 #endif /* TCPSOCKET */
1089 return(zkself()); /* Try to log self out */
1091 #endif /* NOSERVER */
1094 <generic>H { /* REMOTE HELP */
1096 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1097 cksyslog(SYSLG_PR, 1, "server", "REMOTE HELP", NULL);
1098 #endif /* CKSYSLOG */
1100 if (ikdbopen) slotstate(what,"REMOTE HELP", "", "");
1104 BEGIN ssinit; /* try to send it */
1105 } else { /* If not ok, */
1106 errpkt((CHAR *)"Can't send help"); /* send error message instead */
1107 RESUME; /* and return to server command wait */
1109 #endif /* NOSERVER */
1112 <generic>R { /* REMOTE RENAME */
1114 debug(F101,"srv_rename","",rc);
1115 if (rc > -1) return(rc); /* (see below) */
1118 <generic>K { /* REMOTE COPY */
1120 debug(F101,"srv_copy","",rc);
1121 if (rc > -1) return(rc); /* (see below) */
1124 <generic>S { /* REMOTE SET */
1126 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1127 cksyslog(SYSLG_PR, 1, "server", "REMOTE SET", (char *)srvcmd);
1128 #endif /* CKSYSLOG */
1131 if (ikdbopen) slotstate(what,"REMOTE SET", (char *)(srvcmd+1), "");
1133 if (!ENABLED(en_set)) {
1134 errpkt((CHAR *)"REMOTE SET disabled");
1137 if (remset((char *)(srvcmd+1))) { /* Try to do what they ask */
1139 ack(); /* If OK, then acknowledge */
1140 } else /* Otherwise */
1141 errpkt((CHAR *)"Unknown REMOTE SET parameter"); /* give error msg */
1142 RESUME; /* Return to server command wait */
1144 #endif /* NOSERVER */
1147 <generic>T { /* REMOTE TYPE */
1151 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1152 cksyslog(SYSLG_PR, 1, "server", "REMOTE TYPE", (char *)srvcmd);
1153 #endif /* CKSYSLOG */
1154 if (!ENABLED(en_typ)) {
1155 errpkt((CHAR *)"REMOTE TYPE disabled");
1159 if (ikdbopen) slotstate(what,"REMOTE TYPE", (char *)(srvcmd+2), "");
1161 if (!ENABLED(en_cwd)) { /* If CWD disabled */
1162 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
1163 if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */
1164 errpkt((CHAR *)"Access denied");
1165 RESUME; /* Remember, this is not a goto! */
1168 if (state == generic) { /* It's OK to go ahead. */
1169 binary = XYFT_T; /* Use text mode for this. */
1170 if ( /* (RESUME didn't change state) */
1172 syscmd(TYPCMD,(char *)(srvcmd+2)) /* Old way */
1174 sndtype((char *)(srvcmd+2)) /* New way */
1175 #endif /* COMMENT */
1177 BEGIN ssinit; /* OK */
1179 errpkt((CHAR *)"Can't type file"); /* give error message */
1180 RESUME; /* wait for next server command */
1184 #endif /* NOSERVER */
1187 <generic>m { /* REMOTE MKDIR */
1191 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1192 cksyslog(SYSLG_PR, 1, "server", "REMOTE MKDIR", (char *)srvcmd);
1193 #endif /* CKSYSLOG */
1195 if (ikdbopen) slotstate(what,"REMOTE MKDIR", (char *)(srvcmd+2), "");
1197 if (!ENABLED(en_mkd)) {
1198 errpkt((CHAR *)"REMOTE MKDIR disabled");
1200 } else if (!ENABLED(en_cwd)) { /* If CWD disabled */
1201 errpkt((CHAR *)"Directory access restricted");
1202 RESUME; /* Remember, this is not a goto! */
1204 if (state == generic) { /* OK to go ahead. */
1206 x = ckmkdir(0,(char *)(srvcmd+2),&p,0,1); /* Make the directory */
1209 encstr((CHAR *)p); /* OK - encode the name */
1210 ack1(data); /* Send short-form response */
1213 } else { /* not OK */
1214 if (!*p) p = "Directory creation failure";
1215 errpkt((CHAR *)p); /* give error message */
1216 RESUME; /* Wait for next server command */
1220 errpkt((CHAR *)"REMOTE MKDIR not available");
1222 #endif /* CK_MKDIR */
1223 #endif /* NOSERVER */
1226 <generic>d { /* REMOTE RMDIR */
1230 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1231 cksyslog(SYSLG_PR, 1, "server", "REMOTE RMDIR", (char *)srvcmd);
1232 #endif /* CKSYSLOG */
1234 if (ikdbopen) slotstate(what,"REMOTE RMDIR", (char *)(srvcmd+2), "");
1236 if (!ENABLED(en_rmd)) {
1237 errpkt((CHAR *)"REMOTE RMDIR disabled");
1239 } else if (!ENABLED(en_cwd)) { /* If CWD disabled */
1240 errpkt((CHAR *)"Directory access restricted");
1241 RESUME; /* Remember, this is not a goto! */
1243 if (state == generic) { /* OK to go ahead. */
1245 x = ckmkdir(1,(char *)(srvcmd+2),&p,0,1);
1248 encstr((CHAR *)p); /* OK - encode the name */
1249 ack1(data); /* Send short-form response */
1252 } else { /* not OK */
1253 if (!*p) p = "Directory removal failure";
1254 errpkt((CHAR *)p); /* give error message */
1255 RESUME; /* Wait for next server command */
1259 errpkt((CHAR *)"REMOTE RMDIR not available");
1261 #endif /* CK_MKDIR */
1262 #endif /* NOSERVER */
1265 <generic>U { /* REMOTE SPACE */
1268 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1269 cksyslog(SYSLG_PR, 1, "server", "REMOTE SPACE", (char *)srvcmd);
1270 #endif /* CKSYSLOG */
1271 if (!ENABLED(en_spa)) {
1272 errpkt((CHAR *)"REMOTE SPACE disabled");
1275 x = srvcmd[1]; /* Get area to check */
1276 x = ((x == NUL) || (x == SP)
1278 || (x == '!') || (srvcmd[3] == ':')
1282 if (ikdbopen) slotstate(what,
1284 (x ? "" : (char *)srvcmd),
1288 if (!x && !ENABLED(en_cwd)) { /* CWD disabled */
1289 errpkt((CHAR *)"Access denied"); /* and non-default area given, */
1290 RESUME; /* refuse. */
1293 _PROTOTYP(int sndspace,(int));
1294 if (sndspace(x ? toupper(srvcmd[2]) : 0)) {
1295 BEGIN ssinit; /* send the report. */
1296 } else { /* If not ok, */
1297 errpkt((CHAR *)"Can't send space"); /* send error message */
1298 RESUME; /* and return to server command wait */
1304 x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,(char *)(srvcmd+2)));
1305 if (x) { /* If we got the info */
1306 BEGIN ssinit; /* send it */
1307 } else { /* otherwise */
1308 errpkt((CHAR *)"Can't check space"); /* send error message */
1309 RESUME; /* and await next server command */
1314 #endif /* NOSERVER */
1317 <generic>W { /* REMOTE WHO */
1320 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1321 cksyslog(SYSLG_PR, 1, "server", "REMOTE WHO", (char *)srvcmd);
1322 #endif /* CKSYSLOG */
1324 if (ikdbopen) slotstate(what,"REMOTE WHO", (char *)(srvcmd+2), "");
1326 if (!ENABLED(en_who)) {
1327 errpkt((CHAR *)"REMOTE WHO disabled");
1331 _PROTOTYP(int sndwho,(char *));
1332 if (sndwho((char *)(srvcmd+2))) {
1333 BEGIN ssinit; /* try to send it */
1334 } else { /* If not ok, */
1335 errpkt((CHAR *)"Can't do who command"); /* send error msg */
1336 RESUME; /* and return to server command wait */
1339 if (syscmd(WHOCMD,(char *)(srvcmd+2))) {
1342 errpkt((CHAR *)"Can't do who command");
1347 #endif /* NOSERVER */
1350 <generic>V { /* Variable query or set */
1352 debug(F101,"srv_query","",rc);
1353 if (rc > -1) return(rc);
1356 <generic>q { /* Interrupted or connection lost */
1358 if (fatalio) { /* Connection lost */
1360 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1361 cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
1362 #endif /* CKSYSLOG */
1364 xitsta |= (what & W_KERMIT);
1366 } else if (interrupted) {
1367 if (!ENABLED(en_fin)) { /* Ctrl-C typed */
1368 errpkt((CHAR *)"QUIT disabled");
1372 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1373 cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
1374 #endif /* CKSYSLOG */
1376 xitsta |= (what & W_KERMIT);
1379 } else { /* Shouldn't happen */
1380 debug(F100,"SERVER (generic) GOT UNEXPECTED 'q'","",0);
1383 #endif /* NOSERVER */
1386 <generic>. { /* Anything else in this state... */
1388 errpkt((CHAR *)"Unimplemented REMOTE command"); /* Complain */
1389 RESUME; /* and return to server command wait */
1390 #endif /* NOSERVER */
1393 <rgen>q { /* Sent BYE and connection broken */
1394 if (bye_active && ttchk() < 0) {
1397 ttclos(0); /* Close our end of the connection */
1399 return(success = 1);
1400 } else { /* Other generic command */
1401 return(success = 0); /* or connection not broken */
1405 <rgen>Y { /* Short-Form reply */
1406 rc = rcv_shortreply();
1407 debug(F101,"<rgen>Y rcv_shortreply","",rc);
1408 if (rc > -1) return(rc);
1411 <rgen,rfile>F { /* File header */
1414 debug(F101,"<rfile>F winlo 1","",winlo);
1415 xflg = 0; /* Not screen data */
1417 cancel = 0; /* Reset cancellation counter */
1421 #endif /* CALIBRATE */
1422 if (!rcvfil(filnam)) { /* Figure out local filename */
1423 errpkt((CHAR *)rf_err); /* Trouble */
1425 } else { /* Real file, OK to receive */
1427 debug(F111,"<rfile>F winlo 2",fspec,winlo);
1428 if (filcnt == 1) /* rcvfil set this to 1 for 1st file */
1429 crc16 = 0L; /* Clear file CRC */
1430 fnp = fspec; /* This is the full path */
1431 if (server && !ENABLED(en_cwd) || /* if DISABLE CD */
1432 !fackpath /* or F-ACK-PATH OFF */
1434 zstrip(fspec,&fnp); /* don't send back full path */
1436 encstr((CHAR *)fnp);
1440 ack1(data); /* Send it back in ACK */
1441 initattr(&iattr); /* Clear file attribute structure */
1443 if (window(wslotn) < 0) { /* Allocate negotiated window slots */
1444 errpkt((CHAR *)"Can't open window");
1448 if (ikdbopen) slotstate(what,
1449 server ? "SERVER" : "",
1454 BEGIN rattr; /* Now expect Attribute packets */
1458 <rgen,rfile>X { /* X-packet instead of file header */
1459 xflg = 1; /* Screen data */
1461 cancel = 0; /* Reset cancellation counter */
1462 ack(); /* Acknowledge the X-packet */
1463 initattr(&iattr); /* Initialize attribute structure */
1465 if (window(wslotn) < 0) { /* allocate negotiated window slots */
1466 errpkt((CHAR *)"Can't open window");
1470 if (query) { /* If this is the response to */
1471 qbufp = querybuf; /* a query that we sent, initialize */
1472 qbufn = 0; /* the response buffer */
1476 what = W_REMO; /* we're doing a REMOTE command */
1478 if (ikdbopen) slotstate(what,
1479 server ? "SERVER" : "",
1484 BEGIN rattr; /* Expect Attribute packets */
1487 <rattr>A { /* Attribute packet */
1488 if (gattr(rdatap,&iattr) == 0) { /* Read into attribute structure */
1490 ack1((CHAR *)iattr.reply.val); /* Reply with data */
1492 ack(); /* If OK, acknowledge */
1493 #endif /* CK_RESEND */
1494 } else { /* Otherwise */
1497 r = getreason(iattr.reply.val);
1498 ack1((CHAR *)iattr.reply.val); /* refuse to accept the file */
1499 xxscreen(SCR_ST,ST_REFU,0L,r); /* reason */
1501 if (tralog && !tlogfmt)
1502 doxlog(what,filnam,fsize,binary,1,r);
1507 <rattr>D { /* First data packet */
1508 debug(F100,"<rattr> D firstdata","",0);
1509 rc = rcv_firstdata();
1510 debug(F101,"rcv_firstdata rc","",rc);
1511 if (rc > -1) return(rc); /* (see below) */
1514 <rfile>B { /* EOT, no more files */
1515 ack(); /* Acknowledge the B packet */
1516 reot(); /* Do EOT things */
1518 /* If we were cd'd temporarily to another device or directory ... */
1521 x = zchdir((char *) savdir); /* ... restore previous directory */
1522 f_tmpdir = 0; /* and remember we did it. */
1523 debug(F111,"ckcpro.w B tmpdir restoring",savdir,x);
1525 #endif /* CK_TMPDIR */
1526 RESUME; /* and quit */
1529 <rdpkt>D { /* Got Data packet */
1530 debug(F101,"<rdpkt>D cxseen","",cxseen);
1531 debug(F101,"<rdpkt>D czseen","",czseen);
1532 if (cxseen || czseen || discard) { /* If file or group interruption */
1534 msg = czseen ? (CHAR *)"Z" : (CHAR *)"X";
1536 if (streaming) { /* Need to cancel */
1537 debug(F111,"<rdpkt>D streaming cancel",msg,cancel);
1538 if (cancel++ == 0) { /* Only do this once */
1539 ack1(msg); /* Put "X" or "Z" in ACK */
1540 } else if (czseen) {
1541 errpkt((CHAR *)"User canceled");
1547 #endif /* STREAMING */
1549 } else { /* No interruption */
1557 rc = (binary && !parity) ?
1558 bdecode(rdatap,putfil):
1559 decode(rdatap, qf ? puttrm : putfil, 1);
1561 rc = decode(rdatap, qf ? puttrm : putfil, 1);
1562 #endif /* CKTUNING */
1564 discard = (keep == 0 || (keep == SET_AUTO && binary != XYFT_T));
1565 errpkt((CHAR *)"Error writing data"); /* If failure, */
1567 } else /* Data written OK, send ACK */
1572 #endif /* STREAMING */
1577 <rattr>Z { /* EOF immediately after A-Packet. */
1578 rf_err = "Can't create file";
1580 if (discard) { /* Discarding a real file... */
1582 } else if (xflg) { /* If screen data */
1583 if (remfile) { /* redirected to file */
1584 if (rempipe) /* or pipe */
1585 x = openc(ZOFILE,remdest); /* Pipe: start command */
1587 x = opena(remdest,&iattr); /* File: open with attributes */
1588 } else { /* otherwise */
1589 x = opent(&iattr); /* "open" the screen */
1592 } else if (calibrate) { /* If calibration run */
1593 x = ckopenx(&iattr); /* do this */
1594 #endif /* CALIBRATE */
1595 } else { /* otherwise */
1596 x = opena(filnam,&iattr); /* open the file, with attributes */
1597 if (x == -17) { /* REGET skipped because same size */
1602 if (!x || reof(filnam, &iattr) < 0) { /* Close output file */
1603 errpkt((CHAR *) rf_err); /* If problem, send error msg */
1604 RESUME; /* and quit */
1605 } else { /* otherwise */
1607 xxscreen(SCR_ST,ST_SKIP,SKP_RES,"");
1608 ack(); /* acknowledge the EOF packet */
1609 BEGIN rfile; /* and await another file */
1613 <rdpkt>q { /* Ctrl-C or connection loss. */
1615 window(1); /* Set window size back to 1... */
1617 x = clsof(1); /* Close file */
1618 return(success = 0); /* Failed */
1621 <rdpkt>Z { /* End Of File (EOF) Packet */
1622 /* wslots = 1; */ /* (don't set) Window size back to 1 */
1623 #ifndef COHERENT /* Coherent compiler blows up on this switch() statement. */
1624 x = reof(filnam, &iattr); /* Handle the EOF packet */
1625 switch (x) { /* reof() sets the success flag */
1626 case -5: /* Handle problems */
1627 errpkt((CHAR *)"RENAME failed"); /* Fatal */
1631 errpkt((CHAR *)"MOVE failed"); /* Fatal */
1634 case -3: /* If problem, send error msg */
1635 errpkt((CHAR *)"Can't print file"); /* Fatal */
1639 errpkt((CHAR *)"Can't mail file"); /* Fatal */
1642 case 2: /* Not fatal */
1644 xxscreen(SCR_EM,0,0L,"Receiver can't delete temp file");
1648 if (x < 0) { /* Fatal */
1649 errpkt((CHAR *)"Can't close file");
1651 } else { /* Success */
1653 if (query) /* Query reponses generally */
1654 conoll(""); /* don't have line terminators */
1656 if (czseen) { /* Batch canceled? */
1657 if (cancel++ == 0) { /* If we haven't tried this yet */
1658 ack1((CHAR *)"Z"); /* Try it once */
1659 } else { /* Otherwise */
1660 errpkt((CHAR *)"User canceled"); /* quite with Error */
1664 ack(); /* Acknowledge the EOF packet */
1665 BEGIN rfile; /* and await another file */
1669 if (reof(filnam, &iattr) < 0) { /* Close the file */
1670 errpkt((CHAR *)"Error at end of file");
1672 } else { /* reof() sets success flag */
1676 #endif /* COHERENT */
1679 <ssinit>Y { /* ACK for Send-Init */
1680 spar(rdatap); /* set parameters from it */
1682 bctu = bctr; /* switch to agreed-upon block check */
1683 bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
1685 if ((sendmode == SM_RESEND) && (!atcapu || !rscapu)) { /* RESEND */
1686 errpkt((CHAR *) "RESEND capabilities not negotiated");
1689 #endif /* CK_RESEND */
1690 what = W_SEND; /* Remember we're sending */
1692 x = sfile(xflg); /* Send X or F header packet */
1693 cancel = 0; /* Reset cancellation counter */
1694 if (x) { /* If the packet was sent OK */
1695 if (!xflg && filcnt == 1) /* and it's a real file */
1696 crc16 = 0L; /* Clear the file CRC */
1697 resetc(); /* reset per-transaction counters */
1698 rtimer(); /* reset timers */
1701 #endif /* GFTIMER */
1702 streamon(); /* turn on streaming */
1704 if (ikdbopen) slotstate(what,
1705 (server ? "SERVER" : ""),
1710 BEGIN ssfile; /* and switch to receive-file state */
1711 } else { /* otherwise send error msg & quit */
1712 s = xflg ? "Can't execute command" : (char *)epktmsg;
1713 if (!*s) s = "Can't open file";
1719 #endif /* CK_RESEND */
1723 These states are necessary to handle the case where we get a server command
1724 packet (R, G, or C) reply with an S packet, but the client retransmits the
1725 command packet. The input() function doesn't catch this because the packet
1726 number is still zero.
1728 <ssinit>R { /* R packet was retransmitted. */
1729 xsinit(); /* Resend packet 0 */
1732 <ssinit>G { /* Same deal if G packet comes again */
1736 /* should probably add cases for O, W, V, H, J, ... */
1738 <ssinit>C { /* Same deal if C packet comes again */
1742 <ssfile>Y { /* ACK for F or X packet */
1743 srvptr = srvcmd; /* Point to string buffer */
1744 decode(rdatap,putsrv,0); /* Decode data field, if any */
1745 putsrv(NUL); /* Terminate with null */
1746 ffc = 0L; /* Reset file byte counter */
1747 debug(F101,"<ssfile>Y cxseen","",cxseen);
1748 if (*srvcmd) { /* If remote name was recorded */
1749 if (sendmode != SM_RESEND) {
1750 if (fdispla == XYFD_C || fdispla == XYFD_S)
1751 xxscreen(SCR_AN,0,0L,(char *)srvcmd);
1752 tlog(F110," remote name:",(char *) srvcmd,0L);
1753 makestr(&psrfspec,(char *)srvcmd);
1756 if (cxseen||czseen) { /* Interrupted? */
1757 debug(F101,"<ssfile>Y canceling","",0);
1758 x = clsif(); /* Close input file */
1759 sxeof(1); /* Send EOF(D) */
1760 BEGIN sseof; /* and switch to EOF state. */
1761 } else if (atcapu) { /* If attributes are to be used */
1762 if (sattr(xflg | stdinf, 1) < 0) { /* send them */
1763 errpkt((CHAR *)"Can't send attributes"); /* if problem, say so */
1764 RESUME; /* and quit */
1765 } else BEGIN ssattr; /* if ok, switch to attribute state */
1766 } else { /* Attributes not negotiated */
1767 if (window(wslotn) < 0) { /* Open window */
1768 errpkt((CHAR *)"Can't open window");
1770 } else if ((x = sdata()) == -2) { /* Send first data packet data */
1771 window(1); /* Connection lost, reset window */
1772 x = clsif(); /* Close input file */
1773 return(success = 0); /* Return failure */
1774 } else if (x == -9) { /* User interrupted */
1775 errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1776 window(1); /* Set window size back to 1... */
1777 timint = s_timint; /* Restore timeout */
1778 return(success = 0); /* Failed */
1779 } else if (x < 0) { /* EOF (empty file) or interrupted */
1780 window(1); /* put window size back to 1, */
1781 debug(F101,"<ssfile>Y cxseen","",cxseen);
1782 x = clsif(); /* If not ok, close input file, */
1783 if (x < 0) /* treating failure as interruption */
1784 cxseen = 1; /* Send EOF packet */
1785 seof(cxseen||czseen);
1786 BEGIN sseof; /* and switch to EOF state. */
1787 } else { /* First data sent OK */
1788 BEGIN ssdata; /* All ok, switch to send-data state */
1793 <ssattr>Y { /* Got ACK to A packet */
1794 ffc = 0L; /* Reset file byte counter */
1795 debug(F101,"<ssattr>Y cxseen","",cxseen);
1796 if (cxseen||czseen) { /* Interrupted? */
1797 debug(F101,"<sattr>Y canceling","",0);
1798 x = clsif(); /* Close input file */
1799 sxeof(1); /* Send EOF(D) */
1800 BEGIN sseof; /* and switch to EOF state. */
1801 } else if (rsattr(rdatap) < 0) { /* Was the file refused? */
1802 discard = 1; /* Set the discard flag */
1803 clsif(); /* Close the file */
1804 sxeof(1); /* send EOF with "discard" code */
1805 BEGIN sseof; /* switch to send-EOF state */
1806 } else if ((x = sattr(xflg | stdinf, 0)) < 0) { /* Send more? */
1807 errpkt((CHAR *)"Can't send attributes"); /* Trouble... */
1809 } else if (x == 0) { /* No more to send so now the data */
1810 if (window(wslotn) < 0) { /* Allocate negotiated window slots */
1811 errpkt((CHAR *)"Can't open window");
1814 if ((x = sdata()) == -2) { /* File accepted, send first data */
1815 window(1); /* Connection broken */
1816 x = clsif(); /* Close file */
1817 return(success = 0); /* Return failure */
1818 } else if (x == -9) { /* User interrupted */
1819 errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1820 window(1); /* Set window size back to 1... */
1821 timint = s_timint; /* Restore timeout */
1822 return(success = 0); /* Failed */
1823 } else if (x < 0) { /* If data was not sent */
1824 window(1); /* put window size back to 1, */
1825 debug(F101,"<ssattr>Y cxseen","",cxseen);
1826 if (clsif() < 0) /* Close input file */
1827 cxseen = 1; /* Send EOF packet */
1828 seof(cxseen||czseen);
1829 BEGIN sseof; /* and switch to EOF state. */
1831 BEGIN ssdata; /* All ok, switch to send-data state */
1836 <ssdata>q { /* Ctrl-C or connection loss. */
1837 window(1); /* Set window size back to 1... */
1838 cxseen = 1; /* To indicate interruption */
1839 x = clsif(); /* Close file */
1840 return(success = 0); /* Failed */
1843 <ssdata>Y { /* Got ACK to Data packet */
1844 canned(rdatap); /* Check if file transfer cancelled */
1845 debug(F111,"<ssdata>Y cxseen",rdatap,cxseen);
1846 debug(F111,"<ssdata>Y czseen",rdatap,czseen);
1847 if ((x = sdata()) == -2) { /* Try to send next data */
1848 window(1); /* Connection lost, reset window */
1849 x = clsif(); /* Close file */
1850 return(success = 0); /* Failed */
1851 } else if (x == -9) { /* User interrupted */
1852 errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1853 window(1); /* Set window size back to 1... */
1854 timint = s_timint; /* Restore original timeout */
1855 return(success = 0); /* Failed */
1856 } else if (x < 0) { /* EOF - finished sending data */
1857 debug(F101,"<ssdata>Y cxseen","",cxseen);
1858 window(1); /* Set window size back to 1... */
1859 if (clsif() < 0) /* Close input file */
1860 cxseen = 1; /* Send EOF packet */
1861 debug(F101,"<ssdata>Y CALLING SEOF()","",cxseen);
1862 seof(cxseen||czseen);
1863 BEGIN sseof; /* and enter send-eof state */
1865 /* NOTE: If x == 0 it means we're draining: see sdata()! */
1868 <sseof>Y { /* Got ACK to EOF */
1870 canned(rdatap); /* Check if file transfer cancelled */
1871 debug(F111,"<sseof>Y cxseen",rdatap,cxseen);
1872 debug(F111,"<sseof>Y czseen",rdatap,czseen);
1873 debug(F111,"<sseof>Y discard",rdatap,discard);
1876 success = (cxseen == 0 && czseen == 0); /* Transfer status... */
1877 debug(F101,"<sseof>Y success","",success);
1878 if (success && rejection > 0) /* If rejected, succeed if */
1879 if (rejection != '#' && /* reason was date */
1880 rejection != 1 && rejection != '?') /* or name; */
1881 success = 0; /* fail otherwise. */
1882 cxseen = 0; /* This goes back to zero. */
1883 if (success) { /* Only if transfer succeeded... */
1884 xxscreen(SCR_ST,ST_OK,0L,"");
1886 makestr(&sfspec,psfspec); /* Record filenames for WHERE */
1887 makestr(&srfspec,psrfspec);
1889 if (moving) { /* If MOVE'ing */
1890 x = zdelet(filnam); /* Try to delete the source file */
1894 tlog(F110," deleted",filnam,0);
1896 tlog(F110," delete failed:",ck_errstr(),0);
1900 } else if (snd_move) { /* Or move it */
1902 x = zrename(filnam,snd_move);
1906 tlog(F110," moved to ",snd_move,0);
1908 tlog(F110," move failed:",ck_errstr(),0);
1912 } else if (snd_rename) { /* Or rename it */
1913 char *s = snd_rename; /* Renaming string */
1915 int y; /* Pass it thru the evaluator */
1916 extern int cmd_quoting; /* for \v(filename) */
1917 if (cmd_quoting) { /* But only if cmd_quoting is on */
1920 zzstring(snd_rename,&s,&y);
1926 x = zrename(filnam,s);
1930 tlog(F110," renamed to",s,0);
1932 tlog(F110," rename failed:",ck_errstr(),0);
1938 #endif /* COMMENT */
1942 if (czseen) { /* Check group interruption flag */
1943 g = 0; /* No more files if interrupted */
1944 } else { /* Otherwise... */
1946 /* This code makes any open error fatal to a file-group transfer. */
1948 debug(F111,"<sseof>Y gnfile",filnam,g);
1949 if (g > 0) { /* Any more files to send? */
1950 if (sfile(xflg)) /* Yes, try to send next file header */
1951 BEGIN ssfile; /* if ok, enter send-file state */
1952 else { /* otherwise */
1953 s = xflg ? "Can't execute command" : (char *)epktmsg;
1954 if (!*s) s = "Can't open file";
1955 errpkt((CHAR *)s); /* send error message */
1956 RESUME; /* and quit */
1958 } else { /* No next file */
1959 tsecs = gtimer(); /* get statistics timers */
1961 fptsecs = gftimer();
1962 #endif /* GFTIMER */
1963 seot(); /* send EOT packet */
1964 BEGIN sseot; /* enter send-eot state */
1967 while (1) { /* Keep trying... */
1968 g = gnfile(); /* Get next file */
1969 debug(F111,"<sseof>Y gnfile",filnam,g);
1970 if (g == 0 && gnferror == 0) /* No more, stop trying */
1972 if (g > 0) { /* Have one */
1973 if (sfile(xflg)) { /* Try to open and send F packet */
1974 BEGIN ssfile; /* If OK, enter send-file state */
1975 break; /* and break out of loop. */
1977 } /* Otherwise keep trying to get one we can send... */
1981 debug(F101,"<sseof>Y no more files","",czseen);
1982 tsecs = gtimer(); /* Get statistics timers */
1984 fptsecs = gftimer();
1985 #endif /* GFTIMER */
1986 seot(); /* Send EOT packet */
1987 BEGIN sseot; /* Enter send-eot state */
1989 #endif /* COMMENT */
1992 <sseot>Y { /* Got ACK to EOT */
1993 debug(F101,"sseot justone","",justone);
1994 RESUME; /* All done, just quit */
1997 E { /* Got Error packet, in any state */
1999 window(1); /* Close window */
2000 timint = s_timint; /* Restore original timeout */
2001 if (*epktmsg) /* Message from Error packet */
2002 s = (char *)epktmsg;
2003 if (!*s) { /* If not there then maybe here */
2005 ckstrncpy((char *)epktmsg,(char *)rdatap,PKTMSGLEN);
2007 if (!*s) /* Hopefully we'll never see this. */
2008 s = "Unknown error";
2009 success = 0; /* For IF SUCCESS/FAIL. */
2010 debug(F101,"ckcpro.w justone at E pkt","",justone);
2012 success = 0; /* Transfer failed */
2013 xferstat = success; /* Remember transfer status */
2015 x = quiet; quiet = 1; /* Close files silently, */
2016 epktrcvd = 1; /* Prevent messages from clsof() */
2018 clsof(1); /* discarding any output file. */
2019 ermsg(s); /* Issue the message (calls screen). */
2020 quiet = x; /* Restore quiet state */
2022 tstats(); /* Get stats */
2024 If we are executing commands from a command file or macro, let the command
2025 file or macro decide whether to exit, based on SET { TAKE, MACRO } ERROR.
2032 fatal("Protocol error");
2033 xitsta |= (what & W_KERMIT); /* Save this for doexit(). */
2035 /* If we were cd'd temporarily to another device or directory ... */
2038 x = zchdir((char *) savdir); /* ... restore previous directory */
2039 f_tmpdir = 0; /* and remember we did it. */
2040 debug(F111,"ckcpro.w E tmpdir restored",savdir,x);
2042 #endif /* CK_TMPDIR */
2044 if (ikdbopen) slotstate(what,"ERROR", (char *)epktmsg, "");
2049 q { success = 0; QUIT; } /* Ctrl-C or connection loss. */
2051 . { /* Anything not accounted for above */
2052 errpkt((CHAR *)"Unexpected packet type"); /* Give error message */
2054 xitsta |= (what & W_KERMIT); /* Save this for doexit(). */
2055 RESUME; /* and quit */
2061 From here down to proto() are routines that were moved out of the state
2062 table switcher because the resulting switch() had become too large.
2063 To move the contents of a state-table case to a routine:
2064 1. Add a prototype to the list above the state table switcher.
2065 2. Make a routine with an appropriate name, returning int.
2066 3. Move the code into it.
2067 4. Put a call to the new routine in the former spot:
2068 rc = name_of_routine();
2069 if (rc > -1) return(rc);
2070 5. Add "return(-1);" after every RESUME, SERVE, or BEGIN macro and
2071 at the end if the code is open-ended.
2076 debug(F101,"rcv_firstdata","",dispos);
2078 if (discard) { /* if we're discarding the file */
2079 ack1((CHAR *)"X"); /* just ack the data like this. */
2080 cancel++; /* and count it */
2081 BEGIN rdpkt; /* and wait for more data packets. */
2083 } else { /* Not discarding. */
2084 rf_err = "Can't open file";
2085 if (xflg) { /* If screen data */
2086 if (remfile) { /* redirected to file */
2087 if (rempipe) /* or pipe */
2088 x = openc(ZOFILE,remdest); /* Pipe: start command */
2090 x = opena(remdest,&iattr); /* File: open with attributes */
2091 } else { /* otherwise */
2092 x = opent(&iattr); /* "open" the screen */
2094 } else { /* otherwise */
2096 if (calibrate) { /* If calibration run */
2097 x = ckopenx(&iattr); /* open nothing */
2099 if (streaming) /* Streaming */
2100 fastack(); /* ACK without ACKing. */
2102 #endif /* STREAMING */
2103 ack(); /* Send real ACK */
2104 BEGIN rdpkt; /* Proceed to next state */
2107 #endif /* CALIBRATE */
2110 In UNIX we can pipe the file data into the mail program, which is to be
2111 preferred to writing it out to a temp file and then mailing it afterwards.
2112 This depends rather heavily on all UNIXes having a mail command that
2113 accepts '-s "subject"' on the command line. MAILCMD (e.g. mail, Mail, mailx)
2114 is defined in ckufio.c.
2116 if (dispos == 'M') { /* Mail... */
2120 extern char *MAILCMD;
2121 s = iattr.disp.val + 1;
2122 n = (int)strlen(MAILCMD) + /* Mail command */
2123 (int)strlen(s) + /* address */
2124 (int)strlen(ofilnam) + 32; /* subject */
2125 if (tmp = (char *)malloc(n)) {
2127 MAILCMD," -s \"",ofilnam,"\" ",s,
2128 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
2129 debug(F111,"rcv_firsdata mail",tmp,(int)strlen(tmp));
2130 x = openc(ZOFILE,(char *)tmp);
2134 } else if (dispos == 'P') { /* Ditto for print */
2137 extern char *PRINTCMD;
2138 n = (int)strlen(PRINTCMD) + (int)strlen(iattr.disp.val+1) + 4;
2139 if (tmp = (char *)malloc(n)) {
2140 sprintf(tmp, /* safe (prechecked) */
2141 "%s %s", PRINTCMD, iattr.disp.val + 1);
2142 x = openc(ZOFILE,(char *)tmp);
2148 x = opena(filnam,&iattr); /* open the file, with attributes */
2150 if (x) { /* If file was opened ok */
2159 rc = (binary && !parity) ?
2160 bdecode(rdatap,putfil):
2161 decode(rdatap, qf ? puttrm : putfil, 1);
2163 rc = decode(rdatap, qf ? puttrm : putfil, 1);
2164 #endif /* CKTUNING */
2166 errpkt((CHAR *)"Error writing data");
2171 if (streaming) /* Streaming was negotiated */
2172 fastack(); /* ACK without ACKing. */
2174 #endif /* STREAMING */
2175 ack(); /* acknowledge it */
2176 BEGIN rdpkt; /* and switch to receive-data state */
2178 } else { /* otherwise */
2179 errpkt((CHAR *) rf_err); /* send error packet */
2180 RESUME; /* and quit. */
2190 debug(F111,"rcv_shortreply",rdatap,ipktlen);
2191 if (ipktack[0] && !strncmp(ipktack,(char *)rdatap,ipktlen)) {
2192 /* No it's the ACK to the I packet again */
2193 x = scmd(vcmd,(CHAR *)cmarg); /* So send the REMOTE command again */
2194 /* Maybe this should be resend() */
2195 debug(F110,"IPKTZEROHACK",ipktack,x);
2197 errpkt((CHAR *)srimsg);
2203 #endif /* PKTZEROHACK */
2207 if (query) { /* If to query, */
2208 qbufp = querybuf; /* initialize query response buffer */
2214 if (remfile) { /* Response redirected to file */
2215 rf_err = "Can't open file";
2216 if (rempipe) /* or pipe */
2219 zxcmd(ZOFILE,remdest) /* Pipe: Start command */
2225 x = opena(remdest,&iattr); /* File: Open with attributes */
2226 debug(F111,"rcv_shortreply remfile",remdest,x);
2228 x = opent(&iattr); /* "open" the screen */
2230 if (x) { /* If file was opened ok */
2233 (query || !remfile) ? puttrm :
2237 zputfil, 1) < 0) { /* Note: zputfil, not putfil. */
2238 errpkt((CHAR *)"Error writing data");
2242 if (rdatap) /* If we had data */
2243 if (*rdatap) /* add a line terminator */
2244 if (remfile) { /* to file */
2246 } else { /* or to screen. */
2248 if (!query || !xcmdsrc)
2250 if (!(quiet && rcdactive))
2253 if (bye_active && network) { /* I sent BYE or REMOTE LOGOUT */
2254 msleep(500); /* command and got the ACK... */
2259 if (!epktsent && !epktrcvd) /* If no error packet... */
2260 success = 1; /* success. */
2264 } else { /* File not opened OK */
2265 errpkt((CHAR *) rf_err); /* send error message */
2266 RESUME; /* and quit. */
2269 #endif /* NOSERVER */
2272 #endif /* PKTZEROHACK */
2273 debug(F101,"rcv_shortreply fallthru","",success);
2284 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2285 cksyslog(SYSLG_PR, 1, "server", "REMOTE QUERY", (char *)srvcmd);
2286 #endif /* CKSYSLOG */
2288 if (ikdbopen) slotstate(what,"REMOTE QUERY", (char *)(srvcmd+2), "");
2290 c = *(srvcmd+2); /* Q = Query, S = Set */
2291 if (c == 'Q') { /* Query */
2292 if (!ENABLED(en_que)) { /* Security */
2293 errpkt((CHAR *)"REMOTE QUERY disabled");
2296 } else { /* Query allowed */
2298 qbufp = querybuf; /* Wipe out old stuff */
2301 p = (char *) srvcmd + 3; /* Pointer for making wrapper */
2302 n = strlen((char *)srvcmd); /* Position of end */
2303 c = *(srvcmd+4); /* Which type of variable */
2305 if (*(srvcmd+6) == CMDQ) { /* Starts with command quote? */
2306 p = (char *) srvcmd + 6; /* Take it literally */
2307 if (*p == CMDQ) p++;
2308 } else { /* They played by the rules */
2309 if (c == 'K') { /* Kermit variable */
2311 k = (int) strlen(p);
2312 if (k > 0 && p[k-1] == ')') {
2313 p = (char *)(srvcmd + 4);
2315 *(srvcmd+5) = 'f'; /* Function, so make it \f...() */
2317 *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
2318 *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */
2319 *(srvcmd+5) = '('; /* around variable name */
2321 *(srvcmd+n+1) = NUL;
2324 *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
2325 *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */
2326 *(srvcmd+5) = '('; /* around variable name */
2328 *(srvcmd+n+1) = NUL;
2329 if (c == 'S') { /* System variable */
2330 *(srvcmd+4) = '$'; /* so it's \$(...) */
2331 } else if (c == 'G') { /* Non-\ Global variable */
2332 *(srvcmd+4) = 'm'; /* so wrap it in \m(...) */
2335 } /* Now evaluate it */
2336 n = QBUFL; /* Max length */
2337 q = querybuf; /* Where to put it */
2338 if (zzstring(p,&q,&n) < 0) {
2339 errpkt((n > 0) ? (CHAR *)"Can't get value"
2340 : (CHAR *)"Value too long"
2345 if (encstr((CHAR *)querybuf) > -1) { /* Encode it */
2346 ack1(data); /* If it fits, send it back in ACK */
2350 } else if (sndstring(querybuf)) { /* Long form response */
2353 } else { /* sndhlp() fails */
2354 errpkt((CHAR *)"Can't send value");
2360 } else if (c == 'S') { /* Set (assign) */
2361 if (!ENABLED(en_asg)) { /* Security */
2362 errpkt((CHAR *)"REMOTE ASSIGN disabled");
2367 n = xunchar(*(srvcmd+3)); /* Length of name */
2368 n = 3 + n + 1; /* Position of length of value */
2369 *(srvcmd+n) = NUL; /* Don't need it */
2370 if (addmac((char *)(srvcmd+4),(char *)(srvcmd+n+1)) < 0)
2371 errpkt((CHAR *)"REMOTE ASSIGN failed");
2380 errpkt((CHAR *)"Badly formed server command");
2385 errpkt((CHAR *)"Variable query/set not available");
2389 #endif /* NOSERVER */
2396 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2397 cksyslog(SYSLG_PR, 1, "server", "REMOTE COPY", (char *)srvcmd);
2398 #endif /* CKSYSLOG */
2400 if (!ENABLED(en_cpy)) {
2401 errpkt((CHAR *)"REMOTE COPY disabled");
2405 char *str1, *str2, f1[256], f2[256];
2407 len1 = xunchar(srvcmd[1]); /* Separate the parameters */
2408 len2 = xunchar(srvcmd[2+len1]);
2409 strncpy(f1,(char *)(srvcmd+2),len1);
2411 strncpy(f2,(char *)(srvcmd+3+len1),len2);
2414 if (ikdbopen) slotstate(what,"REMOTE COPY", f1, f2);
2416 if (!ENABLED(en_cwd)) { /* If CWD is disabled */
2417 zstrip(f1,&str1); /* and they included a pathname, */
2419 if (strcmp(f1,str1) || strcmp(f2,str2)) { /* Refuse. */
2420 errpkt((CHAR *)"Access denied");
2421 RESUME; /* Remember, this is not a goto! */
2425 if (state == generic) { /* It's OK to go ahead. */
2426 if (zcopy(f1,f2)) { /* Try */
2427 errpkt((CHAR *)"Can't copy file"); /* give error message */
2432 RESUME; /* wait for next server command */
2437 #else /* no ZCOPY */
2438 errpkt((CHAR *)"REMOTE COPY not available"); /* give error message */
2439 RESUME; /* wait for next server command */
2442 #endif /* NOSERVER */
2449 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2450 cksyslog(SYSLG_PR, 1, "server", "REMOTE RENAME", (char *)srvcmd);
2451 #endif /* CKSYSLOG */
2453 if (!ENABLED(en_ren)) {
2454 errpkt((CHAR *)"REMOTE RENAME disabled");
2457 } else { /* RENAME is enabled */
2458 char *str1, *str2, f1[256], f2[256];
2460 len1 = xunchar(srvcmd[1]); /* Separate the parameters */
2461 len2 = xunchar(srvcmd[2+len1]);
2462 strncpy(f1,(char *)(srvcmd+2),len1);
2464 strncpy(f2,(char *)(srvcmd+3+len1),len2);
2466 len2 = xunchar(srvcmd[2+len1]);
2467 strncpy(f1,(char *)(srvcmd+2),len1);
2469 strncpy(f2,(char *)(srvcmd+3+len1),len2);
2472 if (ikdbopen) slotstate(what,"REMOTE RENAME", f1, f2);
2474 if (!ENABLED(en_cwd)) { /* If CWD is disabled */
2475 zstrip(f1,&str1); /* and they included a pathname, */
2477 if ( strcmp(f1,str1) || strcmp(f2,str2) ) { /* refuse. */
2478 errpkt((CHAR *)"Access denied");
2479 RESUME; /* Remember, this is not a goto! */
2483 if (state == generic) { /* It's OK to go ahead. */
2484 if (zrename(f1,f2)) { /* Try */
2485 errpkt((CHAR *)"Can't rename file"); /* Give error msg */
2490 RESUME; /* Wait for next server command */
2495 #else /* no ZRENAME */
2496 /* Give error message */
2497 errpkt((CHAR *)"REMOTE RENAME not available");
2498 RESUME; /* Wait for next server command */
2500 #endif /* ZRENAME */
2501 #endif /* NOSERVER */
2507 char f1[LOGINLEN+1], f2[LOGINLEN+1], f3[LOGINLEN+1];
2511 debug(F101,"REMOTE LOGIN x_login","",x_login);
2512 debug(F101,"REMOTE LOGIN x_logged","",x_logged);
2514 f1[0] = NUL; f2[0] = NUL; f3[0] = NUL;
2516 if (srvcmd[1]) /* First length field */
2517 len = xunchar(srvcmd[1]); /* Separate the parameters */
2519 if (x_login) { /* Login required */
2520 if (x_logged) { /* And already logged in */
2521 if (len > 0) { /* Logging in again */
2522 errpkt((CHAR *)"Already logged in.");
2523 } else { /* Logging out */
2524 debug(F101,"REMOTE LOGOUT","",x_logged);
2526 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2527 cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGOUT", NULL);
2528 #endif /* CKSYSLOG */
2530 if (ikdbopen) slotstate(what,"REMOTE LOGOUT", "", "");
2532 tlog(F110,"Logged out",x_user,0);
2533 ack1((CHAR *)"Logged out");
2542 #endif /* CK_LOGIN */
2544 } else { /* Not logged in yet */
2545 debug(F101,"REMOTE LOGIN len","",len);
2546 if (len > 0) { /* Have username */
2548 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2549 cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGIN", NULL);
2550 #endif /* CKSYSLOG */
2551 if (len > LOGINLEN) {
2552 errpkt((CHAR *)"Username too long");
2554 p = srvcmd + 2; /* Point to it */
2555 for (i = 0; i < len; i++) /* Copy it */
2557 f1[len] = NUL; /* Terminate it */
2558 p += len; /* Point to next length field */
2559 if (*p) { /* If we have one */
2560 len = xunchar(*p++); /* decode it */
2561 if (len > 0 && len <= LOGINLEN) {
2562 for (i = 0; i < len; i++) /* Same deal for password */
2565 p += len; /* And account */
2567 len = xunchar(*p++);
2568 if (len > 0 && len <= LOGINLEN) {
2569 for (i = 0; i < len; i++)
2570 f3[i] = p[i]; /* Set but never used */
2571 f3[len] = NUL; /* (because account not used) */
2576 debug(F101,"REMOTE LOGIN 1","",x_logged);
2579 if (inserver) { /* Log in to system for real */
2580 x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
2581 debug(F101,"REMOTE LOGIN 2","",x_logged);
2582 if (x_logged) { /* Count attempts */
2590 #endif /* CK_LOGIN */
2592 if (x_user && x_passwd) { /* User and password must match */
2593 if (!strcmp(x_user,f1)) /* SET SERVER LOGIN */
2594 if (!strcmp(x_passwd,f2))
2596 debug(F101,"REMOTE LOGIN 3","",x_logged);
2597 } else if (x_user) { /* Only username given, no password */
2598 if (!strcmp(x_user,f1)) /* so only username must match */
2600 debug(F101,"REMOTE LOGIN 4","",x_logged);
2604 x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
2605 debug(F101,"REMOTE LOGIN 5","",x_logged);
2607 #endif /* CK_LOGIN */
2608 if (x_logged) { /* Logged in? */
2609 tlog(F110,"Logged in", x_user, 0);
2611 ack1((CHAR *)"Logged in as guest - restrictions apply");
2613 ack1((CHAR *)"Logged in");
2616 tlog(F110,"Login failed", f1, 0);
2617 errpkt((CHAR *)"Access denied.");
2620 if (inserver && logtries > 2)
2622 #endif /* CK_LOGIN */
2625 } else { /* LOGOUT */
2626 errpkt((CHAR *)"Logout ignored");
2629 } else { /* Login not required */
2631 errpkt((CHAR *)"Login ignored.");
2633 errpkt((CHAR *)"Logout ignored.");
2635 #endif /* NOSERVER */
2642 /* K95 does this its own way */
2646 printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", srvidl);
2647 doexit(GOOD_EXIT,xitsta);
2651 printf("\r\nSERVER IDLE TIMEOUT: %d sec\r\n", srvidl);
2652 xitsta |= (what & W_KERMIT);
2656 else if (fatalio) { /* Connection lost */
2658 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2659 cksyslog(SYSLG_PR, 1, "server", "Connection lost", NULL);
2660 #endif /* CKSYSLOG */
2662 if (ikdbopen) slotstate(what,"SERVER DISCONNECT",(char *)srvcmd, "");
2666 } else if (interrupted) { /* Interrupted by hand */
2667 if (!ENABLED(en_fin)) {
2668 errpkt((CHAR *)"QUIT disabled");
2672 if (what == W_SEND || what == W_RECV || what == W_REMO) {
2675 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2676 cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
2677 #endif /* CKSYSLOG */
2678 } else if (what == W_NOTHING && filcnt == 0) {
2680 } /* Otherwise leave success alone */
2681 xitsta |= (what & W_KERMIT);
2684 } else { /* Shouldn't happen */
2685 debug(F100,"SERVER (top) GOT UNEXPECTED 'q'","",0);
2688 #endif /* NOSERVER */
2696 if (/* state == serve && */ x_login && !x_logged) {
2697 errpkt((CHAR *)"Login required");
2700 #endif /* NOSERVER */
2701 if (state == serve && !ENABLED(en_sen)) { /* Not in server mode */
2702 errpkt((CHAR *)"SEND disabled"); /* when SEND is disabled. */
2705 } else { /* OK to go ahead. */
2707 if (dldir && !f_tmpdir) { /* If they have a download directory */
2708 debug(F110,"receive download dir",dldir,0);
2709 if (s = zgtdir()) { /* Get current directory */
2710 debug(F110,"receive current dir",s,0);
2711 if (zchdir(dldir)) { /* Change to download directory */
2712 debug(F100,"receive zchdir ok","",0);
2713 ckstrncpy(savdir,s,TMPDIRLEN);
2714 f_tmpdir = 1; /* Remember that we did this */
2716 debug(F100,"receive zchdir failed","",0);
2719 #endif /* CK_TMPDIR */
2720 nakstate = 1; /* Can send NAKs from here. */
2721 rinit(rdatap); /* Set parameters */
2722 bctu = bctr; /* Switch to agreed-upon block check */
2723 bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
2724 what = W_RECV; /* Remember we're receiving */
2726 resetc(); /* Reset counters */
2727 rtimer(); /* Reset timer */
2730 #endif /* GFTIMER */
2732 BEGIN rfile; /* Go into receive-file state */
2738 /* END OF ROUTINES MOVED OUT OF STATE MACHINE */
2741 /* P R O T O -- Protocol entry function */
2743 static int is_tn = 0; /* It's a Telnet connection */
2746 int f_ctlp = 0; /* Control-character prefix table */
2749 #endif /* COMMENT */
2750 #endif /* CK_SPEED */
2753 This is simply a wrapper for the real protocol function just below,
2754 that saves any items that might be changed automatically by protocol
2755 negotiations and then restores them upon exit from protocol mode.
2759 extern int b_save, f_save, c_save, ss_save, slostart, reliable, urclear;
2761 extern int fcharset, fcs_save, tcharset, tcs_save;
2762 #endif /* NOCSETS */
2765 extern int pipesend;
2766 #endif /* PIPESEND */
2769 extern int cursorena[], cursor_save, term_io;
2771 extern int display_demo;
2774 #endif /* NOLOCAL */
2776 int _u_bin=0, _me_bin = 0;
2778 int /* _u_start=0, */ _me_start = 0;
2779 #endif /* IKS_OPTION */
2784 #endif /* PATTERNS */
2789 #endif /* PATTERNS */
2790 scan_save = filepeek;
2795 if (isguest) { /* If user is anonymous */
2796 en_pri = 0; /* disable printing */
2797 en_mai = 0; /* and disable email */
2798 en_del = 0; /* and file deletion */
2800 #endif /* CK_LOGIN */
2804 cursor_save = cursorena[vmode];
2805 cursorena[vmode] = 0;
2806 term_io_save = term_io;
2809 #endif /* NOLOCAL */
2810 b_save = binary; /* SET FILE TYPE */
2811 f_save = fncnv; /* SET FILE NAMES */
2818 fcs_save = fcharset;
2819 tcs_save = tcharset;
2820 #endif /* NOCSETS */
2823 /* Don't do this because then user can never find out what happened. */
2825 for (i = 0; i < 256; i++)
2826 s_ctlp[i] = ctlp[i];
2828 #endif /* CK_SPEED */
2829 #endif /* COMMENT */
2830 if (reliable == SET_ON)
2832 is_tn = (!local && sstelnet)
2834 || (local && network && ttnproto == NP_TELNET)
2839 if (tn_b_xfer && !(sstelnet || inserver)) {
2840 /* Save the current state of Telnet Binary */
2841 _u_bin = TELOPT_U(TELOPT_BINARY);
2842 _me_bin = TELOPT_ME(TELOPT_BINARY);
2844 /* If either direction is not Binary attempt to negotiate it */
2845 if (!_u_bin && TELOPT_U_MODE(TELOPT_BINARY) != TN_NG_RF) {
2846 tn_sopt(DO,TELOPT_BINARY);
2847 TELOPT_UNANSWERED_DO(TELOPT_BINARY) = 1;
2849 if (!_me_bin && TELOPT_ME_MODE(TELOPT_BINARY) != TN_NG_RF) {
2850 tn_sopt(WILL,TELOPT_BINARY);
2851 TELOPT_UNANSWERED_WILL(TELOPT_BINARY) = 1;
2853 if (!(_me_bin && _u_bin))
2854 tn_wait("proto set binary mode");
2858 if (protocol != PROTO_K) { /* Non-Kermit protocol selected */
2859 if (TELOPT_U(TELOPT_KERMIT) &&
2860 TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2861 iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
2864 if (TELOPT_ME(TELOPT_KERMIT) &&
2865 TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2866 tn_siks(KERMIT_STOP); /* I'm not servering */
2867 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2872 if (sstate == 'x' || sstate == 'v') { /* Responding to a request */
2873 if (!inserver && TELOPT_U(TELOPT_KERMIT) &&
2874 TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2875 iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
2878 if (TELOPT_ME(TELOPT_KERMIT) &&
2879 !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2880 tn_siks(KERMIT_START); /* Send Kermit-Server Start */
2881 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1;
2883 } else { /* Initiating a request */
2884 if (TELOPT_ME(TELOPT_KERMIT) &&
2885 TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2886 tn_siks(KERMIT_STOP); /* I'm not servering */
2887 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2890 if (TELOPT_U(TELOPT_KERMIT) &&
2891 !TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2892 /* Send Req-Server-Start */
2893 if (!iks_wait(KERMIT_REQ_START,0)) {
2894 if (sstate != 's') {
2895 success = 0; /* Other Kermit refused to serve */
2897 printf("A Kermit Server is not available\r\n");
2898 debug(F110,"proto()",
2899 "A Kermit Server is not available",0);
2900 tlog(F110,"IKS client/server failure",
2901 "A Kermit Server is not available",0);
2907 #endif /* IKS_OPTION */
2908 #ifdef CK_ENCRYPTION
2909 if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
2912 #endif /* CK_ENCRYPTION */
2916 if (!xfrint) connoi();
2917 xxproto(); /* Call the real protocol function */
2921 #endif /* IKS_OPTION */
2922 xferstat = success; /* Remember transfer status */
2926 #ifdef CK_ENCRYPTION
2927 if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
2930 #endif /* CK_ENCRYPTION */
2932 if (TELOPT_ME(TELOPT_KERMIT) &&
2933 TELOPT_SB(TELOPT_KERMIT).kermit.me_start && !_me_start) {
2934 tn_siks(KERMIT_STOP); /* Server is stopped */
2935 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2937 #endif /* IKS_OPTION */
2938 if (is_tn && tn_b_xfer && !(sstelnet || inserver)) {
2939 /* if we negotiated Binary mode try to reset it */
2941 /* Check to see if the state changed during the transfer */
2942 if (TELOPT_U(TELOPT_BINARY)) {
2943 tn_sopt(DONT,TELOPT_BINARY);
2944 TELOPT_UNANSWERED_DONT(TELOPT_BINARY) = 1;
2946 _u_bin = 1; /* So we don't call tn_wait() */
2949 /* Check to see if the state changed during the transfer */
2950 if (TELOPT_ME(TELOPT_BINARY)) {
2951 tn_sopt(WONT,TELOPT_BINARY);
2952 TELOPT_UNANSWERED_WONT(TELOPT_BINARY) = 1;
2954 _me_bin = 1; /* So we don't call tn_wait() */
2956 if (!(_me_bin && _u_bin))
2957 tn_wait("proto reset binary mode");
2963 #endif /* PATTERNS */
2964 filepeek = scan_save;
2969 #endif /* STREAMING */
2972 for (i = 0; i < 256; i++)
2973 ctlp[i] = s_ctlp[i];
2975 #endif /* CK_SPEED */
2976 #endif /* COMMENT */
2979 xitsta |= (what & W_KERMIT);
2980 tlog(F110," failed:",(char *)epktmsg,0);
2982 debug(F111,"proto xferstat",epktmsg,xferstat);
2984 if (s_timint > -1) { /* Because of REMOTE SET */
2990 if (c_save > -1) { /* Because of REMOTE SET */
2997 pipesend = 0; /* Next time might not be pipesend */
2998 #endif /* PIPESEND */
3001 cursorena[vmode] = cursor_save;
3002 term_io = term_io_save;
3005 #endif /* NOLOCAL */
3014 _PROTOTYP( int pxyz, (int) );
3015 #endif /* XYZ_INTERNAL */
3018 char xss[2]; /* String representation of sstate */
3023 debug(F101,"xxproto entry justone","",justone);
3026 retrieve = 0; /* Reset these ... */
3030 if (local && ttchk() < 0) { /* Giving BYE or FIN */
3031 if (bye_active) { /* but there is no connection */
3036 /* Ditto for any REMOTE command */
3037 if (sstate == 'g' && cmarg ) {
3038 if (*cmarg == 'L' || *cmarg == 'F' || *cmarg == 'X')
3041 printf("?No connection\r\n");
3046 /* Set up the communication line for file transfer. */
3047 /* NOTE: All of the xxscreen() calls prior to the wart() invocation */
3048 /* could just as easily be printf's or, for that matter, hints. */
3050 if (local && (speed < 0L) && (network == 0)) {
3051 xxscreen(SCR_EM,0,0L,"Sorry, you must 'set speed' first");
3055 if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {
3056 debug(F111,"failed: proto ttopen local",ttname,local);
3057 xxscreen(SCR_EM,0,0L,"Can't open line");
3060 if (x > -1) local = x;
3061 debug(F111,"proto ttopen local",ttname,local);
3063 lx = (local && !network) ? speed : -1;
3067 ctlp[(unsigned)255] = ctlp[CR] = 1;
3068 if (parity == 'e' || parity == 'm') ctlp[127] = 1;
3069 if (flow == FLO_XONX) { /* Also watch out for Xon/Xoff */
3070 ctlp[17] = ctlp[19] = 1;
3071 ctlp[17+128] = ctlp[19+128] = 1;
3074 #endif /* CK_SPEED */
3075 #endif /* NETCONN */
3076 if (ttpkt(lx,flow,parity) < 0) { /* Put line in packet mode, */
3077 xxscreen(SCR_EM,0,0L,"Can't condition line");
3080 if (local && !network && carrier != CAR_OFF) {
3081 int x; /* Serial connection */
3082 x = ttgmdm(); /* with carrier checking */
3084 if (!(x & BM_DCD)) {
3085 debug(F101,"proto ttgmdm","",0);
3086 xxscreen(SCR_EM,0,0L,"Carrier required but not detected");
3091 /* Send remote side's "receive" or "server" startup string, if any */
3092 if (local && ckindex((char *)xss,"srgcjhk",0,0,1)) {
3096 /* Don't send auto-blah string if we know other side is serving */
3097 !TELOPT_U(TELOPT_KERMIT) ||
3098 !TELOPT_SB(TELOPT_KERMIT).kermit.u_start
3101 #endif /* IKS_OPTION */
3103 if (sstate == 's') { /* Sending file(s) */
3104 s = binary ? ptab[protocol].h_b_init : ptab[protocol].h_t_init;
3105 } else if (protocol == PROTO_K) { /* Command for server */
3106 s = ptab[protocol].h_x_init;
3110 #ifndef UNPREFIXZERO
3111 if (protocol == PROTO_K) /* Because of C-strings... */
3113 #endif /* UNPREFIXZERO */
3114 #endif /* CK_SPEED */
3115 if (s) if (*s) { /* If we have a command to send... */
3117 int tmpbufsiz = 356;
3118 int stuff = -1, stuff2 = -1, len = 0;
3120 if (sstate == 's') { /* Sending file(s) */
3122 if (protocol == PROTO_X) {
3124 s2 = cmarg2[0] ? cmarg2 : cmarg;
3125 if ((int)strlen(s) + (int)strlen(s2) + 4 < 356)
3126 sprintf(tmpbuf, s, s2);
3131 ckmakmsg(tmpbuf, 356, s, NULL, NULL, NULL);
3135 } else { /* Command for server */
3136 ckstrncpy(tmpbuf,s,356);
3138 ckstrncat(tmpbuf, "\015",sizeof(tmpbuf));
3139 if (tnlm) /* TERMINAL NEWLINE ON */
3140 stuff = LF; /* Stuff LF */
3142 /* TELNET NEWLINE MODE */
3144 switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) {
3160 if (network && ttnproto == NP_RLOGIN) {
3161 switch (tn_b_nlm) { /* Always BINARY */
3174 #endif /* RLOGCODE */
3175 #endif /* TCPSOCKET */
3176 #endif /* NETCONN */
3178 len = strlen(tmpbuf);
3179 if (stuff >= 0 && len < tmpbufsiz - 1) {
3180 tmpbuf[len++] = stuff;
3181 if (stuff2 >= 0 && len < tmpbufsiz - 1)
3182 tmpbuf[len++] = stuff2;
3185 ttol((CHAR *)tmpbuf,len);
3186 if (protocol == PROTO_K) /* Give remote Kermit time to start */
3192 if (protocol != PROTO_K) { /* Non-Kermit protocol selected */
3194 int tmpbufsiz = 356;
3198 if (sstate == 'v') { /* If receiving and... */
3199 if (dldir && !f_tmpdir) { /* if they have a download directory */
3200 if (s = zgtdir()) { /* Get current directory */
3201 if (zchdir(dldir)) { /* Change to download directory */
3202 ckstrncpy(savdir,s,TMPDIRLEN);
3203 f_tmpdir = 1; /* Remember that we did this */
3208 #endif /* CK_TMPDIR */
3210 #ifdef XYZ_INTERNAL /* Internal */
3211 success = !pxyz(sstate);
3213 #ifdef CK_REDIR /* External */
3215 case 's': /* 'Tis better to SEND... */
3216 s = binary ? ptab[protocol].p_b_scmd : ptab[protocol].p_t_scmd;
3218 case 'v': /* ... than RECEIVE */
3219 s = binary ? ptab[protocol].p_b_rcmd : ptab[protocol].p_t_rcmd;
3224 if (sstate == 's') {
3225 if ((int)strlen(s) + (int)strlen(fspec) < tmpbufsiz) {
3226 sprintf(tmpbuf,s,fspec); /* safe (prechecked) */
3227 tlog(F110,"Sending",fspec,0L);
3230 if ((int)strlen(s) + (int)strlen(cmarg2) < tmpbufsiz) {
3231 sprintf(tmpbuf,s,cmarg2); /* safe (prechecked) */
3232 tlog(F110,"Receiving",cmarg2,0L);
3235 tlog(F110," via external protocol:",tmpbuf,0);
3236 debug(F110,"ckcpro ttruncmd",tmpbuf,0);
3237 success = ttruncmd(tmpbuf);
3238 tlog(F110," status:",success ? "OK" : "FAILED", 0);
3240 printf("?Sorry, no external protocol defined for %s\r\n",
3241 ptab[protocol].p_name
3246 "Sorry, only Kermit protocol is supported in this version of Kermit\n"
3248 #endif /* CK_REDIR */
3249 #endif /* XYZ_INTERNAL */
3259 connoi(); /* No console interrupts if remote */
3263 if (sstate == 'x') { /* If entering server mode, */
3264 extern int howcalled;
3265 server = 1; /* set flag, */
3266 debug(F101,"server backgrd","",backgrd);
3267 debug(F101,"server quiet","",quiet);
3268 debug(F100,"SHOULD NOT SEE THIS IF IN BACKGROUND!","",0);
3269 if (howcalled == I_AM_SSHSUB) { /* and issue appropriate message. */
3270 ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
3271 } else if (!local) {
3272 if (!quiet && !backgrd
3274 && !TELOPT_ME(TELOPT_KERMIT) /* User was told by negotiation */
3275 #endif /* IKS_OPTION */
3278 conoll("KERMIT READY TO SERVE...");
3281 conol("Entering server mode on ");
3283 conoll("Type Ctrl-C to quit.");
3284 if (srvdis) intmsg(-1L);
3287 if (network && tcpsrfd > 0)
3288 ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
3289 #endif /* NOLISTEN */
3290 #endif /* TCPSOCKET */
3295 if (!quiet && !backgrd) /* So message doesn't overwrite prompt */
3297 if (local) conres(); /* So Ctrl-C will work */
3300 If in remote mode, not shushed, not in background, and at top command level,
3301 issue a helpful message telling what to do...
3303 if (!local && !quiet && !backgrd) {
3304 if (sstate == 'v') {
3305 conoll("Return to your local Kermit and give a SEND command.");
3307 conoll("KERMIT READY TO RECEIVE...");
3308 } else if (sstate == 's') {
3309 conoll("Return to your local Kermit and give a RECEIVE command.");
3311 conoll("KERMIT READY TO SEND...");
3312 } else if ( sstate == 'g' || sstate == 'r' || sstate == 'h' ||
3313 sstate == 'j' || sstate == 'c' ) {
3314 conoll("Return to your local Kermit and give a SERVER command.");
3316 conoll((sstate == 'r' || sstate == 'j' || sstate == 'h') ?
3317 "KERMIT READY TO GET..." :
3318 "KERMIT READY TO SEND SERVER COMMAND...");
3322 if (!local) sleep(1);
3323 #endif /* COMMENT */
3325 The 'wart()' function is generated by the wart program. It gets a
3326 character from the input() routine and then based on that character and
3327 the current state, selects the appropriate action, according to the state
3328 table above, which is transformed by the wart program into a big case
3329 statement. The function is active for one transaction.
3331 rtimer(); /* Reset elapsed-time timer */
3334 #endif /* GFTIMER */
3335 resetc(); /* & other per-transaction counters. */
3337 debug(F101,"proto calling wart, justone","",justone);
3339 wart(); /* Enter the state table switcher. */
3341 Note: the following is necessary in case we have just done a remote-mode
3342 file transfer, in which case the controlling terminal modes have been
3343 changed by ttpkt(). In particular, special characters like Ctrl-C and
3344 Ctrl-\ might have been turned off (see ttpkt). So this call to ttres() is
3345 essential. IMPORTANT: restore interrupt handlers first, otherwise any
3346 terminal interrupts that occur before this is done in the normal place
3347 later will cause a crash.
3350 ttres(); /* Reset the communication device */
3353 setint(); /* Arm interrupt handlers FIRST */
3355 ttres(); /* Then restore terminal. */
3358 xxscreen(SCR_TC,0,0L,""); /* Transaction complete */
3361 clsif(); /* Failsafe in case we missed */
3362 clsof(1); /* a case in the state machine. */
3365 if (server) { /* Back from packet protocol. */
3366 if (!quiet && !backgrd
3370 ) { /* Give appropriate message */
3372 conoll("C-Kermit server done");
3374 server = 0; /* Not a server any more */
3378 /* S G E T I N I T -- Handle incoming GET-Class packets */
3383 0: GET packet processed OK - ready to Send.
3384 1: Extended GET processed OK - wait for another.
3387 sgetinit(reget,xget) int reget, xget; { /* Server end of GET command */
3388 char * fs = NULL; /* Pointer to filespec */
3391 extern int usepipes, pipesend;
3392 #endif /* PIPESEND */
3395 if (!ENABLED(en_get)) { /* Only if not disabled! */
3396 errpkt((CHAR *)"GET disabled");
3402 nolinks = recursive;
3406 /* If they are alike this was already done in whoarewe() */
3407 debug(F101,"sgetinit whatru","",whatru);
3408 if (whatru & WMI_FLAG) { /* Did we get WHATAMI info? */
3409 debug(F101,"sgetinit binary (1)","",binary);
3411 if (binary != XYFT_I && binary != XYFT_L)
3414 if (binary != XYFT_L)
3417 binary = (whatru & WMI_FMODE) ? /* Yes, set file type */
3418 XYFT_B : XYFT_T; /* automatically */
3419 debug(F101,"sgetinit binary (2)","",binary);
3421 fncnv = (whatru & WMI_FNAME) ? 1 : 0; /* And name conversion */
3423 #endif /* WHATAMI */
3425 fs = (char *)srvcmd;
3426 srvptr = srvcmd; /* Point to server command buffer */
3427 decode(rdatap,putsrv,0); /* Decode the GET command into it */
3428 /* Accept multiple filespecs */
3429 cmarg2 = ""; /* Don't use cmarg2 */
3430 cmarg = ""; /* Don't use cmarg */
3432 done = 1; /* Only 1 packet needed... */
3433 if (xget) { /* Special decoding for Extended GET */
3434 char L, next, c; /* PLV items */
3435 int len, val; /* More PLV items */
3436 char * p = (char *)srvcmd; /* String to decode */
3438 done = 0; /* Maybe more packets needed */
3439 fs = NULL; /* We don't know the filespec yet */
3440 c = *p++; /* Get first parameter */
3442 while (c) { /* For all parameters... */
3443 debug(F000,"sgetinit c","",c);
3444 L = *p++; /* Get length */
3445 if (L >= SP) /* Decode length */
3447 else if (c == '@') { /* Allow missing EOP length field */
3450 len = (xunchar(*p++) * 95);
3451 len += xunchar(*p++);
3453 debug(F101,"sgetinit len","",len);
3454 next = *(p+len); /* Get next parameter */
3455 *(p+len) = NUL; /* Zero it out to terminal value */
3456 debug(F110,"sgetinit p",p,0);
3457 switch (c) { /* Do the parameter */
3458 case 'O': /* GET Options */
3459 val = atoi(p); /* Convert to int */
3460 debug(F101,"sgetinit O val","",val);
3461 if (val & GOPT_DEL) moving = 1;
3462 if (val & GOPT_RES) reget = 1;
3463 if (val & GOPT_REC) {
3466 if (fnspath == PATH_OFF)
3470 case 'M': /* Transfer Mode */
3472 debug(F101,"sgetinit M val","",val);
3475 patterns = 0; /* Takes precedence over patterns */
3476 filepeek = 0; /* and FILE SCAN */
3477 if (val == GMOD_TXT) binary = XYFT_T; /* Text */
3478 if (val == GMOD_BIN) binary = XYFT_B; /* Binary */
3479 if (val == GMOD_LBL) binary = XYFT_L; /* Labeled */
3481 case 'F': /* Filename */
3483 debug(F110,"sgetinit filename",fs,0);
3485 case '@': /* End Of Parameters */
3487 debug(F100,"sgetinit EOP","",0);
3490 errpkt((CHAR *)"Unknown GET Parameter");
3491 debug(F100,"sgetinit unknown parameter","",0);
3498 if (!fs) fs = ""; /* A filename is required */
3501 n = 0; /* Check for quoted name */
3502 if ((n = strlen(fs)) > 1) {
3503 /* Note: this does not allow for multiple quoted names */
3504 if ((fs[0] == '{' && fs[n-1] == '}') ||
3505 (fs[0] == '"' && fs[n-1] == '"')) {
3508 debug(F111,"sgetinit unquoted filename",fs,n);
3510 n = 0; /* This means no quoting */
3514 debug(F111,"sgetinit",fs,usepipes);
3515 if (usepipes && ENABLED(en_hos) && *fs == '!') {
3516 cmarg = fs + 1; /* Point past the bang */
3520 debug(F111,"sgetinit pipesend",cmarg,pipesend);
3522 if (!pipesend) { /* If it's not a pipe */
3523 #endif /* PIPESEND */
3524 if (n == 0) { /* If the name was not quoted */
3526 nfils = fnparse(fs); /* Allow it to be a list of names */
3527 debug(F111,"sgetinit A",fs,nfils);
3529 /* This doesn't work if a GET-PATH is set. */
3530 if (nfils == 1 && !iswild(fs)) { /* Single file */
3532 if ((x = zchki(fs)) < 0) { /* Check if it's sendable */
3534 case -1: m = "File not found"; break;
3535 case -2: m = "Not a regular file"; break;
3536 case -3: m = "Read access denied"; break;
3542 #endif /* COMMENT */
3543 } else { /* If it was quoted */
3544 #endif /* NOMSEND */
3547 if (matchdot) nzxopts |= ZX_MATCHDOT;
3548 #endif /* UNIXOROSK */
3549 if (recursive) nzxopts |= ZX_RECURSE;
3550 /* Treat as a single filespec */
3551 nfils = 0 - nzxpand(fs,nzxopts);
3552 debug(F111,"sgetinit B",fs,nfils);
3557 #endif /* PIPESEND */
3559 if (!done) { /* Need more O packets... */
3560 debug(F100,"sgetinit O-Packet TBC","",0); /* To Be Continued */
3563 debug(F100,"sgetinit O-Packet done - havefs","",havefs);
3564 if (!havefs) { /* Done - make sure we have filename */
3565 errpkt((CHAR *)"GET without filename");
3569 winlo = 0; /* Back to packet 0 again. */
3570 debug(F101,"sgetinit winlo","",winlo);
3571 nakstate = 0; /* Now I'm the sender! */
3572 if (reget) sendmode = SM_RESEND;
3573 if (sinit() > 0) { /* Send Send-Init */
3576 #endif /* STREAMING */
3577 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
3578 return(0); /* If successful, switch state */
3579 } else return(-1); /* Else back to server command wait */