1 char *protv = /* -*-C-*- */
2 "C-Kermit Protocol Module 9.0.160, 16 Oct 2009";
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, 2009,
14 Trustees of Columbia University in the City of New York.
15 All rights reserved. See the C-Kermit COPYING.TXT file or the
16 copyright text in the ckcmai.c module for disclaimer and permissions.
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;
151 extern int quiet, tsecs, parity, backgrd, nakstate, atcapu, wslotn, winlo;
152 extern int wslots, success, xitsta, rprintf, discard, cdtimo, keep, fdispla;
153 extern int timef, stdinf, rscapu, sendmode, epktflg, epktrcvd, epktsent;
154 extern int binary, fncnv;
155 extern long speed, ffc, crc16, calibrate, dest;
157 extern char *TYPCMD, *DIRCMD, *DIRCM2;
160 extern char *SPACMD, *SPACM2, *WHOCMD;
163 extern struct zattr iattr;
170 extern CKFLOAT fptsecs;
174 extern CHAR *epktmsg;
177 extern int f_tmpdir; /* Directory changed temporarily */
178 extern char savdir[]; /* For saving current directory */
180 #endif /* CK_TMPDIR */
182 extern int query; /* Query-active flag */
185 char querybuf[QBUFL+1] = { NUL, NUL }; /* QUERY response buffer */
186 char *qbufp = querybuf; /* Pointer to it */
187 int qbufn = 0; /* Length of data in it */
196 If the following flag is nonzero when the protocol module is entered,
197 then server mode persists for exactly one transaction, rather than
198 looping until BYE or FINISH is received.
202 static int r_save = -1;
203 static int p_save = -1;
205 /* Function to let remote-mode user know where their file(s) went */
207 int whereflg = 1; /* Unset with SET XFER REPORT */
211 extern int quiet, filrej;
214 debug(F101,"wheremsg n","",n);
216 debug(F110,"wheremsg prfspec",prfspec,0);
217 debug(F110,"wheremsg rfspec",rfspec,0);
218 debug(F110,"wheremsg psfspec",psfspec,0);
219 debug(F110,"wheremsg sfspec",sfspec,0);
221 debug(F110,"wheremsg prrfspec",prrfspec,0);
222 debug(F110,"wheremsg rrfspec",rrfspec,0);
223 debug(F110,"wheremsg psrfspec",psrfspec,0);
224 debug(F110,"wheremsg srfspec",srfspec,0);
226 if (!quiet && !local) {
231 printf(" SENT: [%s]",sfspec);
233 printf(" To: [%s]",srfspec);
234 printf(" (%s)\r\n", success ? "OK" : "FAILED");
240 printf(" RCVD: [%s]",rrfspec);
242 printf(" To: [%s]",rfspec);
243 printf(" (%s)\r\n", success ? "OK" : "FAILED");
250 printf(" SENT: (%d files)",n);
252 printf(" Last: [%s]",srfspec);
253 printf(" (%s)\r\n", success ? "OK" : "FAILED");
259 printf(" RCVD: (%d files)",n);
261 printf(" Last: [%s]",rfspec);
262 printf(" (%s)\r\n", success ? "OK" : "FAILED");
267 printf(" SENT: (0 files) \r\n");
268 else if (myjob == 'r' || myjob == 'v')
269 printf(" RCVD: (0 files) \r\n");
277 debug(F111,"RESUME","server=1",justone);
279 debug(F111,"RESUME","server=0",justone);
282 /* Flags for the ENABLE and DISABLE commands */
284 en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri,
285 en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, en_ret, en_xit,
288 extern int en_asg, en_que;
290 extern int what, lastxfer;
292 /* Global variables declared here */
294 int whatru = 0; /* What are you. */
295 int whatru2 = 0; /* What are you, cont'd. */
297 /* Local variables */
299 static char vstate = 0; /* Saved State */
300 static char vcmd = 0; /* Saved Command */
301 static int reget = 0; /* Flag for executing REGET */
302 static int retrieve = 0; /* Flag for executing RETRIEVE */
303 static int opkt = 0; /* Send Extended GET packet */
305 static int x; /* General-purpose integer */
306 static char *s; /* General-purpose string pointer */
308 /* Macros - Note, BEGIN is predefined by Wart (and Lex) as "state = ", */
309 /* BEGIN is NOT a GOTO! */
310 #define TINIT if (tinit(1) < 0) return(-9)
311 #define SERVE { TINIT; resetc(); nakstate=1; what=W_NOTHING; cmarg2=""; \
312 sendmode=SM_SEND; havefs=0; recursive=r_save; fnspath=p_save; BEGIN serve; }
313 #define RESUME { rdebug(); if (!server) { wheremsg(); return(0); } else \
314 if (justone) { justone=0; wheremsg(); return(0); } else { SERVE; } }
317 #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); \
318 fptsecs=gftimer(); quiet=x; return(success)
320 #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); quiet=x; \
325 By late 1999, the big switch() statement generated from the following state
326 table began choking even gcc, so here we extract the code from the larger
327 states into static routines to reduce the size of the cases and the
328 switch() overall. The routines follow the state table; the prototypes are
329 here. Each of these routines simply contains the text from the
330 corresponding case, but with return(-1) added in appropriate places; see
331 instructions after the state table switcher.
333 static int rc; /* Return code for these routines */
334 static int rcv_s_pkt(); /* Received an S packet */
335 static int rcv_firstdata(); /* Received first Data packet */
336 static int rcv_shortreply(); /* Short reply to a REMOTE command */
337 static int srv_query(); /* Server answers an query */
338 static int srv_copy(); /* Server executes REMOTE COPY */
339 static int srv_rename(); /* Server executes REMOTE RENAME */
340 static int srv_login(); /* Server executes REMOTE LOGIN */
341 static int srv_timeout(); /* Server times out */
346 Protocol entry points, one for each start state (sstate).
347 The lowercase letters are internal "inputs" from the user interface.
348 NOTE: The start state letters that appear on the left margin immediately
349 below can NOT be used as packet types OR as G-packet subcodes.
352 s { TINIT; /* Send file(s) */
353 if (sinit() > 0) BEGIN ssinit;
356 v { TINIT; nakstate = 1; BEGIN get; } /* Receive file(s) */
358 r { /* Client sends a GET command */
367 #endif /* PKTZEROHACK */
374 h { /* Client sends a RETRIEVE command */
386 j { /* Client sends a REGET command */
398 o { /* Client sends Extended GET Packet */
401 reget = oopts & GOPT_RES;
402 retrieve = oopts & GOPT_DEL;
410 c { /* Client sends a Host command */
419 k { TINIT; /* Client sends a Kermit command */
427 g { /* Client sends a REMOTE command */
436 x { /* Enter server mode */
439 if (!ENABLED(en_del)) { /* If DELETE is disabled */
440 if (fncact == XYFX_B || /* undo any file collision action */
441 fncact == XYFX_U || /* that could result in deletion or */
442 fncact == XYFX_A || /* modification of existing files. */
446 g_fncact = fncact; /* Save current setting */
448 fncact = XYFX_R; /* Change to RENAME */
449 debug(F101,"server DELETE disabled so fncact RENAME","",fncact);
452 SERVE; /* tinit() clears justone... */
455 if (ikdbopen) slotstate(what, "SERVER", "", "");
461 if (!data) TINIT; /* "ABEND" -- Tell other side. */
463 if (!bctf) { /* Block check 3 forced on all packets */
465 if (epktflg) { /* If because of E-PACKET command */
466 b1 = bctl; b2 = bctu; /* Save block check type */
467 bctl = bctu = 1; /* set it to 1 */
471 errpkt((CHAR *)"User cancelled"); /* Send the packet */
472 if (!bctf) { /* Block check 3 forced on all packets */
474 if (epktflg) { /* Restore the block check */
476 bctl = b1; bctu = b2;
481 return(0); /* Return from protocol. */
485 Dynamic states: <current-states>input-character { action }
486 nakstate != 0 means we're in a receiving state, in which we send ACKs & NAKs.
489 <rgen,get,serve,ropkt>S { /* Receive Send-Init packet. */
491 cancel = 0; /* Reset cancellation counter */
492 debug(F101,"rcv_s_pkt","",rc);
493 if (rc > -1) return(rc); /* (see below) */
496 /* States in which we get replies back from commands sent to a server. */
497 /* Complicated because direction of protocol changes, packet number */
498 /* stays at zero through I-G-S sequence, and complicated even more by */
499 /* sliding windows buffer allocation. */
501 <ipkt>Y { /* Get ack for I-packet */
504 ckstrncpy(ipktack,(char *)rdatap,PKTZEROLEN); /* Save a copy of the ACK */
505 ipktlen = strlen(ipktack);
506 #endif /* PKTZEROHACK */
507 spar(rdatap); /* Set parameters */
509 winlo = 0; /* Set window-low back to zero */
510 debug(F101,"<ipkt>Y winlo","",winlo);
511 urserver = 1; /* So I know I'm talking to a server */
512 if (vcmd) { /* If sending a generic command */
513 if (tinit(0) < 0) return(-9); /* Initialize many things */
514 x = scmd(vcmd,(CHAR *)cmarg); /* Do that */
515 if (x >= 0) x = 0; /* (because of O-Packet) */
516 debug(F101,"proto G packet scmd","",x);
517 vcmd = 0; /* and then un-remember it. */
518 } else if (vstate == get) {
519 debug(F101,"REGET sstate","",sstate);
520 x = srinit(reget, retrieve, opkt); /* GET or REGET, etc */
522 if (x < 0) { /* If command was too long */
524 srimsg = "Error sending string";
525 errpkt((CHAR *)srimsg); /* cancel both sides. */
528 } else if (x > 0) { /* Need to send more O-Packets */
531 rtimer(); /* Reset the elapsed seconds timer. */
535 winlo = 0; /* Window back to 0, again. */
536 debug(F101,"<ipkt>Y vstate","",vstate);
537 nakstate = 1; /* Can send NAKs from here. */
538 BEGIN vstate; /* Switch to desired state */
542 <ssopkt>Y { /* Got ACK to O-Packet */
543 debug(F100,"CPCPRO <ssopkt>Y","",0);
545 debug(F101,"CPCPRO <ssopkt>Y x","",x);
546 if (x < 0) { /* If error */
547 errpkt((CHAR *)srimsg); /* cancel both sides. */
550 } else if (x == 0) { /* This was the last O-Packet */
551 rtimer(); /* Reset the elapsed seconds timer. */
555 winlo = 0; /* Window back to 0, again. */
556 debug(F101,"<ssopkt>Y winlo","",winlo);
557 nakstate = 1; /* Can send NAKs from here. */
558 BEGIN vstate; /* Switch to desired state */
560 debug(F101,"CPCPRO <ssopkt>Y not changing state","",x);
563 <ipkt>E { /* Ignore Error reply to I packet */
565 winlo = 0; /* Set window-low back to zero */
566 debug(F101,"<ipkt>E winlo","",winlo);
567 if (vcmd) { /* In case other Kermit doesn't */
568 if (tinit(0) < 0) return(-9);
569 x = scmd(vcmd,(CHAR *)cmarg); /* understand I-packets. */
570 if (x >= 0) x = 0; /* (because of O-Packet) */
571 vcmd = 0; /* Otherwise act as above... */
572 } else if (vstate == get) x = srinit(reget, retrieve, opkt);
573 if (x < 0) { /* If command was too long */
574 errpkt((CHAR *)srimsg); /* cancel both sides. */
577 } else if (x > 0) { /* Need to send more O-Packets */
580 freerpkt(winlo); /* Discard the Error packet. */
581 debug(F101,"<ipkt>E winlo","",winlo);
582 winlo = 0; /* Back to packet 0 again. */
583 nakstate = 1; /* Can send NAKs from here. */
588 <get>Y { /* Resend of previous I-pkt ACK, same seq number */
589 freerpkt(0); /* Free the ACK's receive buffer */
590 resend(0); /* Send the GET packet again. */
593 /* States in which we're being a server */
595 <serve,get>I { /* Get I-packet */
597 spar(rdatap); /* Set parameters from it */
598 ack1(rpar()); /* Respond with our own parameters */
600 pktinit(); /* Reinitialize packet numbers */
603 /* This can't be right - it undoes the stuff we just negotiated */
605 tinit(1); /* Reinitialize EVERYTHING */
606 justone = x; /* But this... */
608 tinit(0); /* Initialize most things */
611 #endif /* NOSERVER */
612 cancel = 0; /* Reset cancellation counter */
617 if (x_login && !x_logged) {
618 errpkt((CHAR *)"Login required");
620 } else if (sgetinit(0,0) < 0) {
624 if (ckxsyslog >= SYSLG_PR && ckxlogging)
625 cksyslog(SYSLG_PR, 1, "server", "GET", (char *)srvcmd);
626 #endif /* CKSYSLOG */
629 #endif /* NOSERVER */
632 <serve>H { /* GET /DELETE (RETRIEVE) */
634 if (x_login && !x_logged) {
635 errpkt((CHAR *)"Login required");
637 } else if (!ENABLED(en_del)) {
638 errpkt((CHAR *)"Deleting files is disabled");
640 } else if (sgetinit(0,0) < 0) {
645 if (ckxsyslog >= SYSLG_PR && ckxlogging)
646 cksyslog(SYSLG_PR, 1, "server", "GET /DELETE", (char *)srvcmd);
647 #endif /* CKSYSLOG */
650 #endif /* NOSERVER */
653 <serve>V { /* GET /RECURSIVE */
655 recursive = 1; /* Set these before sgetinit() */
656 if (fnspath == PATH_OFF)
657 fnspath = PATH_REL; /* Don't worry, they will be */
658 if (x_login && !x_logged) { /* reset next time through. */
659 errpkt((CHAR *)"Login required");
661 } else if (sgetinit(0,0) < 0) {
665 if (ckxsyslog >= SYSLG_PR && ckxlogging)
666 cksyslog(SYSLG_PR, 1, "server", "GET /RECURSIVE", (char *)srvcmd);
667 #endif /* CKSYSLOG */
670 #endif /* NOSERVER */
673 <serve>W { /* GET /RECURSIVE /DELETE */
675 recursive = 1; /* Set these before sgetinit() */
676 if (fnspath == PATH_OFF)
677 fnspath = PATH_REL; /* Don't worry, they will be */
678 moving = 1; /* reset next time through. */
679 if (x_login && !x_logged) {
680 errpkt((CHAR *)"Login required");
682 } else if (!ENABLED(en_del)) {
683 errpkt((CHAR *)"Deleting files is disabled");
685 } else if (sgetinit(0,0) < 0) {
689 if (ckxsyslog >= SYSLG_PR && ckxlogging)
690 cksyslog(SYSLG_PR,1,"server",
691 "GET /RECURSIVE /DELETE",(char *)srvcmd);
692 #endif /* CKSYSLOG */
695 #endif /* NOSERVER */
698 <serve>J { /* GET /RECOVER (REGET) */
700 if (x_login && !x_logged) {
701 errpkt((CHAR *)"Login required");
703 } else if (sgetinit(1,0) < 0) {
707 if (ckxsyslog >= SYSLG_PR && ckxlogging)
708 cksyslog(SYSLG_PR, 1, "server", "GET /RECOVER", (char *)srvcmd);
709 #endif /* CKSYSLOG */
712 #endif /* NOSERVER */
715 <serve>O { /* Extended GET */
717 if (x_login && !x_logged) { /* (any combination of options) */
718 errpkt((CHAR *)"Login required");
720 } else if ((x = sgetinit(0,1)) < 0) {
721 debug(F101,"CKCPRO <serve>O sgetinit fail","",x);
724 debug(F101,"CKCPRO <serve>O sgetinit done","",x);
726 if (ckxsyslog >= SYSLG_PR && ckxlogging)
727 cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
728 #endif /* CKSYSLOG */
730 } else { /* Otherwise stay in this state */
731 debug(F101,"CKCPRO <serve>O sgetinit TBC","",x);
735 #endif /* NOSERVER */
740 if (x_login && !x_logged) { /* (any combination of options) */
741 errpkt((CHAR *)"Login required");
743 } else if ((x = sgetinit(0,1)) < 0) {
744 debug(F101,"CKCPRO <ropkt>O sgetinit fail","",x);
747 debug(F101,"CKCPRO <ropkt>O sgetinit done","",x);
749 if (ckxsyslog >= SYSLG_PR && ckxlogging)
750 cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
751 #endif /* CKSYSLOG */
753 } else { /* Otherwise stay in this state */
754 debug(F101,"CKCPRO <ropkt>O sgetinit TBC","",x);
757 #endif /* NOSERVER */
760 <serve>G { /* Generic server command */
762 srvptr = srvcmd; /* Point to command buffer */
763 decode(rdatap,putsrv,0); /* Decode packet data into it */
764 putsrv(NUL); /* Insert a couple nulls */
765 putsrv(NUL); /* for termination */
767 sstate = srvcmd[0]; /* Set requested start state */
768 if (x_login && !x_logged && /* Login required? */
769 /* Login, Logout, and Help are allowed when not logged in */
770 sstate != 'I' && sstate != 'L' && sstate != 'H') {
771 errpkt((CHAR *)"Login required");
774 nakstate = 0; /* Now I'm the sender. */
775 what = W_REMO; /* Doing a REMOTE command. */
778 #endif /* STREAMING */
780 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
781 binary = XYFT_T; /* Switch to text mode */
782 BEGIN generic; /* Switch to generic command state */
785 errpkt((CHAR *)"Badly formed server command"); /* report error */
786 RESUME; /* & go back to server command wait */
788 #endif /* NOSERVER */
791 <serve>C { /* Receive Host command */
793 if (x_login && !x_logged) {
794 errpkt((CHAR *)"Login required");
796 } else if (!ENABLED(en_hos)) {
797 errpkt((CHAR *)"REMOTE HOST disabled");
800 errpkt((CHAR *)"HOST commands not available");
803 srvptr = srvcmd; /* Point to command buffer */
804 decode(rdatap,putsrv,0); /* Decode command packet into it */
805 putsrv(NUL); /* Null-terminate */
806 nakstate = 0; /* Now sending, not receiving */
807 binary = XYFT_T; /* Switch to text mode */
808 if (syscmd((char *)srvcmd,"")) { /* Try to execute the command */
809 what = W_REMO; /* Doing a REMOTE command. */
812 #endif /* STREAMING */
814 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
816 if (ckxsyslog >= SYSLG_PR && ckxlogging)
817 cksyslog(SYSLG_PR, 1, "server", "REMOTE HOST", (char *)srvcmd);
818 #endif /* CKSYSLOG */
819 BEGIN ssinit; /* If OK, send back its output */
820 } else { /* Otherwise */
821 errpkt((CHAR *)"Can't do system command"); /* report error */
822 RESUME; /* & go back to server command wait */
825 #endif /* NOSERVER */
828 <serve>q { /* Interrupted or connection lost */
830 debug(F101,"srv_timeout","",rc);
831 if (rc > -1) return(rc); /* (see below) */
834 <serve>N { /* Server got a NAK in command-wait */
836 errpkt((CHAR *)"Did you say RECEIVE instead of GET?");
838 #endif /* NOSERVER */
841 <serve>. { /* Any other command in this state */
843 if (c != ('E' - SP) && c != ('Y' - SP)) /* except E and Y packets. */
844 errpkt((CHAR *)"Unimplemented server function");
845 /* If we answer an E with an E, we get an infinite loop. */
846 /* A Y (ACK) can show up here if we sent back a short-form reply to */
847 /* a G packet and it was echoed. ACKs can be safely ignored here. */
848 RESUME; /* Go back to server command wait. */
849 #endif /* NOSERVER */
852 <generic>I { /* Login/Out */
854 debug(F101,"<generic>I srv_login","",rc);
855 if (rc > -1) return(rc); /* (see below) */
858 <generic>C { /* Got REMOTE CD command */
861 if (ckxsyslog >= SYSLG_PR && ckxlogging)
862 cksyslog(SYSLG_PR, 1, "server", "REMOTE CD", (char *)srvcmd);
863 #endif /* CKSYSLOG */
864 if (!ENABLED(en_cwd)) {
865 errpkt((CHAR *)"REMOTE CD disabled");
869 x = cwd((char *)(srvcmd+1)); /* Try to change directory */
871 if (ikdbopen) slotstate(what,"REMOTE CD", (char *)(srvcmd+2), "");
873 if (!x) { /* Failed */
874 errpkt((CHAR *)"Can't change directory");
875 RESUME; /* Back to server command wait */
876 } else if (x == 2) { /* User wants message */
877 if (!ENABLED(en_typ)) { /* Messages (REMOTE TYPE) disabled? */
878 errpkt((CHAR *)"REMOTE TYPE disabled");
880 } else { /* TYPE is enabled */
882 for (i = 0; i < 8; i++) {
883 if (zchki(cdmsgfile[i]) > -1) {
887 binary = XYFT_T; /* Use text mode for this. */
888 if (i < 8 && sndtype(cdmsgfile[i])) { /* Have readme file? */
889 BEGIN ssinit; /* OK */
890 } else { /* not OK */
893 success = (*p) ? 1 : 0;
894 ack1((CHAR *)p); /* ACK with new directory name */
896 RESUME; /* wait for next server command */
899 } else { /* User doesn't want message */
902 success = (*p) ? 1 : 0;
905 RESUME; /* Wait for next server command */
908 #endif /* NOSERVER */
911 <generic>A { /* Got REMOTE PWD command */
914 if (ckxsyslog >= SYSLG_PR && ckxlogging)
915 cksyslog(SYSLG_PR, 1, "server", "REMOTE PWD", NULL);
916 #endif /* CKSYSLOG */
917 if (!ENABLED(en_cwd)) {
918 errpkt((CHAR *)"REMOTE CD disabled");
921 if (encstr((CHAR *)zgtdir()) > -1) { /* Encode current directory */
922 ack1(data); /* If it fits, send it back in ACK */
924 } else { /* Failed */
925 ack(); /* Send empty ACK */
926 success = 0; /* and indicate failure locally */
928 RESUME; /* Back to server command wait */
930 #endif /* NOSERVER */
933 <generic>D { /* REMOTE DIRECTORY command */
937 if (ckxsyslog >= SYSLG_PR && ckxlogging)
938 cksyslog(SYSLG_PR, 1, "server", "REMOTE DIRECTORY", (char *)srvcmd);
939 #endif /* CKSYSLOG */
940 if (!ENABLED(en_dir)) { /* If DIR is disabled, */
941 errpkt((CHAR *)"REMOTE DIRECTORY disabled"); /* refuse. */
943 } else { /* DIR is enabled. */
945 if (ikdbopen) slotstate(what,"REMOTE DIR", (char *)(srvcmd+2), "");
947 if (!ENABLED(en_cwd)) { /* But CWD is disabled */
948 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
949 if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
950 errpkt((CHAR *)"Access denied");
951 RESUME; /* Remember, this is not a goto! */
954 if (state == generic) { /* It's OK to go ahead. */
956 n2 = (*(srvcmd+2)) ? DIRCMD : DIRCM2;
957 if (syscmd(n2,(char *)(srvcmd+2))) /* If it can be done */
960 if ((x = snddir((char*)(srvcmd+2))) > 0)
963 BEGIN ssinit; /* send the results back; */
964 } else { /* otherwise */
966 errpkt((CHAR *)"No files match");
968 errpkt((CHAR *)"Can't list directory");
969 RESUME; /* return to server command wait */
973 #endif /* NOSERVER */
976 <generic>E { /* REMOTE DELETE (Erase) */
980 if (ckxsyslog >= SYSLG_PR && ckxlogging)
981 cksyslog(SYSLG_PR, 1, "server", "REMOTE DELETE", (char *)srvcmd);
982 #endif /* CKSYSLOG */
983 if (!ENABLED(en_del)) {
984 errpkt((CHAR *)"REMOTE DELETE disabled");
986 } else { /* DELETE is enabled */
988 if (ikdbopen) slotstate(what,"REMOTE DELETE", (char *)(srvcmd+2), "");
990 if (!ENABLED(en_cwd)) { /* but CWD is disabled */
991 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
992 if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
993 errpkt((CHAR *)"Access denied");
994 RESUME; /* Remember, this is not a goto! */
996 } else if (isdir((char *)(srvcmd+2))) { /* A directory name? */
997 errpkt((CHAR *)"It's a directory");
1000 if (state == generic) { /* It's OK to go ahead. */
1002 if ((x = snddel((char*)(srvcmd+2))) > 0) {
1003 BEGIN ssinit; /* If OK send results back */
1004 } else { /* otherwise */
1006 errpkt((CHAR *)"File not found"); /* report failure */
1008 errpkt((CHAR *)"DELETE failed");
1009 RESUME; /* & return to server command wait */
1013 #endif /* NOSERVER */
1016 <generic>F { /* FINISH */
1019 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1020 cksyslog(SYSLG_PR, 1, "server", "FINISH", NULL);
1021 #endif /* CKSYSLOG */
1023 if (ikdbopen) slotstate(what,"SERVER FINISH", "", "");
1025 if (!ENABLED(en_fin)) {
1026 errpkt((CHAR *)"FINISH disabled");
1029 ack(); /* Acknowledge */
1030 xxscreen(SCR_TC,0,0L,""); /* Display */
1032 return(0); /* Done */
1034 #endif /* NOSERVER */
1037 <generic>X { /* EXIT */
1040 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1041 cksyslog(SYSLG_PR, 1, "server", "REMOTE EXIT", NULL);
1042 #endif /* CKSYSLOG */
1044 if (ikdbopen) slotstate(what,"REMOTE EXIT", "", "");
1046 if (!ENABLED(en_xit)) {
1047 errpkt((CHAR *)"EXIT disabled");
1050 ack(); /* Acknowledge */
1051 xxscreen(SCR_TC,0,0L,""); /* Display */
1052 doexit(GOOD_EXIT,xitsta);
1054 #endif /* NOSERVER */
1057 <generic>L { /* BYE (Logout) */
1060 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1061 cksyslog(SYSLG_PR, 1, "server", "BYE", NULL);
1062 #endif /* CKSYSLOG */
1064 if (ikdbopen) slotstate(what,"SERVER BYE", "", "");
1066 if (!ENABLED(en_bye)) {
1067 errpkt((CHAR *)"BYE disabled");
1070 ack(); /* Acknowledge */
1072 msleep(750); /* Give the ACK time to get out */
1074 ttres(); /* Reset the terminal */
1075 xxscreen(SCR_TC,0,0L,""); /* Display */
1076 doclean(1); /* Clean up files, etc */
1078 debug(F100,"C-Kermit BYE - Logging out...","",0);
1086 #endif /* CK_LOGIN */
1090 if (network && tcpsrfd > 0 && !inserver)
1091 doexit(GOOD_EXIT,xitsta);
1093 #endif /* NOLISTEN */
1094 #endif /* TCPSOCKET */
1095 return(zkself()); /* Try to log self out */
1097 #endif /* NOSERVER */
1100 <generic>H { /* REMOTE HELP */
1102 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1103 cksyslog(SYSLG_PR, 1, "server", "REMOTE HELP", NULL);
1104 #endif /* CKSYSLOG */
1106 if (ikdbopen) slotstate(what,"REMOTE HELP", "", "");
1110 BEGIN ssinit; /* try to send it */
1111 } else { /* If not ok, */
1112 errpkt((CHAR *)"Can't send help"); /* send error message instead */
1113 RESUME; /* and return to server command wait */
1115 #endif /* NOSERVER */
1118 <generic>R { /* REMOTE RENAME */
1120 debug(F101,"srv_rename","",rc);
1121 if (rc > -1) return(rc); /* (see below) */
1124 <generic>K { /* REMOTE COPY */
1126 debug(F101,"srv_copy","",rc);
1127 if (rc > -1) return(rc); /* (see below) */
1130 <generic>S { /* REMOTE SET */
1132 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1133 cksyslog(SYSLG_PR, 1, "server", "REMOTE SET", (char *)srvcmd);
1134 #endif /* CKSYSLOG */
1137 if (ikdbopen) slotstate(what,"REMOTE SET", (char *)(srvcmd+1), "");
1139 if (!ENABLED(en_set)) {
1140 errpkt((CHAR *)"REMOTE SET disabled");
1143 if (remset((char *)(srvcmd+1))) { /* Try to do what they ask */
1145 ack(); /* If OK, then acknowledge */
1146 } else /* Otherwise */
1147 errpkt((CHAR *)"Unknown REMOTE SET parameter"); /* give error msg */
1148 RESUME; /* Return to server command wait */
1150 #endif /* NOSERVER */
1153 <generic>T { /* REMOTE TYPE */
1157 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1158 cksyslog(SYSLG_PR, 1, "server", "REMOTE TYPE", (char *)srvcmd);
1159 #endif /* CKSYSLOG */
1160 if (!ENABLED(en_typ)) {
1161 errpkt((CHAR *)"REMOTE TYPE disabled");
1165 if (ikdbopen) slotstate(what,"REMOTE TYPE", (char *)(srvcmd+2), "");
1167 if (!ENABLED(en_cwd)) { /* If CWD disabled */
1168 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
1169 if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */
1170 errpkt((CHAR *)"Access denied");
1171 RESUME; /* Remember, this is not a goto! */
1174 if (state == generic) { /* It's OK to go ahead. */
1175 binary = XYFT_T; /* Use text mode for this. */
1176 if ( /* (RESUME didn't change state) */
1178 syscmd(TYPCMD,(char *)(srvcmd+2)) /* Old way */
1180 sndtype((char *)(srvcmd+2)) /* New way */
1181 #endif /* COMMENT */
1183 BEGIN ssinit; /* OK */
1185 errpkt((CHAR *)"Can't type file"); /* give error message */
1186 RESUME; /* wait for next server command */
1190 #endif /* NOSERVER */
1193 <generic>m { /* REMOTE MKDIR */
1197 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1198 cksyslog(SYSLG_PR, 1, "server", "REMOTE MKDIR", (char *)srvcmd);
1199 #endif /* CKSYSLOG */
1201 if (ikdbopen) slotstate(what,"REMOTE MKDIR", (char *)(srvcmd+2), "");
1203 if (!ENABLED(en_mkd)) {
1204 errpkt((CHAR *)"REMOTE MKDIR disabled");
1206 } else if (!ENABLED(en_cwd)) { /* If CWD disabled */
1207 errpkt((CHAR *)"Directory access restricted");
1208 RESUME; /* Remember, this is not a goto! */
1210 if (state == generic) { /* OK to go ahead. */
1212 x = ckmkdir(0,(char *)(srvcmd+2),&p,0,1); /* Make the directory */
1215 encstr((CHAR *)p); /* OK - encode the name */
1216 ack1(data); /* Send short-form response */
1219 } else { /* not OK */
1220 if (!*p) p = "Directory creation failure";
1221 errpkt((CHAR *)p); /* give error message */
1222 RESUME; /* Wait for next server command */
1226 errpkt((CHAR *)"REMOTE MKDIR not available");
1228 #endif /* CK_MKDIR */
1229 #endif /* NOSERVER */
1232 <generic>d { /* REMOTE RMDIR */
1236 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1237 cksyslog(SYSLG_PR, 1, "server", "REMOTE RMDIR", (char *)srvcmd);
1238 #endif /* CKSYSLOG */
1240 if (ikdbopen) slotstate(what,"REMOTE RMDIR", (char *)(srvcmd+2), "");
1242 if (!ENABLED(en_rmd)) {
1243 errpkt((CHAR *)"REMOTE RMDIR disabled");
1245 } else if (!ENABLED(en_cwd)) { /* If CWD disabled */
1246 errpkt((CHAR *)"Directory access restricted");
1247 RESUME; /* Remember, this is not a goto! */
1249 if (state == generic) { /* OK to go ahead. */
1251 x = ckmkdir(1,(char *)(srvcmd+2),&p,0,1);
1254 encstr((CHAR *)p); /* OK - encode the name */
1255 ack1(data); /* Send short-form response */
1258 } else { /* not OK */
1259 if (!*p) p = "Directory removal failure";
1260 errpkt((CHAR *)p); /* give error message */
1261 RESUME; /* Wait for next server command */
1265 errpkt((CHAR *)"REMOTE RMDIR not available");
1267 #endif /* CK_MKDIR */
1268 #endif /* NOSERVER */
1271 <generic>U { /* REMOTE SPACE */
1274 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1275 cksyslog(SYSLG_PR, 1, "server", "REMOTE SPACE", (char *)srvcmd);
1276 #endif /* CKSYSLOG */
1277 if (!ENABLED(en_spa)) {
1278 errpkt((CHAR *)"REMOTE SPACE disabled");
1281 x = srvcmd[1]; /* Get area to check */
1282 x = ((x == NUL) || (x == SP)
1284 || (x == '!') || (srvcmd[3] == ':')
1288 if (ikdbopen) slotstate(what,
1290 (x ? "" : (char *)srvcmd),
1294 if (!x && !ENABLED(en_cwd)) { /* CWD disabled */
1295 errpkt((CHAR *)"Access denied"); /* and non-default area given, */
1296 RESUME; /* refuse. */
1299 _PROTOTYP(int sndspace,(int));
1300 if (sndspace(x ? toupper(srvcmd[2]) : 0)) {
1301 BEGIN ssinit; /* send the report. */
1302 } else { /* If not ok, */
1303 errpkt((CHAR *)"Can't send space"); /* send error message */
1304 RESUME; /* and return to server command wait */
1310 x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,(char *)(srvcmd+2)));
1311 if (x) { /* If we got the info */
1312 BEGIN ssinit; /* send it */
1313 } else { /* otherwise */
1314 errpkt((CHAR *)"Can't check space"); /* send error message */
1315 RESUME; /* and await next server command */
1320 #endif /* NOSERVER */
1323 <generic>W { /* REMOTE WHO */
1326 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1327 cksyslog(SYSLG_PR, 1, "server", "REMOTE WHO", (char *)srvcmd);
1328 #endif /* CKSYSLOG */
1330 if (ikdbopen) slotstate(what,"REMOTE WHO", (char *)(srvcmd+2), "");
1332 if (!ENABLED(en_who)) {
1333 errpkt((CHAR *)"REMOTE WHO disabled");
1337 _PROTOTYP(int sndwho,(char *));
1338 if (sndwho((char *)(srvcmd+2))) {
1339 BEGIN ssinit; /* try to send it */
1340 } else { /* If not ok, */
1341 errpkt((CHAR *)"Can't do who command"); /* send error msg */
1342 RESUME; /* and return to server command wait */
1345 if (syscmd(WHOCMD,(char *)(srvcmd+2))) {
1348 errpkt((CHAR *)"Can't do who command");
1353 #endif /* NOSERVER */
1356 <generic>V { /* Variable query or set */
1358 debug(F101,"srv_query","",rc);
1359 if (rc > -1) return(rc);
1362 <generic>M { /* REMOTE MESSAGE command */
1364 debug(F110,"RMSG",(char *)srvcmd+2,0);
1365 xxscreen(SCR_MS,0,0L,(char *)(srvcmd+2));
1368 #endif /* NOSERVER */
1371 <generic>q { /* Interrupted or connection lost */
1373 if (fatalio) { /* Connection lost */
1375 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1376 cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
1377 #endif /* CKSYSLOG */
1379 xitsta |= (what & W_KERMIT);
1381 } else if (interrupted) {
1382 if (!ENABLED(en_fin)) { /* Ctrl-C typed */
1383 errpkt((CHAR *)"QUIT disabled");
1387 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1388 cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
1389 #endif /* CKSYSLOG */
1391 xitsta |= (what & W_KERMIT);
1394 } else { /* Shouldn't happen */
1395 debug(F100,"SERVER (generic) GOT UNEXPECTED 'q'","",0);
1398 #endif /* NOSERVER */
1401 <generic>. { /* Anything else in this state... */
1403 errpkt((CHAR *)"Unimplemented REMOTE command"); /* Complain */
1404 RESUME; /* and return to server command wait */
1405 #endif /* NOSERVER */
1408 <rgen>q { /* Sent BYE and connection broken */
1409 if (bye_active && ttchk() < 0) {
1412 ttclos(0); /* Close our end of the connection */
1414 return(success = 1);
1415 } else { /* Other generic command */
1416 return(success = 0); /* or connection not broken */
1420 <rgen>Y { /* Short-Form reply */
1421 rc = rcv_shortreply();
1422 debug(F101,"<rgen>Y rcv_shortreply","",rc);
1423 if (rc > -1) return(rc);
1426 <rgen,rfile>F { /* File header */
1429 debug(F101,"<rfile>F winlo 1","",winlo);
1430 xflg = 0; /* Not screen data */
1432 cancel = 0; /* Reset cancellation counter */
1436 #endif /* CALIBRATE */
1437 if (!rcvfil(filnam)) { /* Figure out local filename */
1438 errpkt((CHAR *)rf_err); /* Trouble */
1440 } else { /* Real file, OK to receive */
1442 debug(F111,"<rfile>F winlo 2",fspec,winlo);
1443 if (filcnt == 1) /* rcvfil set this to 1 for 1st file */
1444 crc16 = 0L; /* Clear file CRC */
1445 fnp = fspec; /* This is the full path */
1446 if (server && !ENABLED(en_cwd) || /* if DISABLE CD */
1447 !fackpath /* or F-ACK-PATH OFF */
1449 zstrip(fspec,&fnp); /* don't send back full path */
1451 encstr((CHAR *)fnp);
1455 ack1(data); /* Send it back in ACK */
1456 initattr(&iattr); /* Clear file attribute structure */
1458 if (window(wslotn) < 0) { /* Allocate negotiated window slots */
1459 errpkt((CHAR *)"Can't open window");
1463 if (ikdbopen) slotstate(what,
1464 server ? "SERVER" : "",
1469 BEGIN rattr; /* Now expect Attribute packets */
1473 <rgen,rfile>X { /* X-packet instead of file header */
1474 xflg = 1; /* Screen data */
1476 cancel = 0; /* Reset cancellation counter */
1477 ack(); /* Acknowledge the X-packet */
1478 initattr(&iattr); /* Initialize attribute structure */
1480 if (window(wslotn) < 0) { /* allocate negotiated window slots */
1481 errpkt((CHAR *)"Can't open window");
1485 if (query) { /* If this is the response to */
1486 qbufp = querybuf; /* a query that we sent, initialize */
1487 qbufn = 0; /* the response buffer */
1491 what = W_REMO; /* we're doing a REMOTE command */
1493 if (ikdbopen) slotstate(what,
1494 server ? "SERVER" : "",
1499 BEGIN rattr; /* Expect Attribute packets */
1502 <rattr>A { /* Attribute packet */
1503 if (gattr(rdatap,&iattr) == 0) { /* Read into attribute structure */
1505 ack1((CHAR *)iattr.reply.val); /* Reply with data */
1507 ack(); /* If OK, acknowledge */
1508 #endif /* CK_RESEND */
1509 } else { /* Otherwise */
1512 r = getreason(iattr.reply.val);
1513 ack1((CHAR *)iattr.reply.val); /* refuse to accept the file */
1514 xxscreen(SCR_ST,ST_REFU,0L,r); /* reason */
1516 if (tralog && !tlogfmt)
1517 doxlog(what,filnam,fsize,binary,1,r);
1522 <rattr>D { /* First data packet */
1523 debug(F100,"<rattr> D firstdata","",0);
1524 rc = rcv_firstdata();
1525 debug(F101,"rcv_firstdata rc","",rc);
1526 if (rc > -1) return(rc); /* (see below) */
1529 <rfile>B { /* EOT, no more files */
1530 ack(); /* Acknowledge the B packet */
1531 reot(); /* Do EOT things */
1533 /* If we were cd'd temporarily to another device or directory ... */
1536 x = zchdir((char *) savdir); /* ... restore previous directory */
1537 f_tmpdir = 0; /* and remember we did it. */
1538 debug(F111,"ckcpro.w B tmpdir restoring",savdir,x);
1540 #endif /* CK_TMPDIR */
1541 RESUME; /* and quit */
1544 <rdpkt>D { /* Got Data packet */
1545 debug(F101,"<rdpkt>D cxseen","",cxseen);
1546 debug(F101,"<rdpkt>D czseen","",czseen);
1547 if (cxseen || czseen || discard) { /* If file or group interruption */
1549 msg = czseen ? (CHAR *)"Z" : (CHAR *)"X";
1551 if (streaming) { /* Need to cancel */
1552 debug(F111,"<rdpkt>D streaming cancel",msg,cancel);
1553 if (cancel++ == 0) { /* Only do this once */
1554 ack1(msg); /* Put "X" or "Z" in ACK */
1555 } else if (czseen) {
1556 errpkt((CHAR *)"User canceled");
1562 #endif /* STREAMING */
1564 } else { /* No interruption */
1572 rc = (binary && !parity) ?
1573 bdecode(rdatap,putfil):
1574 decode(rdatap, qf ? puttrm : putfil, 1);
1576 rc = decode(rdatap, qf ? puttrm : putfil, 1);
1577 #endif /* CKTUNING */
1579 discard = (keep == 0 || (keep == SET_AUTO && binary != XYFT_T));
1580 errpkt((CHAR *)"Error writing data"); /* If failure, */
1582 } else /* Data written OK, send ACK */
1587 #endif /* STREAMING */
1592 <rattr>Z { /* EOF immediately after A-Packet. */
1593 rf_err = "Can't create file";
1595 if (discard) { /* Discarding a real file... */
1597 } else if (xflg) { /* If screen data */
1598 if (remfile) { /* redirected to file */
1599 if (rempipe) /* or pipe */
1600 x = openc(ZOFILE,remdest); /* Pipe: start command */
1602 x = opena(remdest,&iattr); /* File: open with attributes */
1603 } else { /* otherwise */
1604 x = opent(&iattr); /* "open" the screen */
1607 } else if (calibrate) { /* If calibration run */
1608 x = ckopenx(&iattr); /* do this */
1609 #endif /* CALIBRATE */
1610 } else { /* otherwise */
1611 x = opena(filnam,&iattr); /* open the file, with attributes */
1612 if (x == -17) { /* REGET skipped because same size */
1617 if (!x || reof(filnam, &iattr) < 0) { /* Close output file */
1618 errpkt((CHAR *) rf_err); /* If problem, send error msg */
1619 RESUME; /* and quit */
1620 } else { /* otherwise */
1622 xxscreen(SCR_ST,ST_SKIP,SKP_RES,"");
1623 ack(); /* acknowledge the EOF packet */
1624 BEGIN rfile; /* and await another file */
1628 <rdpkt>q { /* Ctrl-C or connection loss. */
1630 window(1); /* Set window size back to 1... */
1632 x = clsof(1); /* Close file */
1633 return(success = 0); /* Failed */
1636 <rdpkt>Z { /* End Of File (EOF) Packet */
1637 /* wslots = 1; */ /* (don't set) Window size back to 1 */
1638 #ifndef COHERENT /* Coherent compiler blows up on this switch() statement. */
1639 x = reof(filnam, &iattr); /* Handle the EOF packet */
1640 switch (x) { /* reof() sets the success flag */
1641 case -5: /* Handle problems */
1642 errpkt((CHAR *)"RENAME failed"); /* Fatal */
1646 errpkt((CHAR *)"MOVE failed"); /* Fatal */
1649 case -3: /* If problem, send error msg */
1650 errpkt((CHAR *)"Can't print file"); /* Fatal */
1654 errpkt((CHAR *)"Can't mail file"); /* Fatal */
1657 case 2: /* Not fatal */
1659 xxscreen(SCR_EM,0,0L,"Receiver can't delete temp file");
1663 if (x < 0) { /* Fatal */
1664 errpkt((CHAR *)"Can't close file");
1666 } else { /* Success */
1668 if (query) /* Query reponses generally */
1669 conoll(""); /* don't have line terminators */
1671 if (czseen) { /* Batch canceled? */
1672 if (cancel++ == 0) { /* If we haven't tried this yet */
1673 ack1((CHAR *)"Z"); /* Try it once */
1674 } else { /* Otherwise */
1675 errpkt((CHAR *)"User canceled"); /* quite with Error */
1679 ack(); /* Acknowledge the EOF packet */
1680 BEGIN rfile; /* and await another file */
1684 if (reof(filnam, &iattr) < 0) { /* Close the file */
1685 errpkt((CHAR *)"Error at end of file");
1687 } else { /* reof() sets success flag */
1691 #endif /* COHERENT */
1694 <ssinit>Y { /* ACK for Send-Init */
1695 spar(rdatap); /* set parameters from it */
1701 bctu = bctr; /* switch to agreed-upon block check */
1702 bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
1706 if ((sendmode == SM_RESEND) && (!atcapu || !rscapu)) { /* RESEND */
1707 errpkt((CHAR *) "RESEND capabilities not negotiated");
1710 #endif /* CK_RESEND */
1711 what = W_SEND; /* Remember we're sending */
1713 x = sfile(xflg); /* Send X or F header packet */
1714 cancel = 0; /* Reset cancellation counter */
1715 if (x) { /* If the packet was sent OK */
1716 if (!xflg && filcnt == 1) /* and it's a real file */
1717 crc16 = 0L; /* Clear the file CRC */
1718 resetc(); /* reset per-transaction counters */
1719 rtimer(); /* reset timers */
1722 #endif /* GFTIMER */
1723 streamon(); /* turn on streaming */
1725 if (ikdbopen) slotstate(what,
1726 (server ? "SERVER" : ""),
1731 BEGIN ssfile; /* and switch to receive-file state */
1732 } else { /* otherwise send error msg & quit */
1733 s = xflg ? "Can't execute command" : (char *)epktmsg;
1734 if (!*s) s = "Can't open file";
1740 #endif /* CK_RESEND */
1744 These states are necessary to handle the case where we get a server command
1745 packet (R, G, or C) reply with an S packet, but the client retransmits the
1746 command packet. The input() function doesn't catch this because the packet
1747 number is still zero.
1749 <ssinit>R { /* R packet was retransmitted. */
1750 xsinit(); /* Resend packet 0 */
1753 <ssinit>G { /* Same deal if G packet comes again */
1757 /* should probably add cases for O, W, V, H, J, ... */
1759 <ssinit>C { /* Same deal if C packet comes again */
1763 <ssfile>Y { /* ACK for F or X packet */
1764 srvptr = srvcmd; /* Point to string buffer */
1765 decode(rdatap,putsrv,0); /* Decode data field, if any */
1766 putsrv(NUL); /* Terminate with null */
1767 ffc = 0L; /* Reset file byte counter */
1768 debug(F101,"<ssfile>Y cxseen","",cxseen);
1769 if (*srvcmd) { /* If remote name was recorded */
1770 if (sendmode != SM_RESEND) {
1771 if (fdispla == XYFD_C || fdispla == XYFD_S)
1772 xxscreen(SCR_AN,0,0L,(char *)srvcmd);
1773 tlog(F110," remote name:",(char *) srvcmd,0L);
1774 makestr(&psrfspec,(char *)srvcmd);
1777 if (cxseen||czseen) { /* Interrupted? */
1778 debug(F101,"<ssfile>Y canceling","",0);
1779 x = clsif(); /* Close input file */
1780 sxeof(1); /* Send EOF(D) */
1781 BEGIN sseof; /* and switch to EOF state. */
1782 } else if (atcapu) { /* If attributes are to be used */
1783 if (sattr(xflg | stdinf, 1) < 0) { /* send them */
1784 errpkt((CHAR *)"Can't send attributes"); /* if problem, say so */
1785 RESUME; /* and quit */
1786 } else BEGIN ssattr; /* if ok, switch to attribute state */
1787 } else { /* Attributes not negotiated */
1788 if (window(wslotn) < 0) { /* Open window */
1789 errpkt((CHAR *)"Can't open window");
1791 } else if ((x = sdata()) == -2) { /* Send first data packet data */
1792 window(1); /* Connection lost, reset window */
1793 x = clsif(); /* Close input file */
1794 return(success = 0); /* Return failure */
1795 } else if (x == -9) { /* User interrupted */
1796 errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1797 window(1); /* Set window size back to 1... */
1798 timint = s_timint; /* Restore timeout */
1799 return(success = 0); /* Failed */
1800 } else if (x < 0) { /* EOF (empty file) or interrupted */
1801 window(1); /* put window size back to 1, */
1802 debug(F101,"<ssfile>Y cxseen","",cxseen);
1803 x = clsif(); /* If not ok, close input file, */
1804 if (x < 0) /* treating failure as interruption */
1805 cxseen = 1; /* Send EOF packet */
1806 seof(cxseen||czseen);
1807 BEGIN sseof; /* and switch to EOF state. */
1808 } else { /* First data sent OK */
1809 BEGIN ssdata; /* All ok, switch to send-data state */
1814 <ssattr>Y { /* Got ACK to A packet */
1815 ffc = 0L; /* Reset file byte counter */
1816 debug(F101,"<ssattr>Y cxseen","",cxseen);
1817 if (cxseen||czseen) { /* Interrupted? */
1818 debug(F101,"<sattr>Y canceling","",0);
1819 x = clsif(); /* Close input file */
1820 sxeof(1); /* Send EOF(D) */
1821 BEGIN sseof; /* and switch to EOF state. */
1822 } else if (rsattr(rdatap) < 0) { /* Was the file refused? */
1823 discard = 1; /* Set the discard flag */
1824 clsif(); /* Close the file */
1825 sxeof(1); /* send EOF with "discard" code */
1826 BEGIN sseof; /* switch to send-EOF state */
1827 } else if ((x = sattr(xflg | stdinf, 0)) < 0) { /* Send more? */
1828 errpkt((CHAR *)"Can't send attributes"); /* Trouble... */
1830 } else if (x == 0) { /* No more to send so now the data */
1831 if (window(wslotn) < 0) { /* Allocate negotiated window slots */
1832 errpkt((CHAR *)"Can't open window");
1835 if ((x = sdata()) == -2) { /* File accepted, send first data */
1836 window(1); /* Connection broken */
1837 x = clsif(); /* Close file */
1838 return(success = 0); /* Return failure */
1839 } else if (x == -9) { /* User interrupted */
1840 errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1841 window(1); /* Set window size back to 1... */
1842 timint = s_timint; /* Restore timeout */
1843 return(success = 0); /* Failed */
1844 } else if (x < 0) { /* If data was not sent */
1845 window(1); /* put window size back to 1, */
1846 debug(F101,"<ssattr>Y cxseen","",cxseen);
1847 if (clsif() < 0) /* Close input file */
1848 cxseen = 1; /* Send EOF packet */
1849 seof(cxseen||czseen);
1850 BEGIN sseof; /* and switch to EOF state. */
1852 BEGIN ssdata; /* All ok, switch to send-data state */
1857 <ssdata>q { /* Ctrl-C or connection loss. */
1858 window(1); /* Set window size back to 1... */
1859 cxseen = 1; /* To indicate interruption */
1860 x = clsif(); /* Close file */
1861 return(success = 0); /* Failed */
1864 <ssdata>Y { /* Got ACK to Data packet */
1865 canned(rdatap); /* Check if file transfer cancelled */
1866 debug(F111,"<ssdata>Y cxseen",rdatap,cxseen);
1867 debug(F111,"<ssdata>Y czseen",rdatap,czseen);
1868 if ((x = sdata()) == -2) { /* Try to send next data */
1869 window(1); /* Connection lost, reset window */
1870 x = clsif(); /* Close file */
1871 return(success = 0); /* Failed */
1872 } else if (x == -9) { /* User interrupted */
1873 errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1874 window(1); /* Set window size back to 1... */
1875 timint = s_timint; /* Restore original timeout */
1876 return(success = 0); /* Failed */
1877 } else if (x < 0) { /* EOF - finished sending data */
1878 debug(F101,"<ssdata>Y cxseen","",cxseen);
1879 window(1); /* Set window size back to 1... */
1880 if (clsif() < 0) /* Close input file */
1881 cxseen = 1; /* Send EOF packet */
1882 debug(F101,"<ssdata>Y CALLING SEOF()","",cxseen);
1883 seof(cxseen||czseen);
1884 BEGIN sseof; /* and enter send-eof state */
1886 /* NOTE: If x == 0 it means we're draining: see sdata()! */
1889 <sseof>Y { /* Got ACK to EOF */
1891 canned(rdatap); /* Check if file transfer cancelled */
1892 debug(F111,"<sseof>Y cxseen",rdatap,cxseen);
1893 debug(F111,"<sseof>Y czseen",rdatap,czseen);
1894 debug(F111,"<sseof>Y discard",rdatap,discard);
1897 success = (cxseen == 0 && czseen == 0); /* Transfer status... */
1898 debug(F101,"<sseof>Y success","",success);
1899 if (success && rejection > 0) /* If rejected, succeed if */
1900 if (rejection != '#' && /* reason was date */
1901 rejection != 1 && rejection != '?') /* or name; */
1902 success = 0; /* fail otherwise. */
1903 cxseen = 0; /* This goes back to zero. */
1904 if (success) { /* Only if transfer succeeded... */
1905 xxscreen(SCR_ST,ST_OK,0L,"");
1907 makestr(&sfspec,psfspec); /* Record filenames for WHERE */
1908 makestr(&srfspec,psrfspec);
1910 if (moving) { /* If MOVE'ing */
1911 x = zdelet(filnam); /* Try to delete the source file */
1915 tlog(F110," deleted",filnam,0);
1917 tlog(F110," delete failed:",ck_errstr(),0);
1921 } else if (snd_move) { /* Or move it */
1923 x = zrename(filnam,snd_move);
1927 tlog(F110," moved to ",snd_move,0);
1929 tlog(F110," move failed:",ck_errstr(),0);
1933 } else if (snd_rename) { /* Or rename it */
1934 char *s = snd_rename; /* Renaming string */
1936 int y; /* Pass it thru the evaluator */
1937 extern int cmd_quoting; /* for \v(filename) */
1938 if (cmd_quoting) { /* But only if cmd_quoting is on */
1941 zzstring(snd_rename,&s,&y);
1947 x = zrename(filnam,s);
1951 tlog(F110," renamed to",s,0);
1953 tlog(F110," rename failed:",ck_errstr(),0);
1959 #endif /* COMMENT */
1963 if (czseen) { /* Check group interruption flag */
1964 g = 0; /* No more files if interrupted */
1965 } else { /* Otherwise... */
1967 /* This code makes any open error fatal to a file-group transfer. */
1969 debug(F111,"<sseof>Y gnfile",filnam,g);
1970 if (g > 0) { /* Any more files to send? */
1971 if (sfile(xflg)) /* Yes, try to send next file header */
1972 BEGIN ssfile; /* if ok, enter send-file state */
1973 else { /* otherwise */
1974 s = xflg ? "Can't execute command" : (char *)epktmsg;
1975 if (!*s) s = "Can't open file";
1976 errpkt((CHAR *)s); /* send error message */
1977 RESUME; /* and quit */
1979 } else { /* No next file */
1980 tsecs = gtimer(); /* get statistics timers */
1982 fptsecs = gftimer();
1983 #endif /* GFTIMER */
1984 seot(); /* send EOT packet */
1985 BEGIN sseot; /* enter send-eot state */
1988 while (1) { /* Keep trying... */
1989 g = gnfile(); /* Get next file */
1990 debug(F111,"<sseof>Y gnfile",filnam,g);
1991 if (g == 0 && gnferror == 0) /* No more, stop trying */
1993 if (g > 0) { /* Have one */
1994 if (sfile(xflg)) { /* Try to open and send F packet */
1995 BEGIN ssfile; /* If OK, enter send-file state */
1996 break; /* and break out of loop. */
1998 } /* Otherwise keep trying to get one we can send... */
2002 debug(F101,"<sseof>Y no more files","",czseen);
2003 tsecs = gtimer(); /* Get statistics timers */
2005 fptsecs = gftimer();
2006 #endif /* GFTIMER */
2007 seot(); /* Send EOT packet */
2008 BEGIN sseot; /* Enter send-eot state */
2010 #endif /* COMMENT */
2013 <sseot>Y { /* Got ACK to EOT */
2014 debug(F101,"sseot justone","",justone);
2015 RESUME; /* All done, just quit */
2018 E { /* Got Error packet, in any state */
2020 window(1); /* Close window */
2021 timint = s_timint; /* Restore original timeout */
2022 if (*epktmsg) /* Message from Error packet */
2023 s = (char *)epktmsg;
2024 if (!*s) { /* If not there then maybe here */
2026 ckstrncpy((char *)epktmsg,(char *)rdatap,PKTMSGLEN);
2028 if (!*s) /* Hopefully we'll never see this. */
2029 s = "Unknown error";
2030 success = 0; /* For IF SUCCESS/FAIL. */
2031 debug(F101,"ckcpro.w justone at E pkt","",justone);
2033 success = 0; /* Transfer failed */
2034 xferstat = success; /* Remember transfer status */
2036 x = quiet; quiet = 1; /* Close files silently, */
2037 epktrcvd = 1; /* Prevent messages from clsof() */
2039 clsof(1); /* discarding any output file. */
2040 ermsg(s); /* Issue the message (calls screen). */
2041 quiet = x; /* Restore quiet state */
2043 tstats(); /* Get stats */
2045 If we are executing commands from a command file or macro, let the command
2046 file or macro decide whether to exit, based on SET { TAKE, MACRO } ERROR.
2053 fatal("Protocol error");
2054 xitsta |= (what & W_KERMIT); /* Save this for doexit(). */
2056 /* If we were cd'd temporarily to another device or directory ... */
2059 x = zchdir((char *) savdir); /* ... restore previous directory */
2060 f_tmpdir = 0; /* and remember we did it. */
2061 debug(F111,"ckcpro.w E tmpdir restored",savdir,x);
2063 #endif /* CK_TMPDIR */
2065 if (ikdbopen) slotstate(what,"ERROR", (char *)epktmsg, "");
2070 q { success = 0; QUIT; } /* Ctrl-C or connection loss. */
2072 . { /* Anything not accounted for above */
2073 errpkt((CHAR *)"Unexpected packet type"); /* Give error message */
2075 xitsta |= (what & W_KERMIT); /* Save this for doexit(). */
2076 RESUME; /* and quit */
2082 From here down to proto() are routines that were moved out of the state
2083 table switcher because the resulting switch() had become too large.
2084 To move the contents of a state-table case to a routine:
2085 1. Add a prototype to the list above the state table switcher.
2086 2. Make a routine with an appropriate name, returning int.
2087 3. Move the code into it.
2088 4. Put a call to the new routine in the former spot:
2089 rc = name_of_routine();
2090 if (rc > -1) return(rc);
2091 5. Add "return(-1);" after every RESUME, SERVE, or BEGIN macro and
2092 at the end if the code is open-ended.
2097 debug(F101,"rcv_firstdata","",dispos);
2099 if (discard) { /* if we're discarding the file */
2100 ack1((CHAR *)"X"); /* just ack the data like this. */
2101 cancel++; /* and count it */
2102 BEGIN rdpkt; /* and wait for more data packets. */
2104 } else { /* Not discarding. */
2105 rf_err = "Can't open file";
2106 if (xflg) { /* If screen data */
2107 if (remfile) { /* redirected to file */
2108 if (rempipe) /* or pipe */
2109 x = openc(ZOFILE,remdest); /* Pipe: start command */
2111 x = opena(remdest,&iattr); /* File: open with attributes */
2112 } else { /* otherwise */
2113 x = opent(&iattr); /* "open" the screen */
2115 } else { /* otherwise */
2117 if (calibrate) { /* If calibration run */
2118 x = ckopenx(&iattr); /* open nothing */
2120 if (streaming) /* Streaming */
2121 fastack(); /* ACK without ACKing. */
2123 #endif /* STREAMING */
2124 ack(); /* Send real ACK */
2125 BEGIN rdpkt; /* Proceed to next state */
2128 #endif /* CALIBRATE */
2131 In UNIX we can pipe the file data into the mail program, which is to be
2132 preferred to writing it out to a temp file and then mailing it afterwards.
2133 This depends rather heavily on all UNIXes having a mail command that
2134 accepts '-s "subject"' on the command line. MAILCMD (e.g. mail, Mail, mailx)
2135 is defined in ckufio.c.
2137 if (dispos == 'M') { /* Mail... */
2141 extern char *MAILCMD;
2142 s = iattr.disp.val + 1;
2143 n = (int)strlen(MAILCMD) + /* Mail command */
2144 (int)strlen(s) + /* address */
2145 (int)strlen(ofilnam) + 32; /* subject */
2146 if (tmp = (char *)malloc(n)) {
2148 MAILCMD," -s \"",ofilnam,"\" ",s,
2149 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
2150 debug(F111,"rcv_firsdata mail",tmp,(int)strlen(tmp));
2151 x = openc(ZOFILE,(char *)tmp);
2155 } else if (dispos == 'P') { /* Ditto for print */
2158 extern char *PRINTCMD;
2159 n = (int)strlen(PRINTCMD) + (int)strlen(iattr.disp.val+1) + 4;
2160 if (tmp = (char *)malloc(n)) {
2161 sprintf(tmp, /* safe (prechecked) */
2162 "%s %s", PRINTCMD, iattr.disp.val + 1);
2163 x = openc(ZOFILE,(char *)tmp);
2169 x = opena(filnam,&iattr); /* open the file, with attributes */
2171 if (x) { /* If file was opened ok */
2180 rc = (binary && !parity) ?
2181 bdecode(rdatap,putfil):
2182 decode(rdatap, qf ? puttrm : putfil, 1);
2184 rc = decode(rdatap, qf ? puttrm : putfil, 1);
2185 #endif /* CKTUNING */
2187 errpkt((CHAR *)"Error writing data");
2192 if (streaming) /* Streaming was negotiated */
2193 fastack(); /* ACK without ACKing. */
2195 #endif /* STREAMING */
2196 ack(); /* acknowledge it */
2197 BEGIN rdpkt; /* and switch to receive-data state */
2199 } else { /* otherwise */
2200 errpkt((CHAR *) rf_err); /* send error packet */
2201 RESUME; /* and quit. */
2211 debug(F111,"rcv_shortreply",rdatap,ipktlen);
2212 if (ipktack[0] && !strncmp(ipktack,(char *)rdatap,ipktlen)) {
2213 /* No it's the ACK to the I packet again */
2214 x = scmd(vcmd,(CHAR *)cmarg); /* So send the REMOTE command again */
2215 /* Maybe this should be resend() */
2216 debug(F110,"IPKTZEROHACK",ipktack,x);
2218 errpkt((CHAR *)srimsg);
2224 #endif /* PKTZEROHACK */
2228 if (query) { /* If to query, */
2229 qbufp = querybuf; /* initialize query response buffer */
2235 if (remfile) { /* Response redirected to file */
2236 rf_err = "Can't open file";
2237 if (rempipe) /* or pipe */
2240 zxcmd(ZOFILE,remdest) /* Pipe: Start command */
2246 x = opena(remdest,&iattr); /* File: Open with attributes */
2247 debug(F111,"rcv_shortreply remfile",remdest,x);
2249 x = opent(&iattr); /* "open" the screen */
2251 if (x) { /* If file was opened ok */
2254 (query || !remfile) ? puttrm :
2258 zputfil, 1) < 0) { /* Note: zputfil, not putfil. */
2259 errpkt((CHAR *)"Error writing data");
2263 if (rdatap) /* If we had data */
2264 if (*rdatap) /* add a line terminator */
2265 if (remfile) { /* to file */
2267 } else { /* or to screen. */
2269 if (!query || !xcmdsrc)
2271 if (!(quiet && rcdactive))
2274 if (bye_active && network) { /* I sent BYE or REMOTE LOGOUT */
2275 msleep(500); /* command and got the ACK... */
2280 if (!epktsent && !epktrcvd) /* If no error packet... */
2281 success = 1; /* success. */
2285 } else { /* File not opened OK */
2286 errpkt((CHAR *) rf_err); /* send error message */
2287 RESUME; /* and quit. */
2290 #endif /* NOSERVER */
2293 #endif /* PKTZEROHACK */
2294 debug(F101,"rcv_shortreply fallthru","",success);
2305 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2306 cksyslog(SYSLG_PR, 1, "server", "REMOTE QUERY", (char *)srvcmd);
2307 #endif /* CKSYSLOG */
2309 if (ikdbopen) slotstate(what,"REMOTE QUERY", (char *)(srvcmd+2), "");
2311 c = *(srvcmd+2); /* Q = Query, S = Set */
2312 if (c == 'Q') { /* Query */
2313 if (!ENABLED(en_que)) { /* Security */
2314 errpkt((CHAR *)"REMOTE QUERY disabled");
2317 } else { /* Query allowed */
2319 qbufp = querybuf; /* Wipe out old stuff */
2322 p = (char *) srvcmd + 3; /* Pointer for making wrapper */
2323 n = strlen((char *)srvcmd); /* Position of end */
2324 c = *(srvcmd+4); /* Which type of variable */
2326 if (*(srvcmd+6) == CMDQ) { /* Starts with command quote? */
2327 p = (char *) srvcmd + 6; /* Take it literally */
2328 if (*p == CMDQ) p++;
2329 } else { /* They played by the rules */
2330 if (c == 'K') { /* Kermit variable */
2332 k = (int) strlen(p);
2333 if (k > 0 && p[k-1] == ')') {
2334 p = (char *)(srvcmd + 4);
2336 *(srvcmd+5) = 'f'; /* Function, so make it \f...() */
2338 *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
2339 *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */
2340 *(srvcmd+5) = '('; /* around variable name */
2342 *(srvcmd+n+1) = NUL;
2345 *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
2346 *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */
2347 *(srvcmd+5) = '('; /* around variable name */
2349 *(srvcmd+n+1) = NUL;
2350 if (c == 'S') { /* System variable */
2351 *(srvcmd+4) = '$'; /* so it's \$(...) */
2352 } else if (c == 'G') { /* Non-\ Global variable */
2353 *(srvcmd+4) = 'm'; /* so wrap it in \m(...) */
2356 } /* Now evaluate it */
2357 n = QBUFL; /* Max length */
2358 q = querybuf; /* Where to put it */
2359 if (zzstring(p,&q,&n) < 0) {
2360 errpkt((n > 0) ? (CHAR *)"Can't get value"
2361 : (CHAR *)"Value too long"
2366 if (encstr((CHAR *)querybuf) > -1) { /* Encode it */
2367 ack1(data); /* If it fits, send it back in ACK */
2371 } else if (sndstring(querybuf)) { /* Long form response */
2374 } else { /* sndhlp() fails */
2375 errpkt((CHAR *)"Can't send value");
2381 } else if (c == 'S') { /* Set (assign) */
2382 if (!ENABLED(en_asg)) { /* Security */
2383 errpkt((CHAR *)"REMOTE ASSIGN disabled");
2388 n = xunchar(*(srvcmd+3)); /* Length of name */
2389 n = 3 + n + 1; /* Position of length of value */
2390 *(srvcmd+n) = NUL; /* Don't need it */
2391 if (addmac((char *)(srvcmd+4),(char *)(srvcmd+n+1)) < 0)
2392 errpkt((CHAR *)"REMOTE ASSIGN failed");
2401 errpkt((CHAR *)"Badly formed server command");
2406 errpkt((CHAR *)"Variable query/set not available");
2410 #endif /* NOSERVER */
2417 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2418 cksyslog(SYSLG_PR, 1, "server", "REMOTE COPY", (char *)srvcmd);
2419 #endif /* CKSYSLOG */
2421 if (!ENABLED(en_cpy)) {
2422 errpkt((CHAR *)"REMOTE COPY disabled");
2426 char *str1, *str2, f1[256], f2[256];
2428 len1 = xunchar(srvcmd[1]); /* Separate the parameters */
2429 len2 = xunchar(srvcmd[2+len1]);
2430 strncpy(f1,(char *)(srvcmd+2),len1);
2432 strncpy(f2,(char *)(srvcmd+3+len1),len2);
2435 if (ikdbopen) slotstate(what,"REMOTE COPY", f1, f2);
2437 if (!ENABLED(en_cwd)) { /* If CWD is disabled */
2438 zstrip(f1,&str1); /* and they included a pathname, */
2440 if (strcmp(f1,str1) || strcmp(f2,str2)) { /* Refuse. */
2441 errpkt((CHAR *)"Access denied");
2442 RESUME; /* Remember, this is not a goto! */
2446 if (state == generic) { /* It's OK to go ahead. */
2447 if (zcopy(f1,f2)) { /* Try */
2448 errpkt((CHAR *)"Can't copy file"); /* give error message */
2453 RESUME; /* wait for next server command */
2458 #else /* no ZCOPY */
2459 errpkt((CHAR *)"REMOTE COPY not available"); /* give error message */
2460 RESUME; /* wait for next server command */
2463 #endif /* NOSERVER */
2470 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2471 cksyslog(SYSLG_PR, 1, "server", "REMOTE RENAME", (char *)srvcmd);
2472 #endif /* CKSYSLOG */
2474 if (!ENABLED(en_ren)) {
2475 errpkt((CHAR *)"REMOTE RENAME disabled");
2478 } else { /* RENAME is enabled */
2479 char *str1, *str2, f1[256], f2[256];
2481 len1 = xunchar(srvcmd[1]); /* Separate the parameters */
2482 len2 = xunchar(srvcmd[2+len1]);
2483 strncpy(f1,(char *)(srvcmd+2),len1);
2485 strncpy(f2,(char *)(srvcmd+3+len1),len2);
2487 len2 = xunchar(srvcmd[2+len1]);
2488 strncpy(f1,(char *)(srvcmd+2),len1);
2490 strncpy(f2,(char *)(srvcmd+3+len1),len2);
2493 if (ikdbopen) slotstate(what,"REMOTE RENAME", f1, f2);
2495 if (!ENABLED(en_cwd)) { /* If CWD is disabled */
2496 zstrip(f1,&str1); /* and they included a pathname, */
2498 if ( strcmp(f1,str1) || strcmp(f2,str2) ) { /* refuse. */
2499 errpkt((CHAR *)"Access denied");
2500 RESUME; /* Remember, this is not a goto! */
2504 if (state == generic) { /* It's OK to go ahead. */
2505 if (zrename(f1,f2)) { /* Try */
2506 errpkt((CHAR *)"Can't rename file"); /* Give error msg */
2511 RESUME; /* Wait for next server command */
2516 #else /* no ZRENAME */
2517 /* Give error message */
2518 errpkt((CHAR *)"REMOTE RENAME not available");
2519 RESUME; /* Wait for next server command */
2521 #endif /* ZRENAME */
2522 #endif /* NOSERVER */
2528 char f1[LOGINLEN+1], f2[LOGINLEN+1], f3[LOGINLEN+1];
2532 debug(F101,"REMOTE LOGIN x_login","",x_login);
2533 debug(F101,"REMOTE LOGIN x_logged","",x_logged);
2535 f1[0] = NUL; f2[0] = NUL; f3[0] = NUL;
2537 if (srvcmd[1]) /* First length field */
2538 len = xunchar(srvcmd[1]); /* Separate the parameters */
2540 if (x_login) { /* Login required */
2541 if (x_logged) { /* And already logged in */
2542 if (len > 0) { /* Logging in again */
2543 errpkt((CHAR *)"Already logged in.");
2544 } else { /* Logging out */
2545 debug(F101,"REMOTE LOGOUT","",x_logged);
2547 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2548 cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGOUT", NULL);
2549 #endif /* CKSYSLOG */
2551 if (ikdbopen) slotstate(what,"REMOTE LOGOUT", "", "");
2553 tlog(F110,"Logged out",x_user,0);
2554 ack1((CHAR *)"Logged out");
2563 #endif /* CK_LOGIN */
2565 } else { /* Not logged in yet */
2566 debug(F101,"REMOTE LOGIN len","",len);
2567 if (len > 0) { /* Have username */
2569 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2570 cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGIN", NULL);
2571 #endif /* CKSYSLOG */
2572 if (len > LOGINLEN) {
2573 errpkt((CHAR *)"Username too long");
2575 p = srvcmd + 2; /* Point to it */
2576 for (i = 0; i < len; i++) /* Copy it */
2578 f1[len] = NUL; /* Terminate it */
2579 p += len; /* Point to next length field */
2580 if (*p) { /* If we have one */
2581 len = xunchar(*p++); /* decode it */
2582 if (len > 0 && len <= LOGINLEN) {
2583 for (i = 0; i < len; i++) /* Same deal for password */
2586 p += len; /* And account */
2588 len = xunchar(*p++);
2589 if (len > 0 && len <= LOGINLEN) {
2590 for (i = 0; i < len; i++)
2591 f3[i] = p[i]; /* Set but never used */
2592 f3[len] = NUL; /* (because account not used) */
2597 debug(F101,"REMOTE LOGIN 1","",x_logged);
2600 if (inserver) { /* Log in to system for real */
2601 x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
2602 debug(F101,"REMOTE LOGIN 2","",x_logged);
2603 if (x_logged) { /* Count attempts */
2611 #endif /* CK_LOGIN */
2613 if (x_user && x_passwd) { /* User and password must match */
2614 if (!strcmp(x_user,f1)) /* SET SERVER LOGIN */
2615 if (!strcmp(x_passwd,f2))
2617 debug(F101,"REMOTE LOGIN 3","",x_logged);
2618 } else if (x_user) { /* Only username given, no password */
2619 if (!strcmp(x_user,f1)) /* so only username must match */
2621 debug(F101,"REMOTE LOGIN 4","",x_logged);
2625 x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
2626 debug(F101,"REMOTE LOGIN 5","",x_logged);
2628 #endif /* CK_LOGIN */
2629 if (x_logged) { /* Logged in? */
2630 tlog(F110,"Logged in", x_user, 0);
2632 ack1((CHAR *)"Logged in as guest - restrictions apply");
2634 ack1((CHAR *)"Logged in");
2637 tlog(F110,"Login failed", f1, 0);
2638 errpkt((CHAR *)"Access denied.");
2641 if (inserver && logtries > 2)
2643 #endif /* CK_LOGIN */
2646 } else { /* LOGOUT */
2647 errpkt((CHAR *)"Logout ignored");
2650 } else { /* Login not required */
2652 errpkt((CHAR *)"Login ignored.");
2654 errpkt((CHAR *)"Logout ignored.");
2656 #endif /* NOSERVER */
2663 /* K95 does this its own way */
2667 printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", srvidl);
2668 doexit(GOOD_EXIT,xitsta);
2672 printf("\r\nSERVER IDLE TIMEOUT: %d sec\r\n", srvidl);
2673 xitsta |= (what & W_KERMIT);
2677 else if (fatalio) { /* Connection lost */
2679 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2680 cksyslog(SYSLG_PR, 1, "server", "Connection lost", NULL);
2681 #endif /* CKSYSLOG */
2683 if (ikdbopen) slotstate(what,"SERVER DISCONNECT",(char *)srvcmd, "");
2687 } else if (interrupted) { /* Interrupted by hand */
2688 if (!ENABLED(en_fin)) {
2689 errpkt((CHAR *)"QUIT disabled");
2693 if (what == W_SEND || what == W_RECV || what == W_REMO) {
2696 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2697 cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
2698 #endif /* CKSYSLOG */
2699 } else if (what == W_NOTHING && filcnt == 0) {
2701 } /* Otherwise leave success alone */
2702 xitsta |= (what & W_KERMIT);
2705 } else { /* Shouldn't happen */
2706 debug(F100,"SERVER (top) GOT UNEXPECTED 'q'","",0);
2709 #endif /* NOSERVER */
2717 if (/* state == serve && */ x_login && !x_logged) {
2718 errpkt((CHAR *)"Login required");
2721 #endif /* NOSERVER */
2722 if (state == serve && !ENABLED(en_sen)) { /* Not in server mode */
2723 errpkt((CHAR *)"SEND disabled"); /* when SEND is disabled. */
2726 } else { /* OK to go ahead. */
2728 if (dldir && !f_tmpdir) { /* If they have a download directory */
2729 debug(F110,"receive download dir",dldir,0);
2730 if (s = zgtdir()) { /* Get current directory */
2731 debug(F110,"receive current dir",s,0);
2732 if (zchdir(dldir)) { /* Change to download directory */
2733 debug(F100,"receive zchdir ok","",0);
2734 ckstrncpy(savdir,s,TMPDIRLEN);
2735 f_tmpdir = 1; /* Remember that we did this */
2737 debug(F100,"receive zchdir failed","",0);
2740 #endif /* CK_TMPDIR */
2741 nakstate = 1; /* Can send NAKs from here. */
2742 rinit(rdatap); /* Set parameters */
2747 bctu = bctr; /* switch to agreed-upon block check */
2748 bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
2750 what = W_RECV; /* Remember we're receiving */
2752 resetc(); /* Reset counters */
2753 rtimer(); /* Reset timer */
2756 #endif /* GFTIMER */
2758 BEGIN rfile; /* Go into receive-file state */
2764 /* END OF ROUTINES MOVED OUT OF STATE MACHINE */
2767 /* P R O T O -- Protocol entry function */
2769 static int is_tn = 0; /* It's a Telnet connection */
2772 int f_ctlp = 0; /* Control-character prefix table */
2775 #endif /* COMMENT */
2776 #endif /* CK_SPEED */
2779 This is simply a wrapper for the real protocol function just below,
2780 that saves any items that might be changed automatically by protocol
2781 negotiations and then restores them upon exit from protocol mode.
2785 extern int b_save, f_save, c_save, ss_save, slostart, reliable, urclear;
2787 extern int fcharset, fcs_save, tcharset, tcs_save;
2788 #endif /* NOCSETS */
2791 extern int pipesend;
2792 #endif /* PIPESEND */
2795 extern int cursorena[], cursor_save, term_io;
2797 extern int display_demo;
2800 #endif /* NOLOCAL */
2802 int _u_bin=0, _me_bin = 0;
2804 int /* _u_start=0, */ _me_start = 0;
2805 #endif /* IKS_OPTION */
2810 #endif /* PATTERNS */
2815 #endif /* PATTERNS */
2816 scan_save = filepeek;
2821 if (isguest) { /* If user is anonymous */
2822 en_pri = 0; /* disable printing */
2823 en_mai = 0; /* and disable email */
2824 en_del = 0; /* and file deletion */
2826 #endif /* CK_LOGIN */
2830 cursor_save = cursorena[vmode];
2831 cursorena[vmode] = 0;
2832 term_io_save = term_io;
2835 #endif /* NOLOCAL */
2836 b_save = binary; /* SET FILE TYPE */
2837 f_save = fncnv; /* SET FILE NAMES */
2844 fcs_save = fcharset;
2845 tcs_save = tcharset;
2846 #endif /* NOCSETS */
2849 /* Don't do this because then user can never find out what happened. */
2851 for (i = 0; i < 256; i++)
2852 s_ctlp[i] = ctlp[i];
2854 #endif /* CK_SPEED */
2855 #endif /* COMMENT */
2856 if (reliable == SET_ON)
2858 is_tn = (!local && sstelnet)
2860 || (local && network && ttnproto == NP_TELNET)
2865 if (tn_b_xfer && !(sstelnet || inserver)) {
2866 /* Save the current state of Telnet Binary */
2867 _u_bin = TELOPT_U(TELOPT_BINARY);
2868 _me_bin = TELOPT_ME(TELOPT_BINARY);
2870 /* If either direction is not Binary attempt to negotiate it */
2871 if (!_u_bin && TELOPT_U_MODE(TELOPT_BINARY) != TN_NG_RF) {
2872 tn_sopt(DO,TELOPT_BINARY);
2873 TELOPT_UNANSWERED_DO(TELOPT_BINARY) = 1;
2875 if (!_me_bin && TELOPT_ME_MODE(TELOPT_BINARY) != TN_NG_RF) {
2876 tn_sopt(WILL,TELOPT_BINARY);
2877 TELOPT_UNANSWERED_WILL(TELOPT_BINARY) = 1;
2879 if (!(_me_bin && _u_bin))
2880 tn_wait("proto set binary mode");
2884 if (protocol != PROTO_K) { /* Non-Kermit protocol selected */
2885 if (TELOPT_U(TELOPT_KERMIT) &&
2886 TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2887 iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
2890 if (TELOPT_ME(TELOPT_KERMIT) &&
2891 TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2892 tn_siks(KERMIT_STOP); /* I'm not servering */
2893 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2898 if (sstate == 'x' || sstate == 'v') { /* Responding to a request */
2899 if (!inserver && TELOPT_U(TELOPT_KERMIT) &&
2900 TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2901 iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
2904 if (TELOPT_ME(TELOPT_KERMIT) &&
2905 !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2906 tn_siks(KERMIT_START); /* Send Kermit-Server Start */
2907 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1;
2909 } else { /* Initiating a request */
2910 if (TELOPT_ME(TELOPT_KERMIT) &&
2911 TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2912 tn_siks(KERMIT_STOP); /* I'm not servering */
2913 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2916 if (TELOPT_U(TELOPT_KERMIT) &&
2917 !TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2918 /* Send Req-Server-Start */
2919 if (!iks_wait(KERMIT_REQ_START,0)) {
2920 if (sstate != 's') {
2921 success = 0; /* Other Kermit refused to serve */
2923 printf("A Kermit Server is not available\r\n");
2924 debug(F110,"proto()",
2925 "A Kermit Server is not available",0);
2926 tlog(F110,"IKS client/server failure",
2927 "A Kermit Server is not available",0);
2933 #endif /* IKS_OPTION */
2934 #ifdef CK_ENCRYPTION
2935 if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
2938 #endif /* CK_ENCRYPTION */
2942 if (!xfrint) connoi();
2943 xxproto(); /* Call the real protocol function */
2947 #endif /* IKS_OPTION */
2948 xferstat = success; /* Remember transfer status */
2952 #ifdef CK_ENCRYPTION
2953 if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
2956 #endif /* CK_ENCRYPTION */
2958 if (TELOPT_ME(TELOPT_KERMIT) &&
2959 TELOPT_SB(TELOPT_KERMIT).kermit.me_start && !_me_start) {
2960 tn_siks(KERMIT_STOP); /* Server is stopped */
2961 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2963 #endif /* IKS_OPTION */
2964 if (is_tn && tn_b_xfer && !(sstelnet || inserver)) {
2965 /* if we negotiated Binary mode try to reset it */
2967 /* Check to see if the state changed during the transfer */
2968 if (TELOPT_U(TELOPT_BINARY)) {
2969 tn_sopt(DONT,TELOPT_BINARY);
2970 TELOPT_UNANSWERED_DONT(TELOPT_BINARY) = 1;
2972 _u_bin = 1; /* So we don't call tn_wait() */
2975 /* Check to see if the state changed during the transfer */
2976 if (TELOPT_ME(TELOPT_BINARY)) {
2977 tn_sopt(WONT,TELOPT_BINARY);
2978 TELOPT_UNANSWERED_WONT(TELOPT_BINARY) = 1;
2980 _me_bin = 1; /* So we don't call tn_wait() */
2982 if (!(_me_bin && _u_bin))
2983 tn_wait("proto reset binary mode");
2989 #endif /* PATTERNS */
2990 filepeek = scan_save;
2995 #endif /* STREAMING */
2998 for (i = 0; i < 256; i++)
2999 ctlp[i] = s_ctlp[i];
3001 #endif /* CK_SPEED */
3002 #endif /* COMMENT */
3005 xitsta |= (what & W_KERMIT);
3006 tlog(F110," failed:",(char *)epktmsg,0);
3008 debug(F111,"proto xferstat",epktmsg,xferstat);
3010 if (s_timint > -1) { /* Because of REMOTE SET */
3016 if (c_save > -1) { /* Because of REMOTE SET */
3023 pipesend = 0; /* Next time might not be pipesend */
3024 #endif /* PIPESEND */
3027 cursorena[vmode] = cursor_save;
3028 term_io = term_io_save;
3031 #endif /* NOLOCAL */
3040 _PROTOTYP( int pxyz, (int) );
3041 #endif /* XYZ_INTERNAL */
3044 char xss[2]; /* String representation of sstate */
3049 debug(F101,"xxproto entry justone","",justone);
3052 retrieve = 0; /* Reset these ... */
3056 if (local && ttchk() < 0) { /* Giving BYE or FIN */
3057 if (bye_active) { /* but there is no connection */
3062 /* Ditto for any REMOTE command */
3063 if (sstate == 'g' && cmarg ) {
3064 if (*cmarg == 'L' || *cmarg == 'F' || *cmarg == 'X')
3067 printf("?No connection\r\n");
3072 /* Set up the communication line for file transfer. */
3073 /* NOTE: All of the xxscreen() calls prior to the wart() invocation */
3074 /* could just as easily be printf's or, for that matter, hints. */
3076 if (local && (speed < 0L) && (network == 0)) {
3077 xxscreen(SCR_EM,0,0L,"Sorry, you must 'set speed' first");
3081 if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {
3082 debug(F111,"failed: proto ttopen local",ttname,local);
3083 xxscreen(SCR_EM,0,0L,"Can't open line");
3086 if (x > -1) local = x;
3087 debug(F111,"proto ttopen local",ttname,local);
3089 lx = (local && !network) ? speed : -1;
3093 ctlp[(unsigned)255] = ctlp[CR] = 1;
3094 if (parity == 'e' || parity == 'm') ctlp[127] = 1;
3095 if (flow == FLO_XONX) { /* Also watch out for Xon/Xoff */
3096 ctlp[17] = ctlp[19] = 1;
3097 ctlp[17+128] = ctlp[19+128] = 1;
3100 #endif /* CK_SPEED */
3101 #endif /* NETCONN */
3102 if (ttpkt(lx,flow,parity) < 0) { /* Put line in packet mode, */
3103 xxscreen(SCR_EM,0,0L,"Can't condition line");
3106 if (local && !network && carrier != CAR_OFF) {
3107 int x; /* Serial connection */
3108 x = ttgmdm(); /* with carrier checking */
3110 if (!(x & BM_DCD)) {
3111 debug(F101,"proto ttgmdm","",0);
3112 xxscreen(SCR_EM,0,0L,"Carrier required but not detected");
3117 /* Send remote side's "receive" or "server" startup string, if any */
3118 if (local && ckindex((char *)xss,"srgcjhk",0,0,1)) {
3122 /* Don't send auto-blah string if we know other side is serving */
3123 !TELOPT_U(TELOPT_KERMIT) ||
3124 !TELOPT_SB(TELOPT_KERMIT).kermit.u_start
3127 #endif /* IKS_OPTION */
3129 if (sstate == 's') { /* Sending file(s) */
3130 s = binary ? ptab[protocol].h_b_init : ptab[protocol].h_t_init;
3131 } else if (protocol == PROTO_K) { /* Command for server */
3132 s = ptab[protocol].h_x_init;
3136 #ifndef UNPREFIXZERO
3137 if (protocol == PROTO_K) /* Because of C-strings... */
3139 #endif /* UNPREFIXZERO */
3140 #endif /* CK_SPEED */
3141 if (s) if (*s) { /* If we have a command to send... */
3143 int tmpbufsiz = 356;
3144 int stuff = -1, stuff2 = -1, len = 0;
3146 if (sstate == 's') { /* Sending file(s) */
3148 if (protocol == PROTO_X) {
3150 s2 = cmarg2[0] ? cmarg2 : cmarg;
3151 if ((int)strlen(s) + (int)strlen(s2) + 4 < 356)
3152 sprintf(tmpbuf, s, s2);
3157 ckmakmsg(tmpbuf, 356, s, NULL, NULL, NULL);
3161 } else { /* Command for server */
3162 ckstrncpy(tmpbuf,s,356);
3164 ckstrncat(tmpbuf, "\015",sizeof(tmpbuf));
3165 if (tnlm) /* TERMINAL NEWLINE ON */
3166 stuff = LF; /* Stuff LF */
3168 /* TELNET NEWLINE MODE */
3170 switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) {
3186 if (network && ttnproto == NP_RLOGIN) {
3187 switch (tn_b_nlm) { /* Always BINARY */
3200 #endif /* RLOGCODE */
3201 #endif /* TCPSOCKET */
3202 #endif /* NETCONN */
3204 len = strlen(tmpbuf);
3205 if (stuff >= 0 && len < tmpbufsiz - 1) {
3206 tmpbuf[len++] = stuff;
3207 if (stuff2 >= 0 && len < tmpbufsiz - 1)
3208 tmpbuf[len++] = stuff2;
3211 ttol((CHAR *)tmpbuf,len);
3212 if (protocol == PROTO_K) /* Give remote Kermit time to start */
3218 if (protocol != PROTO_K) { /* Non-Kermit protocol selected */
3220 int tmpbufsiz = 356;
3224 if (sstate == 'v') { /* If receiving and... */
3225 if (dldir && !f_tmpdir) { /* if they have a download directory */
3226 if (s = zgtdir()) { /* Get current directory */
3227 if (zchdir(dldir)) { /* Change to download directory */
3228 ckstrncpy(savdir,s,TMPDIRLEN);
3229 f_tmpdir = 1; /* Remember that we did this */
3234 #endif /* CK_TMPDIR */
3236 #ifdef XYZ_INTERNAL /* Internal */
3237 success = !pxyz(sstate);
3239 #ifdef CK_REDIR /* External */
3241 case 's': /* 'Tis better to SEND... */
3242 s = binary ? ptab[protocol].p_b_scmd : ptab[protocol].p_t_scmd;
3244 case 'v': /* ... than RECEIVE */
3245 s = binary ? ptab[protocol].p_b_rcmd : ptab[protocol].p_t_rcmd;
3250 if (sstate == 's') { /* Sending */
3251 extern int xfermode;
3252 int k = 0, x = 0, b = binary;
3254 If just one file we can scan it to set the xfer mode.
3255 Otherwise it's up to the external protocol program.
3257 if (patterns && xfermode == XMODE_A && !iswild(fspec)) {
3258 extern int nscanfile;
3259 k = scanfile(fspec,&x,nscanfile);
3261 b = (k == FT_BIN) ? XYFT_B : XYFT_T;
3263 ptab[protocol].p_b_scmd :
3264 ptab[protocol].p_t_scmd;
3267 if ((int)strlen(s) + (int)strlen(fspec) < tmpbufsiz) {
3268 sprintf(tmpbuf,s,fspec); /* safe (prechecked) */
3269 tlog(F110,"Sending",fspec,0L);
3271 } else { /* Receiving */
3272 if ((int)strlen(s) + (int)strlen(cmarg2) < tmpbufsiz) {
3273 sprintf(tmpbuf,s,cmarg2); /* safe (prechecked) */
3274 tlog(F110,"Receiving",cmarg2,0L);
3277 tlog(F110," via external protocol:",tmpbuf,0);
3278 debug(F110,"ckcpro ttruncmd",tmpbuf,0);
3279 success = ttruncmd(tmpbuf);
3280 tlog(F110," status:",success ? "OK" : "FAILED", 0);
3282 printf("?Sorry, no external protocol defined for %s\r\n",
3283 ptab[protocol].p_name
3288 "Sorry, only Kermit protocol is supported in this version of Kermit\n"
3290 #endif /* CK_REDIR */
3291 #endif /* XYZ_INTERNAL */
3301 connoi(); /* No console interrupts if remote */
3305 if (sstate == 'x') { /* If entering server mode, */
3306 extern int howcalled;
3307 server = 1; /* set flag, */
3308 debug(F101,"server backgrd","",backgrd);
3309 debug(F101,"server quiet","",quiet);
3310 debug(F100,"SHOULD NOT SEE THIS IF IN BACKGROUND!","",0);
3311 if (howcalled == I_AM_SSHSUB) { /* and issue appropriate message. */
3312 ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
3313 } else if (!local) {
3314 if (!quiet && !backgrd
3316 && !TELOPT_ME(TELOPT_KERMIT) /* User was told by negotiation */
3317 #endif /* IKS_OPTION */
3320 conoll("KERMIT READY TO SERVE...");
3323 conol("Entering server mode on ");
3325 conoll("Type Ctrl-C to quit.");
3326 if (srvdis) intmsg(-1L);
3329 if (network && tcpsrfd > 0)
3330 ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
3331 #endif /* NOLISTEN */
3332 #endif /* TCPSOCKET */
3337 if (!quiet && !backgrd) /* So message doesn't overwrite prompt */
3339 if (local) conres(); /* So Ctrl-C will work */
3342 If in remote mode, not shushed, not in background, and at top command level,
3343 issue a helpful message telling what to do...
3345 if (!local && !quiet && !backgrd) {
3346 if (sstate == 'v') {
3347 conoll("Return to your local Kermit and give a SEND command.");
3349 conoll("KERMIT READY TO RECEIVE...");
3350 } else if (sstate == 's') {
3351 conoll("Return to your local Kermit and give a RECEIVE command.");
3353 conoll("KERMIT READY TO SEND...");
3354 } else if ( sstate == 'g' || sstate == 'r' || sstate == 'h' ||
3355 sstate == 'j' || sstate == 'c' ) {
3356 conoll("Return to your local Kermit and give a SERVER command.");
3358 conoll((sstate == 'r' || sstate == 'j' || sstate == 'h') ?
3359 "KERMIT READY TO GET..." :
3360 "KERMIT READY TO SEND SERVER COMMAND...");
3364 if (!local) sleep(1);
3365 #endif /* COMMENT */
3367 The 'wart()' function is generated by the wart program. It gets a
3368 character from the input() routine and then based on that character and
3369 the current state, selects the appropriate action, according to the state
3370 table above, which is transformed by the wart program into a big case
3371 statement. The function is active for one transaction.
3373 rtimer(); /* Reset elapsed-time timer */
3376 #endif /* GFTIMER */
3377 resetc(); /* & other per-transaction counters. */
3379 debug(F101,"proto calling wart, justone","",justone);
3381 wart(); /* Enter the state table switcher. */
3383 Note: the following is necessary in case we have just done a remote-mode
3384 file transfer, in which case the controlling terminal modes have been
3385 changed by ttpkt(). In particular, special characters like Ctrl-C and
3386 Ctrl-\ might have been turned off (see ttpkt). So this call to ttres() is
3387 essential. IMPORTANT: restore interrupt handlers first, otherwise any
3388 terminal interrupts that occur before this is done in the normal place
3389 later will cause a crash.
3392 ttres(); /* Reset the communication device */
3395 setint(); /* Arm interrupt handlers FIRST */
3397 ttres(); /* Then restore terminal. */
3400 xxscreen(SCR_TC,0,0L,""); /* Transaction complete */
3403 clsif(); /* Failsafe in case we missed */
3404 clsof(1); /* a case in the state machine. */
3407 if (server) { /* Back from packet protocol. */
3408 if (!quiet && !backgrd
3412 ) { /* Give appropriate message */
3414 conoll("C-Kermit server done");
3416 server = 0; /* Not a server any more */
3420 /* S G E T I N I T -- Handle incoming GET-Class packets */
3425 0: GET packet processed OK - ready to Send.
3426 1: Extended GET processed OK - wait for another.
3429 sgetinit(reget,xget) int reget, xget; { /* Server end of GET command */
3430 char * fs = NULL; /* Pointer to filespec */
3433 extern int usepipes, pipesend;
3434 #endif /* PIPESEND */
3437 if (!ENABLED(en_get)) { /* Only if not disabled! */
3438 errpkt((CHAR *)"GET disabled");
3444 nolinks = recursive;
3448 /* If they are alike this was already done in whoarewe() */
3449 debug(F101,"sgetinit whatru","",whatru);
3450 if (whatru & WMI_FLAG) { /* Did we get WHATAMI info? */
3451 debug(F101,"sgetinit binary (1)","",binary);
3453 if (binary != XYFT_I && binary != XYFT_L)
3456 if (binary != XYFT_L)
3459 binary = (whatru & WMI_FMODE) ? /* Yes, set file type */
3460 XYFT_B : XYFT_T; /* automatically */
3461 debug(F101,"sgetinit binary (2)","",binary);
3463 fncnv = (whatru & WMI_FNAME) ? 1 : 0; /* And name conversion */
3465 #endif /* WHATAMI */
3467 fs = (char *)srvcmd;
3468 srvptr = srvcmd; /* Point to server command buffer */
3469 decode(rdatap,putsrv,0); /* Decode the GET command into it */
3470 /* Accept multiple filespecs */
3471 cmarg2 = ""; /* Don't use cmarg2 */
3472 cmarg = ""; /* Don't use cmarg */
3474 done = 1; /* Only 1 packet needed... */
3475 if (xget) { /* Special decoding for Extended GET */
3476 char L, next, c; /* PLV items */
3477 int len, val; /* More PLV items */
3478 char * p = (char *)srvcmd; /* String to decode */
3480 done = 0; /* Maybe more packets needed */
3481 fs = NULL; /* We don't know the filespec yet */
3482 c = *p++; /* Get first parameter */
3484 while (c) { /* For all parameters... */
3485 debug(F000,"sgetinit c","",c);
3486 L = *p++; /* Get length */
3487 if (L >= SP) /* Decode length */
3489 else if (c == '@') { /* Allow missing EOP length field */
3492 len = (xunchar(*p++) * 95);
3493 len += xunchar(*p++);
3495 debug(F101,"sgetinit len","",len);
3496 next = *(p+len); /* Get next parameter */
3497 *(p+len) = NUL; /* Zero it out to terminal value */
3498 debug(F110,"sgetinit p",p,0);
3499 switch (c) { /* Do the parameter */
3500 case 'O': /* GET Options */
3501 val = atoi(p); /* Convert to int */
3502 debug(F101,"sgetinit O val","",val);
3503 if (val & GOPT_DEL) moving = 1;
3504 if (val & GOPT_RES) reget = 1;
3505 if (val & GOPT_REC) {
3508 if (fnspath == PATH_OFF)
3512 case 'M': /* Transfer Mode */
3514 debug(F101,"sgetinit M val","",val);
3517 patterns = 0; /* Takes precedence over patterns */
3518 filepeek = 0; /* and FILE SCAN */
3519 if (val == GMOD_TXT) binary = XYFT_T; /* Text */
3520 if (val == GMOD_BIN) binary = XYFT_B; /* Binary */
3521 if (val == GMOD_LBL) binary = XYFT_L; /* Labeled */
3523 case 'F': /* Filename */
3525 debug(F110,"sgetinit filename",fs,0);
3527 case '@': /* End Of Parameters */
3529 debug(F100,"sgetinit EOP","",0);
3532 errpkt((CHAR *)"Unknown GET Parameter");
3533 debug(F100,"sgetinit unknown parameter","",0);
3540 if (!fs) fs = ""; /* A filename is required */
3543 n = 0; /* Check for quoted name */
3544 if ((n = strlen(fs)) > 1) {
3545 /* Note: this does not allow for multiple quoted names */
3546 if ((fs[0] == '{' && fs[n-1] == '}') ||
3547 (fs[0] == '"' && fs[n-1] == '"')) {
3550 debug(F111,"sgetinit unquoted filename",fs,n);
3552 n = 0; /* This means no quoting */
3556 debug(F111,"sgetinit",fs,usepipes);
3557 if (usepipes && ENABLED(en_hos) && *fs == '!') {
3558 cmarg = fs + 1; /* Point past the bang */
3562 debug(F111,"sgetinit pipesend",cmarg,pipesend);
3564 if (!pipesend) { /* If it's not a pipe */
3565 #endif /* PIPESEND */
3566 if (n == 0) { /* If the name was not quoted */
3568 nfils = fnparse(fs); /* Allow it to be a list of names */
3569 debug(F111,"sgetinit A",fs,nfils);
3571 /* This doesn't work if a GET-PATH is set. */
3572 if (nfils == 1 && !iswild(fs)) { /* Single file */
3574 if ((x = zchki(fs)) < 0) { /* Check if it's sendable */
3576 case -1: m = "File not found"; break;
3577 case -2: m = "Not a regular file"; break;
3578 case -3: m = "Read access denied"; break;
3584 #endif /* COMMENT */
3585 } else { /* If it was quoted */
3586 #endif /* NOMSEND */
3589 if (matchdot) nzxopts |= ZX_MATCHDOT;
3590 #endif /* UNIXOROSK */
3591 if (recursive) nzxopts |= ZX_RECURSE;
3592 /* Treat as a single filespec */
3593 nfils = 0 - nzxpand(fs,nzxopts);
3594 debug(F111,"sgetinit B",fs,nfils);
3599 #endif /* PIPESEND */
3601 if (!done) { /* Need more O packets... */
3602 debug(F100,"sgetinit O-Packet TBC","",0); /* To Be Continued */
3605 debug(F100,"sgetinit O-Packet done - havefs","",havefs);
3606 if (!havefs) { /* Done - make sure we have filename */
3607 errpkt((CHAR *)"GET without filename");
3611 winlo = 0; /* Back to packet 0 again. */
3612 debug(F101,"sgetinit winlo","",winlo);
3613 nakstate = 0; /* Now I'm the sender! */
3614 if (reget) sendmode = SM_RESEND;
3615 if (sinit() > 0) { /* Send Send-Init */
3618 #endif /* STREAMING */
3619 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
3620 return(0); /* If successful, switch state */
3621 } else return(-1); /* Else back to server command wait */