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, carrier, fnspath, interrupted;
65 extern int recursive, inserver, nzxopts, idletmo, srvidl, xfrint;
66 extern struct ck_p ptab[];
67 extern int remfile, rempipe, xferstat, filestatus, wearealike, fackpath;
68 extern int patterns, filepeek, gnferror;
69 extern char * remdest;
73 static char ipktack[PKTZEROLEN];
74 static int ipktlen = 0;
75 #endif /* PKTZEROHACK */
77 static int s_timint = -1; /* For saving timeout value */
79 static int havefs = 0;
81 static int logtries = 0;
84 static int cancel = 0;
88 extern int streaming, streamok;
93 debug(F100,"streamon","",0);
95 timint = 0; /* No timeouts while streaming. */
99 #ifdef COMMENT /* (not used) */
103 debug(F100,"streamoff","",0);
105 timint = s_timint; /* Restore timeout */
109 #else /* STREAMING */
112 #endif /* STREAMING */
115 _PROTOTYP( int addmac, (char *, char *) );
116 _PROTOTYP( int zzstring, (char *, char **, int *) );
119 _PROTOTYP( int cmdsrc, (void) );
123 extern char * x_user, * x_passwd, * x_acct;
124 extern int x_login, x_logged;
125 #endif /* NOSERVER */
130 extern int ttnproto; /* Network protocol */
134 extern short ctlp[]; /* Control-character prefix table */
135 #endif /* CK_SPEED */
138 extern int tn_b_nlm, tn_b_xfer, tn_nlm;
140 extern int tn_no_encrypt_xfer;
141 #endif /* CK_ENCRYPTION */
147 #endif /* NOLISTEN */
148 #endif /* TCPSOCKET */
150 extern int cxseen, czseen, server, srvdis, local, displa, bctu, bctr, bctl;
152 extern int quiet, tsecs, parity, backgrd, nakstate, atcapu, wslotn, winlo;
153 extern int wslots, success, xitsta, rprintf, discard, cdtimo, keep, fdispla;
154 extern int timef, stdinf, rscapu, sendmode, epktflg, epktrcvd, epktsent;
155 extern int binary, fncnv, dest;
156 extern long speed, crc16;
157 CK_OFF_T calibrate, ffc;
159 extern char *TYPCMD, *DIRCMD, *DIRCM2;
162 extern char *SPACMD, *SPACM2, *WHOCMD;
165 extern struct zattr iattr;
172 extern CKFLOAT fptsecs;
176 extern CHAR *epktmsg;
179 extern int f_tmpdir; /* Directory changed temporarily */
180 extern char savdir[]; /* For saving current directory */
182 #endif /* CK_TMPDIR */
184 extern int query; /* Query-active flag */
187 char querybuf[QBUFL+1] = { NUL, NUL }; /* QUERY response buffer */
188 char *qbufp = querybuf; /* Pointer to it */
189 int qbufn = 0; /* Length of data in it */
198 If the following flag is nonzero when the protocol module is entered,
199 then server mode persists for exactly one transaction, rather than
200 looping until BYE or FINISH is received.
204 static int r_save = -1;
205 static int p_save = -1;
207 /* Function to let remote-mode user know where their file(s) went */
209 int whereflg = 1; /* Unset with SET XFER REPORT */
217 debug(F101,"wheremsg n","",n);
219 debug(F110,"wheremsg prfspec",prfspec,0);
220 debug(F110,"wheremsg rfspec",rfspec,0);
221 debug(F110,"wheremsg psfspec",psfspec,0);
222 debug(F110,"wheremsg sfspec",sfspec,0);
224 debug(F110,"wheremsg prrfspec",prrfspec,0);
225 debug(F110,"wheremsg rrfspec",rrfspec,0);
226 debug(F110,"wheremsg psrfspec",psrfspec,0);
227 debug(F110,"wheremsg srfspec",srfspec,0);
229 if (!quiet && !local) {
234 printf(" SENT: [%s]",sfspec);
236 printf(" To: [%s]",srfspec);
237 printf(" (%s)\r\n", success ? "OK" : "FAILED");
243 printf(" RCVD: [%s]",rrfspec);
245 printf(" To: [%s]",rfspec);
246 printf(" (%s)\r\n", success ? "OK" : "FAILED");
253 printf(" SENT: (%ld files)",n);
255 printf(" Last: [%s]",srfspec);
256 printf(" (%s)\r\n", success ? "OK" : "FAILED");
262 printf(" RCVD: (%ld files)",n);
264 printf(" Last: [%s]",rfspec);
265 printf(" (%s)\r\n", success ? "OK" : "FAILED");
270 printf(" SENT: (0 files) \r\n");
271 else if (myjob == 'r' || myjob == 'v')
272 printf(" RCVD: (0 files) \r\n");
280 debug(F111,"RESUME","server=1",justone);
282 debug(F111,"RESUME","server=0",justone);
285 /* Flags for the ENABLE and DISABLE commands */
287 en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri,
288 en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, en_ret, en_xit,
291 extern int en_asg, en_que;
293 extern int what, lastxfer;
295 /* Global variables declared here */
297 int whatru = 0; /* What are you. */
298 int whatru2 = 0; /* What are you, cont'd. */
300 /* Local variables */
302 static char vstate = 0; /* Saved State */
303 static char vcmd = 0; /* Saved Command */
304 static int reget = 0; /* Flag for executing REGET */
305 static int retrieve = 0; /* Flag for executing RETRIEVE */
306 static int opkt = 0; /* Send Extended GET packet */
308 static int x; /* General-purpose integer */
309 static char *s; /* General-purpose string pointer */
311 /* Macros - Note, BEGIN is predefined by Wart (and Lex) as "state = ", */
312 /* BEGIN is NOT a GOTO! */
313 #define TINIT if (tinit(1) < 0) return(-9)
314 #define SERVE { TINIT; resetc(); nakstate=1; what=W_NOTHING; cmarg2=""; \
315 sendmode=SM_SEND; havefs=0; recursive=r_save; fnspath=p_save; BEGIN serve; }
316 #define RESUME { rdebug(); if (!server) { wheremsg(); return(0); } else \
317 if (justone) { justone=0; wheremsg(); return(0); } else { SERVE; } }
320 #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); \
321 fptsecs=gftimer(); quiet=x; return(success)
323 #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); quiet=x; \
328 By late 1999, the big switch() statement generated from the following state
329 table began choking even gcc, so here we extract the code from the larger
330 states into static routines to reduce the size of the cases and the
331 switch() overall. The routines follow the state table; the prototypes are
332 here. Each of these routines simply contains the text from the
333 corresponding case, but with return(-1) added in appropriate places; see
334 instructions after the state table switcher.
336 static int rc; /* Return code for these routines */
337 static int rcv_s_pkt(); /* Received an S packet */
338 static int rcv_firstdata(); /* Received first Data packet */
339 static int rcv_shortreply(); /* Short reply to a REMOTE command */
340 static int srv_query(); /* Server answers an query */
341 static int srv_copy(); /* Server executes REMOTE COPY */
342 static int srv_rename(); /* Server executes REMOTE RENAME */
343 static int srv_login(); /* Server executes REMOTE LOGIN */
344 static int srv_timeout(); /* Server times out */
349 Protocol entry points, one for each start state (sstate).
350 The lowercase letters are internal "inputs" from the user interface.
351 NOTE: The start state letters that appear on the left margin immediately
352 below can NOT be used as packet types OR as G-packet subcodes.
355 s { TINIT; /* Send file(s) */
356 if (sinit() > 0) BEGIN ssinit;
359 v { TINIT; nakstate = 1; BEGIN get; } /* Receive file(s) */
361 r { /* Client sends a GET command */
370 #endif /* PKTZEROHACK */
377 h { /* Client sends a RETRIEVE command */
389 j { /* Client sends a REGET command */
401 o { /* Client sends Extended GET Packet */
404 reget = oopts & GOPT_RES;
405 retrieve = oopts & GOPT_DEL;
413 c { /* Client sends a Host command */
422 k { TINIT; /* Client sends a Kermit command */
430 g { /* Client sends a REMOTE command */
439 x { /* Enter server mode */
442 if (!ENABLED(en_del)) { /* If DELETE is disabled */
443 if (fncact == XYFX_B || /* undo any file collision action */
444 fncact == XYFX_U || /* that could result in deletion or */
445 fncact == XYFX_A || /* modification of existing files. */
449 g_fncact = fncact; /* Save current setting */
451 fncact = XYFX_R; /* Change to RENAME */
452 debug(F101,"server DELETE disabled so fncact RENAME","",fncact);
455 SERVE; /* tinit() clears justone... */
458 if (ikdbopen) slotstate(what, "SERVER", "", "");
464 if (!data) TINIT; /* "ABEND" -- Tell other side. */
466 if (!bctf) { /* Block check 3 forced on all packets */
468 if (epktflg) { /* If because of E-PACKET command */
469 b1 = bctl; b2 = bctu; /* Save block check type */
470 bctl = bctu = 1; /* set it to 1 */
474 errpkt((CHAR *)"User cancelled"); /* Send the packet */
475 if (!bctf) { /* Block check 3 forced on all packets */
477 if (epktflg) { /* Restore the block check */
479 bctl = b1; bctu = b2;
484 return(0); /* Return from protocol. */
488 Dynamic states: <current-states>input-character { action }
489 nakstate != 0 means we're in a receiving state, in which we send ACKs & NAKs.
492 <rgen,get,serve,ropkt>S { /* Receive Send-Init packet. */
494 cancel = 0; /* Reset cancellation counter */
495 debug(F101,"rcv_s_pkt","",rc);
496 if (rc > -1) return(rc); /* (see below) */
499 /* States in which we get replies back from commands sent to a server. */
500 /* Complicated because direction of protocol changes, packet number */
501 /* stays at zero through I-G-S sequence, and complicated even more by */
502 /* sliding windows buffer allocation. */
504 <ipkt>Y { /* Get ack for I-packet */
507 ckstrncpy(ipktack,(char *)rdatap,PKTZEROLEN); /* Save a copy of the ACK */
508 ipktlen = strlen(ipktack);
509 #endif /* PKTZEROHACK */
510 spar(rdatap); /* Set parameters */
512 winlo = 0; /* Set window-low back to zero */
513 debug(F101,"<ipkt>Y winlo","",winlo);
514 urserver = 1; /* So I know I'm talking to a server */
515 if (vcmd) { /* If sending a generic command */
516 if (tinit(0) < 0) return(-9); /* Initialize many things */
517 x = scmd(vcmd,(CHAR *)cmarg); /* Do that */
518 if (x >= 0) x = 0; /* (because of O-Packet) */
519 debug(F101,"proto G packet scmd","",x);
520 vcmd = 0; /* and then un-remember it. */
521 } else if (vstate == get) {
522 debug(F101,"REGET sstate","",sstate);
523 x = srinit(reget, retrieve, opkt); /* GET or REGET, etc */
525 if (x < 0) { /* If command was too long */
527 srimsg = "Error sending string";
528 errpkt((CHAR *)srimsg); /* cancel both sides. */
531 } else if (x > 0) { /* Need to send more O-Packets */
534 rtimer(); /* Reset the elapsed seconds timer. */
538 winlo = 0; /* Window back to 0, again. */
539 debug(F101,"<ipkt>Y vstate","",vstate);
540 nakstate = 1; /* Can send NAKs from here. */
541 BEGIN vstate; /* Switch to desired state */
545 <ssopkt>Y { /* Got ACK to O-Packet */
546 debug(F100,"CPCPRO <ssopkt>Y","",0);
548 debug(F101,"CPCPRO <ssopkt>Y x","",x);
549 if (x < 0) { /* If error */
550 errpkt((CHAR *)srimsg); /* cancel both sides. */
553 } else if (x == 0) { /* This was the last O-Packet */
554 rtimer(); /* Reset the elapsed seconds timer. */
558 winlo = 0; /* Window back to 0, again. */
559 debug(F101,"<ssopkt>Y winlo","",winlo);
560 nakstate = 1; /* Can send NAKs from here. */
561 BEGIN vstate; /* Switch to desired state */
563 debug(F101,"CPCPRO <ssopkt>Y not changing state","",x);
566 <ipkt>E { /* Ignore Error reply to I packet */
568 winlo = 0; /* Set window-low back to zero */
569 debug(F101,"<ipkt>E winlo","",winlo);
570 if (vcmd) { /* In case other Kermit doesn't */
571 if (tinit(0) < 0) return(-9);
572 x = scmd(vcmd,(CHAR *)cmarg); /* understand I-packets. */
573 if (x >= 0) x = 0; /* (because of O-Packet) */
574 vcmd = 0; /* Otherwise act as above... */
575 } else if (vstate == get) x = srinit(reget, retrieve, opkt);
576 if (x < 0) { /* If command was too long */
577 errpkt((CHAR *)srimsg); /* cancel both sides. */
580 } else if (x > 0) { /* Need to send more O-Packets */
583 freerpkt(winlo); /* Discard the Error packet. */
584 debug(F101,"<ipkt>E winlo","",winlo);
585 winlo = 0; /* Back to packet 0 again. */
586 nakstate = 1; /* Can send NAKs from here. */
591 <get>Y { /* Resend of previous I-pkt ACK, same seq number */
592 freerpkt(0); /* Free the ACK's receive buffer */
593 resend(0); /* Send the GET packet again. */
596 /* States in which we're being a server */
598 <serve,get>I { /* Get I-packet */
600 spar(rdatap); /* Set parameters from it */
601 ack1(rpar()); /* Respond with our own parameters */
603 pktinit(); /* Reinitialize packet numbers */
606 /* This can't be right - it undoes the stuff we just negotiated */
608 tinit(1); /* Reinitialize EVERYTHING */
609 justone = x; /* But this... */
611 tinit(0); /* Initialize most things */
614 #endif /* NOSERVER */
615 cancel = 0; /* Reset cancellation counter */
620 if (x_login && !x_logged) {
621 errpkt((CHAR *)"Login required");
623 } else if (sgetinit(0,0) < 0) {
627 if (ckxsyslog >= SYSLG_PR && ckxlogging)
628 cksyslog(SYSLG_PR, 1, "server", "GET", (char *)srvcmd);
629 #endif /* CKSYSLOG */
632 #endif /* NOSERVER */
635 <serve>H { /* GET /DELETE (RETRIEVE) */
637 if (x_login && !x_logged) {
638 errpkt((CHAR *)"Login required");
640 } else if (!ENABLED(en_del)) {
641 errpkt((CHAR *)"Deleting files is disabled");
643 } else if (sgetinit(0,0) < 0) {
648 if (ckxsyslog >= SYSLG_PR && ckxlogging)
649 cksyslog(SYSLG_PR, 1, "server", "GET /DELETE", (char *)srvcmd);
650 #endif /* CKSYSLOG */
653 #endif /* NOSERVER */
656 <serve>V { /* GET /RECURSIVE */
658 recursive = 1; /* Set these before sgetinit() */
659 if (fnspath == PATH_OFF)
660 fnspath = PATH_REL; /* Don't worry, they will be */
661 if (x_login && !x_logged) { /* reset next time through. */
662 errpkt((CHAR *)"Login required");
664 } else if (sgetinit(0,0) < 0) {
668 if (ckxsyslog >= SYSLG_PR && ckxlogging)
669 cksyslog(SYSLG_PR, 1, "server", "GET /RECURSIVE", (char *)srvcmd);
670 #endif /* CKSYSLOG */
673 #endif /* NOSERVER */
676 <serve>W { /* GET /RECURSIVE /DELETE */
678 recursive = 1; /* Set these before sgetinit() */
679 if (fnspath == PATH_OFF)
680 fnspath = PATH_REL; /* Don't worry, they will be */
681 moving = 1; /* reset next time through. */
682 if (x_login && !x_logged) {
683 errpkt((CHAR *)"Login required");
685 } else if (!ENABLED(en_del)) {
686 errpkt((CHAR *)"Deleting files is disabled");
688 } else if (sgetinit(0,0) < 0) {
692 if (ckxsyslog >= SYSLG_PR && ckxlogging)
693 cksyslog(SYSLG_PR,1,"server",
694 "GET /RECURSIVE /DELETE",(char *)srvcmd);
695 #endif /* CKSYSLOG */
698 #endif /* NOSERVER */
701 <serve>J { /* GET /RECOVER (REGET) */
703 if (x_login && !x_logged) {
704 errpkt((CHAR *)"Login required");
706 } else if (sgetinit(1,0) < 0) {
710 if (ckxsyslog >= SYSLG_PR && ckxlogging)
711 cksyslog(SYSLG_PR, 1, "server", "GET /RECOVER", (char *)srvcmd);
712 #endif /* CKSYSLOG */
715 #endif /* NOSERVER */
718 <serve>O { /* Extended GET */
720 if (x_login && !x_logged) { /* (any combination of options) */
721 errpkt((CHAR *)"Login required");
723 } else if ((x = sgetinit(0,1)) < 0) {
724 debug(F101,"CKCPRO <serve>O sgetinit fail","",x);
727 debug(F101,"CKCPRO <serve>O sgetinit done","",x);
729 if (ckxsyslog >= SYSLG_PR && ckxlogging)
730 cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
731 #endif /* CKSYSLOG */
733 } else { /* Otherwise stay in this state */
734 debug(F101,"CKCPRO <serve>O sgetinit TBC","",x);
738 #endif /* NOSERVER */
743 if (x_login && !x_logged) { /* (any combination of options) */
744 errpkt((CHAR *)"Login required");
746 } else if ((x = sgetinit(0,1)) < 0) {
747 debug(F101,"CKCPRO <ropkt>O sgetinit fail","",x);
750 debug(F101,"CKCPRO <ropkt>O sgetinit done","",x);
752 if (ckxsyslog >= SYSLG_PR && ckxlogging)
753 cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
754 #endif /* CKSYSLOG */
756 } else { /* Otherwise stay in this state */
757 debug(F101,"CKCPRO <ropkt>O sgetinit TBC","",x);
760 #endif /* NOSERVER */
763 <serve>G { /* Generic server command */
765 srvptr = srvcmd; /* Point to command buffer */
766 decode(rdatap,putsrv,0); /* Decode packet data into it */
767 putsrv(NUL); /* Insert a couple nulls */
768 putsrv(NUL); /* for termination */
770 sstate = srvcmd[0]; /* Set requested start state */
771 if (x_login && !x_logged && /* Login required? */
772 /* Login, Logout, and Help are allowed when not logged in */
773 sstate != 'I' && sstate != 'L' && sstate != 'H') {
774 errpkt((CHAR *)"Login required");
777 nakstate = 0; /* Now I'm the sender. */
778 what = W_REMO; /* Doing a REMOTE command. */
781 #endif /* STREAMING */
783 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
784 binary = XYFT_T; /* Switch to text mode */
785 BEGIN generic; /* Switch to generic command state */
788 errpkt((CHAR *)"Badly formed server command"); /* report error */
789 RESUME; /* & go back to server command wait */
791 #endif /* NOSERVER */
794 <serve>C { /* Receive Host command */
796 if (x_login && !x_logged) {
797 errpkt((CHAR *)"Login required");
799 } else if (!ENABLED(en_hos)) {
800 errpkt((CHAR *)"REMOTE HOST disabled");
803 errpkt((CHAR *)"HOST commands not available");
806 srvptr = srvcmd; /* Point to command buffer */
807 decode(rdatap,putsrv,0); /* Decode command packet into it */
808 putsrv(NUL); /* Null-terminate */
809 nakstate = 0; /* Now sending, not receiving */
810 binary = XYFT_T; /* Switch to text mode */
811 if (syscmd((char *)srvcmd,"")) { /* Try to execute the command */
812 what = W_REMO; /* Doing a REMOTE command. */
815 #endif /* STREAMING */
817 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
819 if (ckxsyslog >= SYSLG_PR && ckxlogging)
820 cksyslog(SYSLG_PR, 1, "server", "REMOTE HOST", (char *)srvcmd);
821 #endif /* CKSYSLOG */
822 BEGIN ssinit; /* If OK, send back its output */
823 } else { /* Otherwise */
824 errpkt((CHAR *)"Can't do system command"); /* report error */
825 RESUME; /* & go back to server command wait */
828 #endif /* NOSERVER */
831 <serve>q { /* Interrupted or connection lost */
833 debug(F101,"srv_timeout","",rc);
834 if (rc > -1) return(rc); /* (see below) */
837 <serve>N { /* Server got a NAK in command-wait */
839 errpkt((CHAR *)"Did you say RECEIVE instead of GET?");
841 #endif /* NOSERVER */
844 <serve>. { /* Any other command in this state */
846 if (c != ('E' - SP) && c != ('Y' - SP)) /* except E and Y packets. */
847 errpkt((CHAR *)"Unimplemented server function");
848 /* If we answer an E with an E, we get an infinite loop. */
849 /* A Y (ACK) can show up here if we sent back a short-form reply to */
850 /* a G packet and it was echoed. ACKs can be safely ignored here. */
851 RESUME; /* Go back to server command wait. */
852 #endif /* NOSERVER */
855 <generic>I { /* Login/Out */
857 debug(F101,"<generic>I srv_login","",rc);
858 if (rc > -1) return(rc); /* (see below) */
861 <generic>C { /* Got REMOTE CD command */
864 if (ckxsyslog >= SYSLG_PR && ckxlogging)
865 cksyslog(SYSLG_PR, 1, "server", "REMOTE CD", (char *)srvcmd);
866 #endif /* CKSYSLOG */
867 if (!ENABLED(en_cwd)) {
868 errpkt((CHAR *)"REMOTE CD disabled");
872 x = cwd((char *)(srvcmd+1)); /* Try to change directory */
874 if (ikdbopen) slotstate(what,"REMOTE CD", (char *)(srvcmd+2), "");
876 if (!x) { /* Failed */
877 errpkt((CHAR *)"Can't change directory");
878 RESUME; /* Back to server command wait */
879 } else if (x == 2) { /* User wants message */
880 if (!ENABLED(en_typ)) { /* Messages (REMOTE TYPE) disabled? */
881 errpkt((CHAR *)"REMOTE TYPE disabled");
883 } else { /* TYPE is enabled */
885 for (i = 0; i < 8; i++) {
886 if (zchki(cdmsgfile[i]) > -1) {
890 binary = XYFT_T; /* Use text mode for this. */
891 if (i < 8 && sndtype(cdmsgfile[i])) { /* Have readme file? */
892 BEGIN ssinit; /* OK */
893 } else { /* not OK */
896 success = (*p) ? 1 : 0;
897 ack1((CHAR *)p); /* ACK with new directory name */
899 RESUME; /* wait for next server command */
902 } else { /* User doesn't want message */
905 success = (*p) ? 1 : 0;
908 RESUME; /* Wait for next server command */
911 #endif /* NOSERVER */
914 <generic>A { /* Got REMOTE PWD command */
917 if (ckxsyslog >= SYSLG_PR && ckxlogging)
918 cksyslog(SYSLG_PR, 1, "server", "REMOTE PWD", NULL);
919 #endif /* CKSYSLOG */
920 if (!ENABLED(en_cwd)) {
921 errpkt((CHAR *)"REMOTE CD disabled");
924 if (encstr((CHAR *)zgtdir()) > -1) { /* Encode current directory */
925 ack1(data); /* If it fits, send it back in ACK */
927 } else { /* Failed */
928 ack(); /* Send empty ACK */
929 success = 0; /* and indicate failure locally */
931 RESUME; /* Back to server command wait */
933 #endif /* NOSERVER */
936 <generic>D { /* REMOTE DIRECTORY command */
940 if (ckxsyslog >= SYSLG_PR && ckxlogging)
941 cksyslog(SYSLG_PR, 1, "server", "REMOTE DIRECTORY", (char *)srvcmd);
942 #endif /* CKSYSLOG */
943 if (!ENABLED(en_dir)) { /* If DIR is disabled, */
944 errpkt((CHAR *)"REMOTE DIRECTORY disabled"); /* refuse. */
946 } else { /* DIR is enabled. */
948 if (ikdbopen) slotstate(what,"REMOTE DIR", (char *)(srvcmd+2), "");
950 if (!ENABLED(en_cwd)) { /* But CWD is disabled */
951 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
952 if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
953 errpkt((CHAR *)"Access denied");
954 RESUME; /* Remember, this is not a goto! */
957 if (state == generic) { /* It's OK to go ahead. */
959 n2 = (*(srvcmd+2)) ? DIRCMD : DIRCM2;
960 if (syscmd(n2,(char *)(srvcmd+2))) /* If it can be done */
963 if ((x = snddir((char*)(srvcmd+2))) > 0)
966 BEGIN ssinit; /* send the results back; */
967 } else { /* otherwise */
969 errpkt((CHAR *)"No files match");
971 errpkt((CHAR *)"Can't list directory");
972 RESUME; /* return to server command wait */
976 #endif /* NOSERVER */
979 <generic>E { /* REMOTE DELETE (Erase) */
983 if (ckxsyslog >= SYSLG_PR && ckxlogging)
984 cksyslog(SYSLG_PR, 1, "server", "REMOTE DELETE", (char *)srvcmd);
985 #endif /* CKSYSLOG */
986 if (!ENABLED(en_del)) {
987 errpkt((CHAR *)"REMOTE DELETE disabled");
989 } else { /* DELETE is enabled */
991 if (ikdbopen) slotstate(what,"REMOTE DELETE", (char *)(srvcmd+2), "");
993 if (!ENABLED(en_cwd)) { /* but CWD is disabled */
994 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
995 if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
996 errpkt((CHAR *)"Access denied");
997 RESUME; /* Remember, this is not a goto! */
999 } else if (isdir((char *)(srvcmd+2))) { /* A directory name? */
1000 errpkt((CHAR *)"It's a directory");
1003 if (state == generic) { /* It's OK to go ahead. */
1005 if ((x = snddel((char*)(srvcmd+2))) > 0) {
1006 BEGIN ssinit; /* If OK send results back */
1007 } else { /* otherwise */
1009 errpkt((CHAR *)"File not found"); /* report failure */
1011 errpkt((CHAR *)"DELETE failed");
1012 RESUME; /* & return to server command wait */
1016 #endif /* NOSERVER */
1019 <generic>F { /* FINISH */
1022 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1023 cksyslog(SYSLG_PR, 1, "server", "FINISH", NULL);
1024 #endif /* CKSYSLOG */
1026 if (ikdbopen) slotstate(what,"SERVER FINISH", "", "");
1028 if (!ENABLED(en_fin)) {
1029 errpkt((CHAR *)"FINISH disabled");
1032 ack(); /* Acknowledge */
1033 xxscreen(SCR_TC,0,0L,""); /* Display */
1035 return(0); /* Done */
1037 #endif /* NOSERVER */
1040 <generic>X { /* EXIT */
1043 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1044 cksyslog(SYSLG_PR, 1, "server", "REMOTE EXIT", NULL);
1045 #endif /* CKSYSLOG */
1047 if (ikdbopen) slotstate(what,"REMOTE EXIT", "", "");
1049 if (!ENABLED(en_xit)) {
1050 errpkt((CHAR *)"EXIT disabled");
1053 ack(); /* Acknowledge */
1054 xxscreen(SCR_TC,0,0L,""); /* Display */
1055 doexit(GOOD_EXIT,xitsta);
1057 #endif /* NOSERVER */
1060 <generic>L { /* BYE (Logout) */
1063 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1064 cksyslog(SYSLG_PR, 1, "server", "BYE", NULL);
1065 #endif /* CKSYSLOG */
1067 if (ikdbopen) slotstate(what,"SERVER BYE", "", "");
1069 if (!ENABLED(en_bye)) {
1070 errpkt((CHAR *)"BYE disabled");
1073 ack(); /* Acknowledge */
1075 msleep(750); /* Give the ACK time to get out */
1077 ttres(); /* Reset the terminal */
1078 xxscreen(SCR_TC,0,0L,""); /* Display */
1079 doclean(1); /* Clean up files, etc */
1081 debug(F100,"C-Kermit BYE - Logging out...","",0);
1089 #endif /* CK_LOGIN */
1093 if (network && tcpsrfd > 0 && !inserver)
1094 doexit(GOOD_EXIT,xitsta);
1096 #endif /* NOLISTEN */
1097 #endif /* TCPSOCKET */
1098 return(zkself()); /* Try to log self out */
1100 #endif /* NOSERVER */
1103 <generic>H { /* REMOTE HELP */
1105 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1106 cksyslog(SYSLG_PR, 1, "server", "REMOTE HELP", NULL);
1107 #endif /* CKSYSLOG */
1109 if (ikdbopen) slotstate(what,"REMOTE HELP", "", "");
1113 BEGIN ssinit; /* try to send it */
1114 } else { /* If not ok, */
1115 errpkt((CHAR *)"Can't send help"); /* send error message instead */
1116 RESUME; /* and return to server command wait */
1118 #endif /* NOSERVER */
1121 <generic>R { /* REMOTE RENAME */
1123 debug(F101,"srv_rename","",rc);
1124 if (rc > -1) return(rc); /* (see below) */
1127 <generic>K { /* REMOTE COPY */
1129 debug(F101,"srv_copy","",rc);
1130 if (rc > -1) return(rc); /* (see below) */
1133 <generic>S { /* REMOTE SET */
1135 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1136 cksyslog(SYSLG_PR, 1, "server", "REMOTE SET", (char *)srvcmd);
1137 #endif /* CKSYSLOG */
1140 if (ikdbopen) slotstate(what,"REMOTE SET", (char *)(srvcmd+1), "");
1142 if (!ENABLED(en_set)) {
1143 errpkt((CHAR *)"REMOTE SET disabled");
1146 if (remset((char *)(srvcmd+1))) { /* Try to do what they ask */
1148 ack(); /* If OK, then acknowledge */
1149 } else /* Otherwise */
1150 errpkt((CHAR *)"Unknown REMOTE SET parameter"); /* give error msg */
1151 RESUME; /* Return to server command wait */
1153 #endif /* NOSERVER */
1156 <generic>T { /* REMOTE TYPE */
1160 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1161 cksyslog(SYSLG_PR, 1, "server", "REMOTE TYPE", (char *)srvcmd);
1162 #endif /* CKSYSLOG */
1163 if (!ENABLED(en_typ)) {
1164 errpkt((CHAR *)"REMOTE TYPE disabled");
1168 if (ikdbopen) slotstate(what,"REMOTE TYPE", (char *)(srvcmd+2), "");
1170 if (!ENABLED(en_cwd)) { /* If CWD disabled */
1171 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
1172 if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */
1173 errpkt((CHAR *)"Access denied");
1174 RESUME; /* Remember, this is not a goto! */
1177 if (state == generic) { /* It's OK to go ahead. */
1178 binary = XYFT_T; /* Use text mode for this. */
1179 if ( /* (RESUME didn't change state) */
1181 syscmd(TYPCMD,(char *)(srvcmd+2)) /* Old way */
1183 sndtype((char *)(srvcmd+2)) /* New way */
1184 #endif /* COMMENT */
1186 BEGIN ssinit; /* OK */
1188 errpkt((CHAR *)"Can't type file"); /* give error message */
1189 RESUME; /* wait for next server command */
1193 #endif /* NOSERVER */
1196 <generic>m { /* REMOTE MKDIR */
1200 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1201 cksyslog(SYSLG_PR, 1, "server", "REMOTE MKDIR", (char *)srvcmd);
1202 #endif /* CKSYSLOG */
1204 if (ikdbopen) slotstate(what,"REMOTE MKDIR", (char *)(srvcmd+2), "");
1206 if (!ENABLED(en_mkd)) {
1207 errpkt((CHAR *)"REMOTE MKDIR disabled");
1209 } else if (!ENABLED(en_cwd)) { /* If CWD disabled */
1210 errpkt((CHAR *)"Directory access restricted");
1211 RESUME; /* Remember, this is not a goto! */
1213 if (state == generic) { /* OK to go ahead. */
1215 x = ckmkdir(0,(char *)(srvcmd+2),&p,0,1); /* Make the directory */
1218 encstr((CHAR *)p); /* OK - encode the name */
1219 ack1(data); /* Send short-form response */
1222 } else { /* not OK */
1223 if (!*p) p = "Directory creation failure";
1224 errpkt((CHAR *)p); /* give error message */
1225 RESUME; /* Wait for next server command */
1229 errpkt((CHAR *)"REMOTE MKDIR not available");
1231 #endif /* CK_MKDIR */
1232 #endif /* NOSERVER */
1235 <generic>d { /* REMOTE RMDIR */
1239 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1240 cksyslog(SYSLG_PR, 1, "server", "REMOTE RMDIR", (char *)srvcmd);
1241 #endif /* CKSYSLOG */
1243 if (ikdbopen) slotstate(what,"REMOTE RMDIR", (char *)(srvcmd+2), "");
1245 if (!ENABLED(en_rmd)) {
1246 errpkt((CHAR *)"REMOTE RMDIR disabled");
1248 } else if (!ENABLED(en_cwd)) { /* If CWD disabled */
1249 errpkt((CHAR *)"Directory access restricted");
1250 RESUME; /* Remember, this is not a goto! */
1252 if (state == generic) { /* OK to go ahead. */
1254 x = ckmkdir(1,(char *)(srvcmd+2),&p,0,1);
1257 encstr((CHAR *)p); /* OK - encode the name */
1258 ack1(data); /* Send short-form response */
1261 } else { /* not OK */
1262 if (!*p) p = "Directory removal failure";
1263 errpkt((CHAR *)p); /* give error message */
1264 RESUME; /* Wait for next server command */
1268 errpkt((CHAR *)"REMOTE RMDIR not available");
1270 #endif /* CK_MKDIR */
1271 #endif /* NOSERVER */
1274 <generic>U { /* REMOTE SPACE */
1277 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1278 cksyslog(SYSLG_PR, 1, "server", "REMOTE SPACE", (char *)srvcmd);
1279 #endif /* CKSYSLOG */
1280 if (!ENABLED(en_spa)) {
1281 errpkt((CHAR *)"REMOTE SPACE disabled");
1284 x = srvcmd[1]; /* Get area to check */
1285 x = ((x == NUL) || (x == SP)
1287 || (x == '!') || (srvcmd[3] == ':')
1291 if (ikdbopen) slotstate(what,
1293 (x ? "" : (char *)srvcmd),
1297 if (!x && !ENABLED(en_cwd)) { /* CWD disabled */
1298 errpkt((CHAR *)"Access denied"); /* and non-default area given, */
1299 RESUME; /* refuse. */
1302 _PROTOTYP(int sndspace,(int));
1303 if (sndspace(x ? toupper(srvcmd[2]) : 0)) {
1304 BEGIN ssinit; /* send the report. */
1305 } else { /* If not ok, */
1306 errpkt((CHAR *)"Can't send space"); /* send error message */
1307 RESUME; /* and return to server command wait */
1313 x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,(char *)(srvcmd+2)));
1314 if (x) { /* If we got the info */
1315 BEGIN ssinit; /* send it */
1316 } else { /* otherwise */
1317 errpkt((CHAR *)"Can't check space"); /* send error message */
1318 RESUME; /* and await next server command */
1323 #endif /* NOSERVER */
1326 <generic>W { /* REMOTE WHO */
1329 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1330 cksyslog(SYSLG_PR, 1, "server", "REMOTE WHO", (char *)srvcmd);
1331 #endif /* CKSYSLOG */
1333 if (ikdbopen) slotstate(what,"REMOTE WHO", (char *)(srvcmd+2), "");
1335 if (!ENABLED(en_who)) {
1336 errpkt((CHAR *)"REMOTE WHO disabled");
1340 _PROTOTYP(int sndwho,(char *));
1341 if (sndwho((char *)(srvcmd+2))) {
1342 BEGIN ssinit; /* try to send it */
1343 } else { /* If not ok, */
1344 errpkt((CHAR *)"Can't do who command"); /* send error msg */
1345 RESUME; /* and return to server command wait */
1348 if (syscmd(WHOCMD,(char *)(srvcmd+2))) {
1351 errpkt((CHAR *)"Can't do who command");
1356 #endif /* NOSERVER */
1359 <generic>V { /* Variable query or set */
1361 debug(F101,"srv_query","",rc);
1362 if (rc > -1) return(rc);
1365 <generic>M { /* REMOTE MESSAGE command */
1367 debug(F110,"RMSG",(char *)srvcmd+2,0);
1368 xxscreen(SCR_MS,0,0L,(char *)(srvcmd+2));
1371 #endif /* NOSERVER */
1374 <generic>q { /* Interrupted or connection lost */
1376 if (fatalio) { /* Connection lost */
1378 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1379 cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
1380 #endif /* CKSYSLOG */
1382 xitsta |= (what & W_KERMIT);
1384 } else if (interrupted) {
1385 if (!ENABLED(en_fin)) { /* Ctrl-C typed */
1386 errpkt((CHAR *)"QUIT disabled");
1390 if (ckxsyslog >= SYSLG_PR && ckxlogging)
1391 cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
1392 #endif /* CKSYSLOG */
1394 xitsta |= (what & W_KERMIT);
1397 } else { /* Shouldn't happen */
1398 debug(F100,"SERVER (generic) GOT UNEXPECTED 'q'","",0);
1401 #endif /* NOSERVER */
1404 <generic>. { /* Anything else in this state... */
1406 errpkt((CHAR *)"Unimplemented REMOTE command"); /* Complain */
1407 RESUME; /* and return to server command wait */
1408 #endif /* NOSERVER */
1411 <rgen>q { /* Sent BYE and connection broken */
1412 if (bye_active && ttchk() < 0) {
1415 ttclos(0); /* Close our end of the connection */
1417 return(success = 1);
1418 } else { /* Other generic command */
1419 return(success = 0); /* or connection not broken */
1423 <rgen>Y { /* Short-Form reply */
1424 rc = rcv_shortreply();
1425 debug(F101,"<rgen>Y rcv_shortreply","",rc);
1426 if (rc > -1) return(rc);
1429 <rgen,rfile>F { /* File header */
1432 debug(F101,"<rfile>F winlo 1","",winlo);
1433 xflg = 0; /* Not screen data */
1435 cancel = 0; /* Reset cancellation counter */
1439 #endif /* CALIBRATE */
1440 if (!rcvfil(filnam)) { /* Figure out local filename */
1441 errpkt((CHAR *)rf_err); /* Trouble */
1443 } else { /* Real file, OK to receive */
1445 debug(F111,"<rfile>F winlo 2",fspec,winlo);
1446 if (filcnt == 1) /* rcvfil set this to 1 for 1st file */
1447 crc16 = 0L; /* Clear file CRC */
1448 fnp = fspec; /* This is the full path */
1449 if (server && !ENABLED(en_cwd) || /* if DISABLE CD */
1450 !fackpath /* or F-ACK-PATH OFF */
1452 zstrip(fspec,&fnp); /* don't send back full path */
1454 encstr((CHAR *)fnp);
1458 ack1(data); /* Send it back in ACK */
1459 initattr(&iattr); /* Clear file attribute structure */
1461 if (window(wslotn) < 0) { /* Allocate negotiated window slots */
1462 errpkt((CHAR *)"Can't open window");
1466 if (ikdbopen) slotstate(what,
1467 server ? "SERVER" : "",
1472 BEGIN rattr; /* Now expect Attribute packets */
1476 <rgen,rfile>X { /* X-packet instead of file header */
1477 xflg = 1; /* Screen data */
1479 cancel = 0; /* Reset cancellation counter */
1480 ack(); /* Acknowledge the X-packet */
1481 initattr(&iattr); /* Initialize attribute structure */
1483 if (window(wslotn) < 0) { /* allocate negotiated window slots */
1484 errpkt((CHAR *)"Can't open window");
1488 if (query) { /* If this is the response to */
1489 qbufp = querybuf; /* a query that we sent, initialize */
1490 qbufn = 0; /* the response buffer */
1494 what = W_REMO; /* we're doing a REMOTE command */
1496 if (ikdbopen) slotstate(what,
1497 server ? "SERVER" : "",
1502 BEGIN rattr; /* Expect Attribute packets */
1505 <rattr>A { /* Attribute packet */
1506 if (gattr(rdatap,&iattr) == 0) { /* Read into attribute structure */
1508 ack1((CHAR *)iattr.reply.val); /* Reply with data */
1510 ack(); /* If OK, acknowledge */
1511 #endif /* CK_RESEND */
1512 } else { /* Otherwise */
1513 extern CK_OFF_T fsize;
1515 r = getreason(iattr.reply.val);
1516 ack1((CHAR *)iattr.reply.val); /* refuse to accept the file */
1517 xxscreen(SCR_ST,ST_REFU,0L,r); /* reason */
1519 if (tralog && !tlogfmt)
1520 doxlog(what,filnam,fsize,binary,1,r);
1525 <rattr>D { /* First data packet */
1526 debug(F100,"<rattr> D firstdata","",0);
1527 rc = rcv_firstdata();
1528 debug(F101,"rcv_firstdata rc","",rc);
1529 if (rc > -1) return(rc); /* (see below) */
1532 <rfile>B { /* EOT, no more files */
1533 ack(); /* Acknowledge the B packet */
1534 reot(); /* Do EOT things */
1536 /* If we were cd'd temporarily to another device or directory ... */
1539 x = zchdir((char *) savdir); /* ... restore previous directory */
1540 f_tmpdir = 0; /* and remember we did it. */
1541 debug(F111,"ckcpro.w B tmpdir restoring",savdir,x);
1543 #endif /* CK_TMPDIR */
1544 RESUME; /* and quit */
1547 <rdpkt>D { /* Got Data packet */
1548 debug(F101,"<rdpkt>D cxseen","",cxseen);
1549 debug(F101,"<rdpkt>D czseen","",czseen);
1550 if (cxseen || czseen || discard) { /* If file or group interruption */
1552 msg = czseen ? (CHAR *)"Z" : (CHAR *)"X";
1554 if (streaming) { /* Need to cancel */
1555 debug(F111,"<rdpkt>D streaming cancel",msg,cancel);
1556 if (cancel++ == 0) { /* Only do this once */
1557 ack1(msg); /* Put "X" or "Z" in ACK */
1558 } else if (czseen) {
1559 errpkt((CHAR *)"User canceled");
1565 #endif /* STREAMING */
1567 } else { /* No interruption */
1575 rc = (binary && !parity) ?
1576 bdecode(rdatap,putfil):
1577 decode(rdatap, qf ? puttrm : putfil, 1);
1579 rc = decode(rdatap, qf ? puttrm : putfil, 1);
1580 #endif /* CKTUNING */
1582 discard = (keep == 0 || (keep == SET_AUTO && binary != XYFT_T));
1583 errpkt((CHAR *)"Error writing data"); /* If failure, */
1585 } else /* Data written OK, send ACK */
1590 #endif /* STREAMING */
1595 <rattr>Z { /* EOF immediately after A-Packet. */
1596 rf_err = "Can't create file";
1598 if (discard) { /* Discarding a real file... */
1600 } else if (xflg) { /* If screen data */
1601 if (remfile) { /* redirected to file */
1602 if (rempipe) /* or pipe */
1603 x = openc(ZOFILE,remdest); /* Pipe: start command */
1605 x = opena(remdest,&iattr); /* File: open with attributes */
1606 } else { /* otherwise */
1607 x = opent(&iattr); /* "open" the screen */
1610 } else if (calibrate) { /* If calibration run */
1611 x = ckopenx(&iattr); /* do this */
1612 #endif /* CALIBRATE */
1613 } else { /* otherwise */
1614 x = opena(filnam,&iattr); /* open the file, with attributes */
1615 if (x == -17) { /* REGET skipped because same size */
1620 if (!x || reof(filnam, &iattr) < 0) { /* Close output file */
1621 errpkt((CHAR *) rf_err); /* If problem, send error msg */
1622 RESUME; /* and quit */
1623 } else { /* otherwise */
1625 xxscreen(SCR_ST,ST_SKIP,SKP_RES,"");
1626 ack(); /* acknowledge the EOF packet */
1627 BEGIN rfile; /* and await another file */
1631 <rdpkt>q { /* Ctrl-C or connection loss. */
1633 window(1); /* Set window size back to 1... */
1635 x = clsof(1); /* Close file */
1636 return(success = 0); /* Failed */
1639 <rdpkt>Z { /* End Of File (EOF) Packet */
1640 /* wslots = 1; */ /* (don't set) Window size back to 1 */
1641 #ifndef COHERENT /* Coherent compiler blows up on this switch() statement. */
1642 x = reof(filnam, &iattr); /* Handle the EOF packet */
1643 switch (x) { /* reof() sets the success flag */
1644 case -5: /* Handle problems */
1645 errpkt((CHAR *)"RENAME failed"); /* Fatal */
1649 errpkt((CHAR *)"MOVE failed"); /* Fatal */
1652 case -3: /* If problem, send error msg */
1653 errpkt((CHAR *)"Can't print file"); /* Fatal */
1657 errpkt((CHAR *)"Can't mail file"); /* Fatal */
1660 case 2: /* Not fatal */
1662 xxscreen(SCR_EM,0,0L,"Receiver can't delete temp file");
1666 if (x < 0) { /* Fatal */
1667 errpkt((CHAR *)"Can't close file");
1669 } else { /* Success */
1671 if (query) /* Query reponses generally */
1672 conoll(""); /* don't have line terminators */
1674 if (czseen) { /* Batch canceled? */
1675 if (cancel++ == 0) { /* If we haven't tried this yet */
1676 ack1((CHAR *)"Z"); /* Try it once */
1677 } else { /* Otherwise */
1678 errpkt((CHAR *)"User canceled"); /* quite with Error */
1682 ack(); /* Acknowledge the EOF packet */
1683 BEGIN rfile; /* and await another file */
1687 if (reof(filnam, &iattr) < 0) { /* Close the file */
1688 errpkt((CHAR *)"Error at end of file");
1690 } else { /* reof() sets success flag */
1694 #endif /* COHERENT */
1697 <ssinit>Y { /* ACK for Send-Init */
1698 spar(rdatap); /* set parameters from it */
1704 bctu = bctr; /* switch to agreed-upon block check */
1705 bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
1709 if ((sendmode == SM_RESEND) && (!atcapu || !rscapu)) { /* RESEND */
1710 errpkt((CHAR *) "RESEND capabilities not negotiated");
1713 #endif /* CK_RESEND */
1714 what = W_SEND; /* Remember we're sending */
1716 x = sfile(xflg); /* Send X or F header packet */
1717 cancel = 0; /* Reset cancellation counter */
1718 if (x) { /* If the packet was sent OK */
1719 if (!xflg && filcnt == 1) /* and it's a real file */
1720 crc16 = 0L; /* Clear the file CRC */
1721 resetc(); /* reset per-transaction counters */
1722 rtimer(); /* reset timers */
1725 #endif /* GFTIMER */
1726 streamon(); /* turn on streaming */
1728 if (ikdbopen) slotstate(what,
1729 (server ? "SERVER" : ""),
1734 BEGIN ssfile; /* and switch to receive-file state */
1735 } else { /* otherwise send error msg & quit */
1736 s = xflg ? "Can't execute command" : (char *)epktmsg;
1737 if (!*s) s = "Can't open file";
1743 #endif /* CK_RESEND */
1747 These states are necessary to handle the case where we get a server command
1748 packet (R, G, or C) reply with an S packet, but the client retransmits the
1749 command packet. The input() function doesn't catch this because the packet
1750 number is still zero.
1752 <ssinit>R { /* R packet was retransmitted. */
1753 xsinit(); /* Resend packet 0 */
1756 <ssinit>G { /* Same deal if G packet comes again */
1760 /* should probably add cases for O, W, V, H, J, ... */
1762 <ssinit>C { /* Same deal if C packet comes again */
1766 <ssfile>Y { /* ACK for F or X packet */
1767 srvptr = srvcmd; /* Point to string buffer */
1768 decode(rdatap,putsrv,0); /* Decode data field, if any */
1769 putsrv(NUL); /* Terminate with null */
1770 ffc = 0L; /* Reset file byte counter */
1771 debug(F101,"<ssfile>Y cxseen","",cxseen);
1772 if (*srvcmd) { /* If remote name was recorded */
1773 if (sendmode != SM_RESEND) {
1774 if (fdispla == XYFD_C || fdispla == XYFD_S)
1775 xxscreen(SCR_AN,0,0L,(char *)srvcmd);
1776 tlog(F110," remote name:",(char *) srvcmd,0L);
1777 makestr(&psrfspec,(char *)srvcmd);
1780 if (cxseen||czseen) { /* Interrupted? */
1781 debug(F101,"<ssfile>Y canceling","",0);
1782 x = clsif(); /* Close input file */
1783 sxeof(1); /* Send EOF(D) */
1784 BEGIN sseof; /* and switch to EOF state. */
1785 } else if (atcapu) { /* If attributes are to be used */
1786 if (sattr(xflg | stdinf, 1) < 0) { /* send them */
1787 errpkt((CHAR *)"Can't send attributes"); /* if problem, say so */
1788 RESUME; /* and quit */
1789 } else BEGIN ssattr; /* if ok, switch to attribute state */
1790 } else { /* Attributes not negotiated */
1791 if (window(wslotn) < 0) { /* Open window */
1792 errpkt((CHAR *)"Can't open window");
1794 } else if ((x = sdata()) == -2) { /* Send first data packet data */
1795 window(1); /* Connection lost, reset window */
1796 x = clsif(); /* Close input file */
1797 return(success = 0); /* Return failure */
1798 } else if (x == -9) { /* User interrupted */
1799 errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1800 window(1); /* Set window size back to 1... */
1801 timint = s_timint; /* Restore timeout */
1802 return(success = 0); /* Failed */
1803 } else if (x < 0) { /* EOF (empty file) or interrupted */
1804 window(1); /* put window size back to 1, */
1805 debug(F101,"<ssfile>Y cxseen","",cxseen);
1806 x = clsif(); /* If not ok, close input file, */
1807 if (x < 0) /* treating failure as interruption */
1808 cxseen = 1; /* Send EOF packet */
1809 seof(cxseen||czseen);
1810 BEGIN sseof; /* and switch to EOF state. */
1811 } else { /* First data sent OK */
1812 BEGIN ssdata; /* All ok, switch to send-data state */
1817 <ssattr>Y { /* Got ACK to A packet */
1818 ffc = 0L; /* Reset file byte counter */
1819 debug(F101,"<ssattr>Y cxseen","",cxseen);
1820 if (cxseen||czseen) { /* Interrupted? */
1821 debug(F101,"<sattr>Y canceling","",0);
1822 x = clsif(); /* Close input file */
1823 sxeof(1); /* Send EOF(D) */
1824 BEGIN sseof; /* and switch to EOF state. */
1825 } else if (rsattr(rdatap) < 0) { /* Was the file refused? */
1826 discard = 1; /* Set the discard flag */
1827 clsif(); /* Close the file */
1828 sxeof(1); /* send EOF with "discard" code */
1829 BEGIN sseof; /* switch to send-EOF state */
1830 } else if ((x = sattr(xflg | stdinf, 0)) < 0) { /* Send more? */
1831 errpkt((CHAR *)"Can't send attributes"); /* Trouble... */
1833 } else if (x == 0) { /* No more to send so now the data */
1834 if (window(wslotn) < 0) { /* Allocate negotiated window slots */
1835 errpkt((CHAR *)"Can't open window");
1838 if ((x = sdata()) == -2) { /* File accepted, send first data */
1839 window(1); /* Connection broken */
1840 x = clsif(); /* Close file */
1841 return(success = 0); /* Return failure */
1842 } else if (x == -9) { /* User interrupted */
1843 errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1844 window(1); /* Set window size back to 1... */
1845 timint = s_timint; /* Restore timeout */
1846 return(success = 0); /* Failed */
1847 } else if (x < 0) { /* If data was not sent */
1848 window(1); /* put window size back to 1, */
1849 debug(F101,"<ssattr>Y cxseen","",cxseen);
1850 if (clsif() < 0) /* Close input file */
1851 cxseen = 1; /* Send EOF packet */
1852 seof(cxseen||czseen);
1853 BEGIN sseof; /* and switch to EOF state. */
1855 BEGIN ssdata; /* All ok, switch to send-data state */
1860 <ssdata>q { /* Ctrl-C or connection loss. */
1861 window(1); /* Set window size back to 1... */
1862 cxseen = 1; /* To indicate interruption */
1863 x = clsif(); /* Close file */
1864 return(success = 0); /* Failed */
1867 <ssdata>Y { /* Got ACK to Data packet */
1868 canned(rdatap); /* Check if file transfer cancelled */
1869 debug(F111,"<ssdata>Y cxseen",rdatap,cxseen);
1870 debug(F111,"<ssdata>Y czseen",rdatap,czseen);
1871 if ((x = sdata()) == -2) { /* Try to send next data */
1872 window(1); /* Connection lost, reset window */
1873 x = clsif(); /* Close file */
1874 return(success = 0); /* Failed */
1875 } else if (x == -9) { /* User interrupted */
1876 errpkt((CHAR *)"User cancelled"); /* Send Error packet */
1877 window(1); /* Set window size back to 1... */
1878 timint = s_timint; /* Restore original timeout */
1879 return(success = 0); /* Failed */
1880 } else if (x < 0) { /* EOF - finished sending data */
1881 debug(F101,"<ssdata>Y cxseen","",cxseen);
1882 window(1); /* Set window size back to 1... */
1883 if (clsif() < 0) /* Close input file */
1884 cxseen = 1; /* Send EOF packet */
1885 debug(F101,"<ssdata>Y CALLING SEOF()","",cxseen);
1886 seof(cxseen||czseen);
1887 BEGIN sseof; /* and enter send-eof state */
1889 /* NOTE: If x == 0 it means we're draining: see sdata()! */
1892 <sseof>Y { /* Got ACK to EOF */
1894 canned(rdatap); /* Check if file transfer cancelled */
1895 debug(F111,"<sseof>Y cxseen",rdatap,cxseen);
1896 debug(F111,"<sseof>Y czseen",rdatap,czseen);
1897 debug(F111,"<sseof>Y discard",rdatap,discard);
1900 success = (cxseen == 0 && czseen == 0); /* Transfer status... */
1901 debug(F101,"<sseof>Y success","",success);
1902 if (success && rejection > 0) /* If rejected, succeed if */
1903 if (rejection != '#' && /* reason was date */
1904 rejection != 1 && rejection != '?') /* or name; */
1905 success = 0; /* fail otherwise. */
1906 cxseen = 0; /* This goes back to zero. */
1907 if (success) { /* Only if transfer succeeded... */
1908 xxscreen(SCR_ST,ST_OK,0L,"");
1910 makestr(&sfspec,psfspec); /* Record filenames for WHERE */
1911 makestr(&srfspec,psrfspec);
1913 if (moving) { /* If MOVE'ing */
1914 x = zdelet(filnam); /* Try to delete the source file */
1918 tlog(F110," deleted",filnam,0);
1920 tlog(F110," delete failed:",ck_errstr(),0);
1924 } else if (snd_move) { /* Or move it */
1926 x = zrename(filnam,snd_move);
1930 tlog(F110," moved to ",snd_move,0);
1932 tlog(F110," move failed:",ck_errstr(),0);
1936 } else if (snd_rename) { /* Or rename it */
1937 char *s = snd_rename; /* Renaming string */
1939 int y; /* Pass it thru the evaluator */
1940 extern int cmd_quoting; /* for \v(filename) */
1941 if (cmd_quoting) { /* But only if cmd_quoting is on */
1944 zzstring(snd_rename,&s,&y);
1950 x = zrename(filnam,s);
1954 tlog(F110," renamed to",s,0);
1956 tlog(F110," rename failed:",ck_errstr(),0);
1962 #endif /* COMMENT */
1966 if (czseen) { /* Check group interruption flag */
1967 g = 0; /* No more files if interrupted */
1968 } else { /* Otherwise... */
1970 /* This code makes any open error fatal to a file-group transfer. */
1972 debug(F111,"<sseof>Y gnfile",filnam,g);
1973 if (g > 0) { /* Any more files to send? */
1974 if (sfile(xflg)) /* Yes, try to send next file header */
1975 BEGIN ssfile; /* if ok, enter send-file state */
1976 else { /* otherwise */
1977 s = xflg ? "Can't execute command" : (char *)epktmsg;
1978 if (!*s) s = "Can't open file";
1979 errpkt((CHAR *)s); /* send error message */
1980 RESUME; /* and quit */
1982 } else { /* No next file */
1983 tsecs = gtimer(); /* get statistics timers */
1985 fptsecs = gftimer();
1986 #endif /* GFTIMER */
1987 seot(); /* send EOT packet */
1988 BEGIN sseot; /* enter send-eot state */
1991 while (1) { /* Keep trying... */
1992 g = gnfile(); /* Get next file */
1993 debug(F111,"<sseof>Y gnfile",filnam,g);
1994 if (g == 0 && gnferror == 0) /* No more, stop trying */
1996 if (g > 0) { /* Have one */
1997 if (sfile(xflg)) { /* Try to open and send F packet */
1998 BEGIN ssfile; /* If OK, enter send-file state */
1999 break; /* and break out of loop. */
2001 } /* Otherwise keep trying to get one we can send... */
2005 debug(F101,"<sseof>Y no more files","",czseen);
2006 tsecs = gtimer(); /* Get statistics timers */
2008 fptsecs = gftimer();
2009 #endif /* GFTIMER */
2010 seot(); /* Send EOT packet */
2011 BEGIN sseot; /* Enter send-eot state */
2013 #endif /* COMMENT */
2016 <sseot>Y { /* Got ACK to EOT */
2017 debug(F101,"sseot justone","",justone);
2018 RESUME; /* All done, just quit */
2021 E { /* Got Error packet, in any state */
2023 window(1); /* Close window */
2024 timint = s_timint; /* Restore original timeout */
2025 if (*epktmsg) /* Message from Error packet */
2026 s = (char *)epktmsg;
2027 if (!*s) { /* If not there then maybe here */
2029 ckstrncpy((char *)epktmsg,(char *)rdatap,PKTMSGLEN);
2031 if (!*s) /* Hopefully we'll never see this. */
2032 s = "Unknown error";
2033 success = 0; /* For IF SUCCESS/FAIL. */
2034 debug(F101,"ckcpro.w justone at E pkt","",justone);
2036 success = 0; /* Transfer failed */
2037 xferstat = success; /* Remember transfer status */
2039 x = quiet; quiet = 1; /* Close files silently, */
2040 epktrcvd = 1; /* Prevent messages from clsof() */
2042 clsof(1); /* discarding any output file. */
2043 ermsg(s); /* Issue the message (calls screen). */
2044 quiet = x; /* Restore quiet state */
2046 tstats(); /* Get stats */
2048 If we are executing commands from a command file or macro, let the command
2049 file or macro decide whether to exit, based on SET { TAKE, MACRO } ERROR.
2056 fatal("Protocol error");
2057 xitsta |= (what & W_KERMIT); /* Save this for doexit(). */
2059 /* If we were cd'd temporarily to another device or directory ... */
2062 x = zchdir((char *) savdir); /* ... restore previous directory */
2063 f_tmpdir = 0; /* and remember we did it. */
2064 debug(F111,"ckcpro.w E tmpdir restored",savdir,x);
2066 #endif /* CK_TMPDIR */
2068 if (ikdbopen) slotstate(what,"ERROR", (char *)epktmsg, "");
2073 q { success = 0; QUIT; } /* Ctrl-C or connection loss. */
2075 . { /* Anything not accounted for above */
2076 errpkt((CHAR *)"Unexpected packet type"); /* Give error message */
2078 xitsta |= (what & W_KERMIT); /* Save this for doexit(). */
2079 RESUME; /* and quit */
2085 From here down to proto() are routines that were moved out of the state
2086 table switcher because the resulting switch() had become too large.
2087 To move the contents of a state-table case to a routine:
2088 1. Add a prototype to the list above the state table switcher.
2089 2. Make a routine with an appropriate name, returning int.
2090 3. Move the code into it.
2091 4. Put a call to the new routine in the former spot:
2092 rc = name_of_routine();
2093 if (rc > -1) return(rc);
2094 5. Add "return(-1);" after every RESUME, SERVE, or BEGIN macro and
2095 at the end if the code is open-ended.
2100 debug(F101,"rcv_firstdata","",dispos);
2102 if (discard) { /* if we're discarding the file */
2103 ack1((CHAR *)"X"); /* just ack the data like this. */
2104 cancel++; /* and count it */
2105 BEGIN rdpkt; /* and wait for more data packets. */
2107 } else { /* Not discarding. */
2108 rf_err = "Can't open file";
2109 if (xflg) { /* If screen data */
2110 if (remfile) { /* redirected to file */
2111 if (rempipe) /* or pipe */
2112 x = openc(ZOFILE,remdest); /* Pipe: start command */
2114 x = opena(remdest,&iattr); /* File: open with attributes */
2115 } else { /* otherwise */
2116 x = opent(&iattr); /* "open" the screen */
2118 } else { /* otherwise */
2120 if (calibrate) { /* If calibration run */
2121 x = ckopenx(&iattr); /* open nothing */
2123 if (streaming) /* Streaming */
2124 fastack(); /* ACK without ACKing. */
2126 #endif /* STREAMING */
2127 ack(); /* Send real ACK */
2128 BEGIN rdpkt; /* Proceed to next state */
2131 #endif /* CALIBRATE */
2134 In UNIX we can pipe the file data into the mail program, which is to be
2135 preferred to writing it out to a temp file and then mailing it afterwards.
2136 This depends rather heavily on all UNIXes having a mail command that
2137 accepts '-s "subject"' on the command line. MAILCMD (e.g. mail, Mail, mailx)
2138 is defined in ckufio.c.
2140 if (dispos == 'M') { /* Mail... */
2144 extern char *MAILCMD;
2145 s = iattr.disp.val + 1;
2146 n = (int)strlen(MAILCMD) + /* Mail command */
2147 (int)strlen(s) + /* address */
2148 (int)strlen(ofilnam) + 32; /* subject */
2149 if (tmp = (char *)malloc(n)) {
2151 MAILCMD," -s \"",ofilnam,"\" ",s,
2152 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
2153 debug(F111,"rcv_firsdata mail",tmp,(int)strlen(tmp));
2154 x = openc(ZOFILE,(char *)tmp);
2158 } else if (dispos == 'P') { /* Ditto for print */
2161 extern char *PRINTCMD;
2162 n = (int)strlen(PRINTCMD) + (int)strlen(iattr.disp.val+1) + 4;
2163 if (tmp = (char *)malloc(n)) {
2164 sprintf(tmp, /* safe (prechecked) */
2165 "%s %s", PRINTCMD, iattr.disp.val + 1);
2166 x = openc(ZOFILE,(char *)tmp);
2172 x = opena(filnam,&iattr); /* open the file, with attributes */
2174 if (x) { /* If file was opened ok */
2183 rc = (binary && !parity) ?
2184 bdecode(rdatap,putfil):
2185 decode(rdatap, qf ? puttrm : putfil, 1);
2187 rc = decode(rdatap, qf ? puttrm : putfil, 1);
2188 #endif /* CKTUNING */
2190 errpkt((CHAR *)"Error writing data");
2195 if (streaming) /* Streaming was negotiated */
2196 fastack(); /* ACK without ACKing. */
2198 #endif /* STREAMING */
2199 ack(); /* acknowledge it */
2200 BEGIN rdpkt; /* and switch to receive-data state */
2202 } else { /* otherwise */
2203 errpkt((CHAR *) rf_err); /* send error packet */
2204 RESUME; /* and quit. */
2214 debug(F111,"rcv_shortreply",rdatap,ipktlen);
2215 if (ipktack[0] && !strncmp(ipktack,(char *)rdatap,ipktlen)) {
2216 /* No it's the ACK to the I packet again */
2217 x = scmd(vcmd,(CHAR *)cmarg); /* So send the REMOTE command again */
2218 /* Maybe this should be resend() */
2219 debug(F110,"IPKTZEROHACK",ipktack,x);
2221 errpkt((CHAR *)srimsg);
2227 #endif /* PKTZEROHACK */
2231 if (query) { /* If to query, */
2232 qbufp = querybuf; /* initialize query response buffer */
2238 if (remfile) { /* Response redirected to file */
2239 rf_err = "Can't open file";
2240 if (rempipe) /* or pipe */
2243 zxcmd(ZOFILE,remdest) /* Pipe: Start command */
2249 x = opena(remdest,&iattr); /* File: Open with attributes */
2250 debug(F111,"rcv_shortreply remfile",remdest,x);
2252 x = opent(&iattr); /* "open" the screen */
2254 if (x) { /* If file was opened ok */
2257 (query || !remfile) ? puttrm :
2261 zputfil, 1) < 0) { /* Note: zputfil, not putfil. */
2262 errpkt((CHAR *)"Error writing data");
2266 if (rdatap) /* If we had data */
2267 if (*rdatap) /* add a line terminator */
2268 if (remfile) { /* to file */
2270 } else { /* or to screen. */
2272 if (!query || !xcmdsrc)
2274 if (!(quiet && rcdactive))
2277 if (bye_active && network) { /* I sent BYE or REMOTE LOGOUT */
2278 msleep(500); /* command and got the ACK... */
2283 if (!epktsent && !epktrcvd) /* If no error packet... */
2284 success = 1; /* success. */
2288 } else { /* File not opened OK */
2289 errpkt((CHAR *) rf_err); /* send error message */
2290 RESUME; /* and quit. */
2293 #endif /* NOSERVER */
2296 #endif /* PKTZEROHACK */
2297 debug(F101,"rcv_shortreply fallthru","",success);
2308 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2309 cksyslog(SYSLG_PR, 1, "server", "REMOTE QUERY", (char *)srvcmd);
2310 #endif /* CKSYSLOG */
2312 if (ikdbopen) slotstate(what,"REMOTE QUERY", (char *)(srvcmd+2), "");
2314 c = *(srvcmd+2); /* Q = Query, S = Set */
2315 if (c == 'Q') { /* Query */
2316 if (!ENABLED(en_que)) { /* Security */
2317 errpkt((CHAR *)"REMOTE QUERY disabled");
2320 } else { /* Query allowed */
2322 qbufp = querybuf; /* Wipe out old stuff */
2325 p = (char *) srvcmd + 3; /* Pointer for making wrapper */
2326 n = strlen((char *)srvcmd); /* Position of end */
2327 c = *(srvcmd+4); /* Which type of variable */
2329 if (*(srvcmd+6) == CMDQ) { /* Starts with command quote? */
2330 p = (char *) srvcmd + 6; /* Take it literally */
2331 if (*p == CMDQ) p++;
2332 } else { /* They played by the rules */
2333 if (c == 'K') { /* Kermit variable */
2335 k = (int) strlen(p);
2336 if (k > 0 && p[k-1] == ')') {
2337 p = (char *)(srvcmd + 4);
2339 *(srvcmd+5) = 'f'; /* Function, so make it \f...() */
2341 *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
2342 *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */
2343 *(srvcmd+5) = '('; /* around variable name */
2345 *(srvcmd+n+1) = NUL;
2348 *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
2349 *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */
2350 *(srvcmd+5) = '('; /* around variable name */
2352 *(srvcmd+n+1) = NUL;
2353 if (c == 'S') { /* System variable */
2354 *(srvcmd+4) = '$'; /* so it's \$(...) */
2355 } else if (c == 'G') { /* Non-\ Global variable */
2356 *(srvcmd+4) = 'm'; /* so wrap it in \m(...) */
2359 } /* Now evaluate it */
2360 n = QBUFL; /* Max length */
2361 q = querybuf; /* Where to put it */
2362 if (zzstring(p,&q,&n) < 0) {
2363 errpkt((n > 0) ? (CHAR *)"Can't get value"
2364 : (CHAR *)"Value too long"
2369 if (encstr((CHAR *)querybuf) > -1) { /* Encode it */
2370 ack1(data); /* If it fits, send it back in ACK */
2374 } else if (sndstring(querybuf)) { /* Long form response */
2377 } else { /* sndhlp() fails */
2378 errpkt((CHAR *)"Can't send value");
2384 } else if (c == 'S') { /* Set (assign) */
2385 if (!ENABLED(en_asg)) { /* Security */
2386 errpkt((CHAR *)"REMOTE ASSIGN disabled");
2391 n = xunchar(*(srvcmd+3)); /* Length of name */
2392 n = 3 + n + 1; /* Position of length of value */
2393 *(srvcmd+n) = NUL; /* Don't need it */
2394 if (addmac((char *)(srvcmd+4),(char *)(srvcmd+n+1)) < 0)
2395 errpkt((CHAR *)"REMOTE ASSIGN failed");
2404 errpkt((CHAR *)"Badly formed server command");
2409 errpkt((CHAR *)"Variable query/set not available");
2413 #endif /* NOSERVER */
2420 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2421 cksyslog(SYSLG_PR, 1, "server", "REMOTE COPY", (char *)srvcmd);
2422 #endif /* CKSYSLOG */
2424 if (!ENABLED(en_cpy)) {
2425 errpkt((CHAR *)"REMOTE COPY disabled");
2429 char *str1, *str2, f1[256], f2[256];
2431 len1 = xunchar(srvcmd[1]); /* Separate the parameters */
2432 len2 = xunchar(srvcmd[2+len1]);
2433 strncpy(f1,(char *)(srvcmd+2),len1);
2435 strncpy(f2,(char *)(srvcmd+3+len1),len2);
2438 if (ikdbopen) slotstate(what,"REMOTE COPY", f1, f2);
2440 if (!ENABLED(en_cwd)) { /* If CWD is disabled */
2441 zstrip(f1,&str1); /* and they included a pathname, */
2443 if (strcmp(f1,str1) || strcmp(f2,str2)) { /* Refuse. */
2444 errpkt((CHAR *)"Access denied");
2445 RESUME; /* Remember, this is not a goto! */
2449 if (state == generic) { /* It's OK to go ahead. */
2450 if (zcopy(f1,f2)) { /* Try */
2451 errpkt((CHAR *)"Can't copy file"); /* give error message */
2456 RESUME; /* wait for next server command */
2461 #else /* no ZCOPY */
2462 errpkt((CHAR *)"REMOTE COPY not available"); /* give error message */
2463 RESUME; /* wait for next server command */
2466 #endif /* NOSERVER */
2473 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2474 cksyslog(SYSLG_PR, 1, "server", "REMOTE RENAME", (char *)srvcmd);
2475 #endif /* CKSYSLOG */
2477 if (!ENABLED(en_ren)) {
2478 errpkt((CHAR *)"REMOTE RENAME disabled");
2481 } else { /* RENAME is enabled */
2482 char *str1, *str2, f1[256], f2[256];
2484 len1 = xunchar(srvcmd[1]); /* Separate the parameters */
2485 len2 = xunchar(srvcmd[2+len1]);
2486 strncpy(f1,(char *)(srvcmd+2),len1);
2488 strncpy(f2,(char *)(srvcmd+3+len1),len2);
2490 len2 = xunchar(srvcmd[2+len1]);
2491 strncpy(f1,(char *)(srvcmd+2),len1);
2493 strncpy(f2,(char *)(srvcmd+3+len1),len2);
2496 if (ikdbopen) slotstate(what,"REMOTE RENAME", f1, f2);
2498 if (!ENABLED(en_cwd)) { /* If CWD is disabled */
2499 zstrip(f1,&str1); /* and they included a pathname, */
2501 if ( strcmp(f1,str1) || strcmp(f2,str2) ) { /* refuse. */
2502 errpkt((CHAR *)"Access denied");
2503 RESUME; /* Remember, this is not a goto! */
2507 if (state == generic) { /* It's OK to go ahead. */
2508 if (zrename(f1,f2)) { /* Try */
2509 errpkt((CHAR *)"Can't rename file"); /* Give error msg */
2514 RESUME; /* Wait for next server command */
2519 #else /* no ZRENAME */
2520 /* Give error message */
2521 errpkt((CHAR *)"REMOTE RENAME not available");
2522 RESUME; /* Wait for next server command */
2524 #endif /* ZRENAME */
2525 #endif /* NOSERVER */
2531 char f1[LOGINLEN+1], f2[LOGINLEN+1], f3[LOGINLEN+1];
2535 debug(F101,"REMOTE LOGIN x_login","",x_login);
2536 debug(F101,"REMOTE LOGIN x_logged","",x_logged);
2538 f1[0] = NUL; f2[0] = NUL; f3[0] = NUL;
2540 if (srvcmd[1]) /* First length field */
2541 len = xunchar(srvcmd[1]); /* Separate the parameters */
2543 if (x_login) { /* Login required */
2544 if (x_logged) { /* And already logged in */
2545 if (len > 0) { /* Logging in again */
2546 errpkt((CHAR *)"Already logged in.");
2547 } else { /* Logging out */
2548 debug(F101,"REMOTE LOGOUT","",x_logged);
2550 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2551 cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGOUT", NULL);
2552 #endif /* CKSYSLOG */
2554 if (ikdbopen) slotstate(what,"REMOTE LOGOUT", "", "");
2556 tlog(F110,"Logged out",x_user,0);
2557 ack1((CHAR *)"Logged out");
2566 #endif /* CK_LOGIN */
2568 } else { /* Not logged in yet */
2569 debug(F101,"REMOTE LOGIN len","",len);
2570 if (len > 0) { /* Have username */
2572 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2573 cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGIN", NULL);
2574 #endif /* CKSYSLOG */
2575 if (len > LOGINLEN) {
2576 errpkt((CHAR *)"Username too long");
2578 p = srvcmd + 2; /* Point to it */
2579 for (i = 0; i < len; i++) /* Copy it */
2581 f1[len] = NUL; /* Terminate it */
2582 p += len; /* Point to next length field */
2583 if (*p) { /* If we have one */
2584 len = xunchar(*p++); /* decode it */
2585 if (len > 0 && len <= LOGINLEN) {
2586 for (i = 0; i < len; i++) /* Same deal for password */
2589 p += len; /* And account */
2591 len = xunchar(*p++);
2592 if (len > 0 && len <= LOGINLEN) {
2593 for (i = 0; i < len; i++)
2594 f3[i] = p[i]; /* Set but never used */
2595 f3[len] = NUL; /* (because account not used) */
2600 debug(F101,"REMOTE LOGIN 1","",x_logged);
2603 if (inserver) { /* Log in to system for real */
2604 x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
2605 debug(F101,"REMOTE LOGIN 2","",x_logged);
2606 if (x_logged) { /* Count attempts */
2614 #endif /* CK_LOGIN */
2616 if (x_user && x_passwd) { /* User and password must match */
2617 if (!strcmp(x_user,f1)) /* SET SERVER LOGIN */
2618 if (!strcmp(x_passwd,f2))
2620 debug(F101,"REMOTE LOGIN 3","",x_logged);
2621 } else if (x_user) { /* Only username given, no password */
2622 if (!strcmp(x_user,f1)) /* so only username must match */
2624 debug(F101,"REMOTE LOGIN 4","",x_logged);
2628 x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
2629 debug(F101,"REMOTE LOGIN 5","",x_logged);
2631 #endif /* CK_LOGIN */
2632 if (x_logged) { /* Logged in? */
2633 tlog(F110,"Logged in", x_user, 0);
2635 ack1((CHAR *)"Logged in as guest - restrictions apply");
2637 ack1((CHAR *)"Logged in");
2640 tlog(F110,"Login failed", f1, 0);
2641 errpkt((CHAR *)"Access denied.");
2644 if (inserver && logtries > 2)
2646 #endif /* CK_LOGIN */
2649 } else { /* LOGOUT */
2650 errpkt((CHAR *)"Logout ignored");
2653 } else { /* Login not required */
2655 errpkt((CHAR *)"Login ignored.");
2657 errpkt((CHAR *)"Logout ignored.");
2659 #endif /* NOSERVER */
2666 /* K95 does this its own way */
2670 printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", srvidl);
2671 doexit(GOOD_EXIT,xitsta);
2675 printf("\r\nSERVER IDLE TIMEOUT: %d sec\r\n", srvidl);
2676 xitsta |= (what & W_KERMIT);
2680 else if (fatalio) { /* Connection lost */
2682 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2683 cksyslog(SYSLG_PR, 1, "server", "Connection lost", NULL);
2684 #endif /* CKSYSLOG */
2686 if (ikdbopen) slotstate(what,"SERVER DISCONNECT",(char *)srvcmd, "");
2690 } else if (interrupted) { /* Interrupted by hand */
2691 if (!ENABLED(en_fin)) {
2692 errpkt((CHAR *)"QUIT disabled");
2696 if (what == W_SEND || what == W_RECV || what == W_REMO) {
2699 if (ckxsyslog >= SYSLG_PR && ckxlogging)
2700 cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
2701 #endif /* CKSYSLOG */
2702 } else if (what == W_NOTHING && filcnt == 0) {
2704 } /* Otherwise leave success alone */
2705 xitsta |= (what & W_KERMIT);
2708 } else { /* Shouldn't happen */
2709 debug(F100,"SERVER (top) GOT UNEXPECTED 'q'","",0);
2712 #endif /* NOSERVER */
2720 if (/* state == serve && */ x_login && !x_logged) {
2721 errpkt((CHAR *)"Login required");
2724 #endif /* NOSERVER */
2725 if (state == serve && !ENABLED(en_sen)) { /* Not in server mode */
2726 errpkt((CHAR *)"SEND disabled"); /* when SEND is disabled. */
2729 } else { /* OK to go ahead. */
2731 if (dldir && !f_tmpdir) { /* If they have a download directory */
2732 debug(F110,"receive download dir",dldir,0);
2733 if (s = zgtdir()) { /* Get current directory */
2734 debug(F110,"receive current dir",s,0);
2735 if (zchdir(dldir)) { /* Change to download directory */
2736 debug(F100,"receive zchdir ok","",0);
2737 ckstrncpy(savdir,s,TMPDIRLEN);
2738 f_tmpdir = 1; /* Remember that we did this */
2740 debug(F100,"receive zchdir failed","",0);
2743 #endif /* CK_TMPDIR */
2744 nakstate = 1; /* Can send NAKs from here. */
2745 rinit(rdatap); /* Set parameters */
2750 bctu = bctr; /* switch to agreed-upon block check */
2751 bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
2753 what = W_RECV; /* Remember we're receiving */
2755 resetc(); /* Reset counters */
2756 rtimer(); /* Reset timer */
2759 #endif /* GFTIMER */
2761 BEGIN rfile; /* Go into receive-file state */
2767 /* END OF ROUTINES MOVED OUT OF STATE MACHINE */
2770 /* P R O T O -- Protocol entry function */
2772 static int is_tn = 0; /* It's a Telnet connection */
2775 int f_ctlp = 0; /* Control-character prefix table */
2778 #endif /* COMMENT */
2779 #endif /* CK_SPEED */
2782 This is simply a wrapper for the real protocol function just below,
2783 that saves any items that might be changed automatically by protocol
2784 negotiations and then restores them upon exit from protocol mode.
2788 extern int b_save, f_save, c_save, ss_save, slostart, reliable, urclear;
2790 extern int fcharset, fcs_save, tcharset, tcs_save;
2791 #endif /* NOCSETS */
2794 extern int pipesend;
2795 #endif /* PIPESEND */
2798 extern int cursorena[], cursor_save, term_io;
2800 extern int display_demo;
2803 #endif /* NOLOCAL */
2805 int _u_bin=0, _me_bin = 0;
2807 int /* _u_start=0, */ _me_start = 0;
2808 #endif /* IKS_OPTION */
2813 #endif /* PATTERNS */
2818 #endif /* PATTERNS */
2819 scan_save = filepeek;
2824 if (isguest) { /* If user is anonymous */
2825 en_pri = 0; /* disable printing */
2826 en_mai = 0; /* and disable email */
2827 en_del = 0; /* and file deletion */
2829 #endif /* CK_LOGIN */
2833 cursor_save = cursorena[vmode];
2834 cursorena[vmode] = 0;
2835 term_io_save = term_io;
2838 #endif /* NOLOCAL */
2839 b_save = binary; /* SET FILE TYPE */
2840 f_save = fncnv; /* SET FILE NAMES */
2847 fcs_save = fcharset;
2848 tcs_save = tcharset;
2849 #endif /* NOCSETS */
2852 /* Don't do this because then user can never find out what happened. */
2854 for (i = 0; i < 256; i++)
2855 s_ctlp[i] = ctlp[i];
2857 #endif /* CK_SPEED */
2858 #endif /* COMMENT */
2859 if (reliable == SET_ON)
2861 is_tn = (!local && sstelnet)
2863 || (local && network && ttnproto == NP_TELNET)
2868 if (tn_b_xfer && !(sstelnet || inserver)) {
2869 /* Save the current state of Telnet Binary */
2870 _u_bin = TELOPT_U(TELOPT_BINARY);
2871 _me_bin = TELOPT_ME(TELOPT_BINARY);
2873 /* If either direction is not Binary attempt to negotiate it */
2874 if (!_u_bin && TELOPT_U_MODE(TELOPT_BINARY) != TN_NG_RF) {
2875 tn_sopt(DO,TELOPT_BINARY);
2876 TELOPT_UNANSWERED_DO(TELOPT_BINARY) = 1;
2878 if (!_me_bin && TELOPT_ME_MODE(TELOPT_BINARY) != TN_NG_RF) {
2879 tn_sopt(WILL,TELOPT_BINARY);
2880 TELOPT_UNANSWERED_WILL(TELOPT_BINARY) = 1;
2882 if (!(_me_bin && _u_bin))
2883 tn_wait("proto set binary mode");
2887 if (protocol != PROTO_K) { /* Non-Kermit protocol selected */
2888 if (TELOPT_U(TELOPT_KERMIT) &&
2889 TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2890 iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
2893 if (TELOPT_ME(TELOPT_KERMIT) &&
2894 TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2895 tn_siks(KERMIT_STOP); /* I'm not servering */
2896 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2901 if (sstate == 'x' || sstate == 'v') { /* Responding to a request */
2902 if (!inserver && TELOPT_U(TELOPT_KERMIT) &&
2903 TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2904 iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
2907 if (TELOPT_ME(TELOPT_KERMIT) &&
2908 !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2909 tn_siks(KERMIT_START); /* Send Kermit-Server Start */
2910 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1;
2912 } else { /* Initiating a request */
2913 if (TELOPT_ME(TELOPT_KERMIT) &&
2914 TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2915 tn_siks(KERMIT_STOP); /* I'm not servering */
2916 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2919 if (TELOPT_U(TELOPT_KERMIT) &&
2920 !TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
2921 /* Send Req-Server-Start */
2922 if (!iks_wait(KERMIT_REQ_START,0)) {
2923 if (sstate != 's') {
2924 success = 0; /* Other Kermit refused to serve */
2926 printf("A Kermit Server is not available\r\n");
2927 debug(F110,"proto()",
2928 "A Kermit Server is not available",0);
2929 tlog(F110,"IKS client/server failure",
2930 "A Kermit Server is not available",0);
2936 #endif /* IKS_OPTION */
2937 #ifdef CK_ENCRYPTION
2938 if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
2941 #endif /* CK_ENCRYPTION */
2945 if (!xfrint) connoi();
2946 xxproto(); /* Call the real protocol function */
2950 #endif /* IKS_OPTION */
2951 xferstat = success; /* Remember transfer status */
2955 #ifdef CK_ENCRYPTION
2956 if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
2959 #endif /* CK_ENCRYPTION */
2961 if (TELOPT_ME(TELOPT_KERMIT) &&
2962 TELOPT_SB(TELOPT_KERMIT).kermit.me_start && !_me_start) {
2963 tn_siks(KERMIT_STOP); /* Server is stopped */
2964 TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2966 #endif /* IKS_OPTION */
2967 if (is_tn && tn_b_xfer && !(sstelnet || inserver)) {
2968 /* if we negotiated Binary mode try to reset it */
2970 /* Check to see if the state changed during the transfer */
2971 if (TELOPT_U(TELOPT_BINARY)) {
2972 tn_sopt(DONT,TELOPT_BINARY);
2973 TELOPT_UNANSWERED_DONT(TELOPT_BINARY) = 1;
2975 _u_bin = 1; /* So we don't call tn_wait() */
2978 /* Check to see if the state changed during the transfer */
2979 if (TELOPT_ME(TELOPT_BINARY)) {
2980 tn_sopt(WONT,TELOPT_BINARY);
2981 TELOPT_UNANSWERED_WONT(TELOPT_BINARY) = 1;
2983 _me_bin = 1; /* So we don't call tn_wait() */
2985 if (!(_me_bin && _u_bin))
2986 tn_wait("proto reset binary mode");
2992 #endif /* PATTERNS */
2993 filepeek = scan_save;
2998 #endif /* STREAMING */
3001 for (i = 0; i < 256; i++)
3002 ctlp[i] = s_ctlp[i];
3004 #endif /* CK_SPEED */
3005 #endif /* COMMENT */
3008 xitsta |= (what & W_KERMIT);
3009 tlog(F110," failed:",(char *)epktmsg,0);
3011 debug(F111,"proto xferstat",epktmsg,xferstat);
3013 if (s_timint > -1) { /* Because of REMOTE SET */
3019 if (c_save > -1) { /* Because of REMOTE SET */
3026 pipesend = 0; /* Next time might not be pipesend */
3027 #endif /* PIPESEND */
3030 cursorena[vmode] = cursor_save;
3031 term_io = term_io_save;
3034 #endif /* NOLOCAL */
3043 _PROTOTYP( int pxyz, (int) );
3044 #endif /* XYZ_INTERNAL */
3047 char xss[2]; /* String representation of sstate */
3052 debug(F101,"xxproto entry justone","",justone);
3055 retrieve = 0; /* Reset these ... */
3059 if (local && ttchk() < 0) { /* Giving BYE or FIN */
3060 if (bye_active) { /* but there is no connection */
3065 /* Ditto for any REMOTE command */
3066 if (sstate == 'g' && cmarg ) {
3067 if (*cmarg == 'L' || *cmarg == 'F' || *cmarg == 'X')
3070 printf("?No connection\r\n");
3075 /* Set up the communication line for file transfer. */
3076 /* NOTE: All of the xxscreen() calls prior to the wart() invocation */
3077 /* could just as easily be printf's or, for that matter, hints. */
3079 if (local && (speed < 0L) && (network == 0)) {
3080 xxscreen(SCR_EM,0,0L,"Sorry, you must 'set speed' first");
3084 if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {
3085 debug(F111,"failed: proto ttopen local",ttname,local);
3086 xxscreen(SCR_EM,0,0L,"Can't open line");
3089 if (x > -1) local = x;
3090 debug(F111,"proto ttopen local",ttname,local);
3092 lx = (local && !network) ? speed : -1;
3096 ctlp[(unsigned)255] = ctlp[CR] = 1;
3097 if (parity == 'e' || parity == 'm') ctlp[127] = 1;
3098 if (flow == FLO_XONX) { /* Also watch out for Xon/Xoff */
3099 ctlp[17] = ctlp[19] = 1;
3100 ctlp[17+128] = ctlp[19+128] = 1;
3103 #endif /* CK_SPEED */
3104 #endif /* NETCONN */
3105 if (ttpkt(lx,flow,parity) < 0) { /* Put line in packet mode, */
3106 xxscreen(SCR_EM,0,0L,"Can't condition line");
3109 if (local && !network && carrier != CAR_OFF) {
3110 int x; /* Serial connection */
3111 x = ttgmdm(); /* with carrier checking */
3113 if (!(x & BM_DCD)) {
3114 debug(F101,"proto ttgmdm","",0);
3115 xxscreen(SCR_EM,0,0L,"Carrier required but not detected");
3120 /* Send remote side's "receive" or "server" startup string, if any */
3121 if (local && ckindex((char *)xss,"srgcjhk",0,0,1)) {
3125 /* Don't send auto-blah string if we know other side is serving */
3126 !TELOPT_U(TELOPT_KERMIT) ||
3127 !TELOPT_SB(TELOPT_KERMIT).kermit.u_start
3130 #endif /* IKS_OPTION */
3132 if (sstate == 's') { /* Sending file(s) */
3133 s = binary ? ptab[protocol].h_b_init : ptab[protocol].h_t_init;
3134 } else if (protocol == PROTO_K) { /* Command for server */
3135 s = ptab[protocol].h_x_init;
3139 #ifndef UNPREFIXZERO
3140 if (protocol == PROTO_K) /* Because of C-strings... */
3142 #endif /* UNPREFIXZERO */
3143 #endif /* CK_SPEED */
3144 if (s) if (*s) { /* If we have a command to send... */
3146 int tmpbufsiz = 356;
3147 int stuff = -1, stuff2 = -1, len = 0;
3149 if (sstate == 's') { /* Sending file(s) */
3151 if (protocol == PROTO_X) {
3153 s2 = cmarg2[0] ? cmarg2 : cmarg;
3154 if ((int)strlen(s) + (int)strlen(s2) + 4 < 356)
3155 sprintf(tmpbuf, s, s2);
3160 ckmakmsg(tmpbuf, 356, s, NULL, NULL, NULL);
3164 } else { /* Command for server */
3165 ckstrncpy(tmpbuf,s,356);
3167 ckstrncat(tmpbuf, "\015",sizeof(tmpbuf));
3168 if (tnlm) /* TERMINAL NEWLINE ON */
3169 stuff = LF; /* Stuff LF */
3171 /* TELNET NEWLINE MODE */
3173 switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) {
3189 if (network && ttnproto == NP_RLOGIN) {
3190 switch (tn_b_nlm) { /* Always BINARY */
3203 #endif /* RLOGCODE */
3204 #endif /* TCPSOCKET */
3205 #endif /* NETCONN */
3207 len = strlen(tmpbuf);
3208 if (stuff >= 0 && len < tmpbufsiz - 1) {
3209 tmpbuf[len++] = stuff;
3210 if (stuff2 >= 0 && len < tmpbufsiz - 1)
3211 tmpbuf[len++] = stuff2;
3214 ttol((CHAR *)tmpbuf,len);
3215 if (protocol == PROTO_K) /* Give remote Kermit time to start */
3221 if (protocol != PROTO_K) { /* Non-Kermit protocol selected */
3223 int tmpbufsiz = 356;
3227 if (sstate == 'v') { /* If receiving and... */
3228 if (dldir && !f_tmpdir) { /* if they have a download directory */
3229 if (s = zgtdir()) { /* Get current directory */
3230 if (zchdir(dldir)) { /* Change to download directory */
3231 ckstrncpy(savdir,s,TMPDIRLEN);
3232 f_tmpdir = 1; /* Remember that we did this */
3237 #endif /* CK_TMPDIR */
3239 #ifdef XYZ_INTERNAL /* Internal */
3240 success = !pxyz(sstate);
3242 #ifdef CK_REDIR /* External */
3244 case 's': /* 'Tis better to SEND... */
3245 s = binary ? ptab[protocol].p_b_scmd : ptab[protocol].p_t_scmd;
3247 case 'v': /* ... than RECEIVE */
3248 s = binary ? ptab[protocol].p_b_rcmd : ptab[protocol].p_t_rcmd;
3253 if (sstate == 's') { /* Sending */
3254 extern int xfermode;
3255 int k = 0, x = 0, b = binary;
3257 If just one file we can scan it to set the xfer mode.
3258 Otherwise it's up to the external protocol program.
3260 if (patterns && xfermode == XMODE_A && !iswild(fspec)) {
3261 extern int nscanfile;
3262 k = scanfile(fspec,&x,nscanfile);
3264 b = (k == FT_BIN) ? XYFT_B : XYFT_T;
3266 ptab[protocol].p_b_scmd :
3267 ptab[protocol].p_t_scmd;
3270 if ((int)strlen(s) + (int)strlen(fspec) < tmpbufsiz) {
3271 sprintf(tmpbuf,s,fspec); /* safe (prechecked) */
3272 tlog(F110,"Sending",fspec,0L);
3274 } else { /* Receiving */
3275 if ((int)strlen(s) + (int)strlen(cmarg2) < tmpbufsiz) {
3276 sprintf(tmpbuf,s,cmarg2); /* safe (prechecked) */
3277 tlog(F110,"Receiving",cmarg2,0L);
3280 tlog(F110," via external protocol:",tmpbuf,0);
3281 debug(F110,"ckcpro ttruncmd",tmpbuf,0);
3282 success = ttruncmd(tmpbuf);
3283 tlog(F110," status:",success ? "OK" : "FAILED", 0);
3285 printf("?Sorry, no external protocol defined for %s\r\n",
3286 ptab[protocol].p_name
3291 "Sorry, only Kermit protocol is supported in this version of Kermit\n"
3293 #endif /* CK_REDIR */
3294 #endif /* XYZ_INTERNAL */
3304 connoi(); /* No console interrupts if remote */
3308 if (sstate == 'x') { /* If entering server mode, */
3309 extern int howcalled;
3310 server = 1; /* set flag, */
3311 debug(F101,"server backgrd","",backgrd);
3312 debug(F101,"server quiet","",quiet);
3313 debug(F100,"SHOULD NOT SEE THIS IF IN BACKGROUND!","",0);
3314 if (howcalled == I_AM_SSHSUB) { /* and issue appropriate message. */
3315 ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
3316 } else if (!local) {
3317 if (!quiet && !backgrd
3319 && !TELOPT_ME(TELOPT_KERMIT) /* User was told by negotiation */
3320 #endif /* IKS_OPTION */
3323 conoll("KERMIT READY TO SERVE...");
3326 conol("Entering server mode on ");
3328 conoll("Type Ctrl-C to quit.");
3329 if (srvdis) intmsg(-1L);
3332 if (network && tcpsrfd > 0)
3333 ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
3334 #endif /* NOLISTEN */
3335 #endif /* TCPSOCKET */
3340 if (!quiet && !backgrd) /* So message doesn't overwrite prompt */
3342 if (local) conres(); /* So Ctrl-C will work */
3345 If in remote mode, not shushed, not in background, and at top command level,
3346 issue a helpful message telling what to do...
3348 if (!local && !quiet && !backgrd) {
3349 if (sstate == 'v') {
3350 conoll("Return to your local Kermit and give a SEND command.");
3352 conoll("KERMIT READY TO RECEIVE...");
3353 } else if (sstate == 's') {
3354 conoll("Return to your local Kermit and give a RECEIVE command.");
3356 conoll("KERMIT READY TO SEND...");
3357 } else if ( sstate == 'g' || sstate == 'r' || sstate == 'h' ||
3358 sstate == 'j' || sstate == 'c' ) {
3359 conoll("Return to your local Kermit and give a SERVER command.");
3361 conoll((sstate == 'r' || sstate == 'j' || sstate == 'h') ?
3362 "KERMIT READY TO GET..." :
3363 "KERMIT READY TO SEND SERVER COMMAND...");
3367 if (!local) sleep(1);
3368 #endif /* COMMENT */
3370 The 'wart()' function is generated by the wart program. It gets a
3371 character from the input() routine and then based on that character and
3372 the current state, selects the appropriate action, according to the state
3373 table above, which is transformed by the wart program into a big case
3374 statement. The function is active for one transaction.
3376 rtimer(); /* Reset elapsed-time timer */
3379 #endif /* GFTIMER */
3380 resetc(); /* & other per-transaction counters. */
3382 debug(F101,"proto calling wart, justone","",justone);
3384 wart(); /* Enter the state table switcher. */
3386 Note: the following is necessary in case we have just done a remote-mode
3387 file transfer, in which case the controlling terminal modes have been
3388 changed by ttpkt(). In particular, special characters like Ctrl-C and
3389 Ctrl-\ might have been turned off (see ttpkt). So this call to ttres() is
3390 essential. IMPORTANT: restore interrupt handlers first, otherwise any
3391 terminal interrupts that occur before this is done in the normal place
3392 later will cause a crash.
3395 ttres(); /* Reset the communication device */
3398 setint(); /* Arm interrupt handlers FIRST */
3400 ttres(); /* Then restore terminal. */
3403 xxscreen(SCR_TC,0,0L,""); /* Transaction complete */
3406 clsif(); /* Failsafe in case we missed */
3407 clsof(1); /* a case in the state machine. */
3410 if (server) { /* Back from packet protocol. */
3411 if (!quiet && !backgrd
3415 ) { /* Give appropriate message */
3417 conoll("C-Kermit server done");
3419 server = 0; /* Not a server any more */
3423 /* S G E T I N I T -- Handle incoming GET-Class packets */
3428 0: GET packet processed OK - ready to Send.
3429 1: Extended GET processed OK - wait for another.
3432 sgetinit(reget,xget) int reget, xget; { /* Server end of GET command */
3433 char * fs = NULL; /* Pointer to filespec */
3436 extern int usepipes, pipesend;
3437 #endif /* PIPESEND */
3440 if (!ENABLED(en_get)) { /* Only if not disabled! */
3441 errpkt((CHAR *)"GET disabled");
3447 nolinks = recursive;
3451 /* If they are alike this was already done in whoarewe() */
3452 debug(F101,"sgetinit whatru","",whatru);
3453 if (whatru & WMI_FLAG) { /* Did we get WHATAMI info? */
3454 debug(F101,"sgetinit binary (1)","",binary);
3456 if (binary != XYFT_I && binary != XYFT_L)
3459 if (binary != XYFT_L)
3462 binary = (whatru & WMI_FMODE) ? /* Yes, set file type */
3463 XYFT_B : XYFT_T; /* automatically */
3464 debug(F101,"sgetinit binary (2)","",binary);
3466 fncnv = (whatru & WMI_FNAME) ? 1 : 0; /* And name conversion */
3468 #endif /* WHATAMI */
3470 fs = (char *)srvcmd;
3471 srvptr = srvcmd; /* Point to server command buffer */
3472 decode(rdatap,putsrv,0); /* Decode the GET command into it */
3473 /* Accept multiple filespecs */
3474 cmarg2 = ""; /* Don't use cmarg2 */
3475 cmarg = ""; /* Don't use cmarg */
3477 done = 1; /* Only 1 packet needed... */
3478 if (xget) { /* Special decoding for Extended GET */
3479 char L, next, c; /* PLV items */
3480 int len, val; /* More PLV items */
3481 char * p = (char *)srvcmd; /* String to decode */
3483 done = 0; /* Maybe more packets needed */
3484 fs = NULL; /* We don't know the filespec yet */
3485 c = *p++; /* Get first parameter */
3487 while (c) { /* For all parameters... */
3488 debug(F000,"sgetinit c","",c);
3489 L = *p++; /* Get length */
3490 if (L >= SP) /* Decode length */
3492 else if (c == '@') { /* Allow missing EOP length field */
3495 len = (xunchar(*p++) * 95);
3496 len += xunchar(*p++);
3498 debug(F101,"sgetinit len","",len);
3499 next = *(p+len); /* Get next parameter */
3500 *(p+len) = NUL; /* Zero it out to terminal value */
3501 debug(F110,"sgetinit p",p,0);
3502 switch (c) { /* Do the parameter */
3503 case 'O': /* GET Options */
3504 val = atoi(p); /* Convert to int */
3505 debug(F101,"sgetinit O val","",val);
3506 if (val & GOPT_DEL) moving = 1;
3507 if (val & GOPT_RES) reget = 1;
3508 if (val & GOPT_REC) {
3511 if (fnspath == PATH_OFF)
3515 case 'M': /* Transfer Mode */
3517 debug(F101,"sgetinit M val","",val);
3520 patterns = 0; /* Takes precedence over patterns */
3521 filepeek = 0; /* and FILE SCAN */
3522 if (val == GMOD_TXT) binary = XYFT_T; /* Text */
3523 if (val == GMOD_BIN) binary = XYFT_B; /* Binary */
3524 if (val == GMOD_LBL) binary = XYFT_L; /* Labeled */
3526 case 'F': /* Filename */
3528 debug(F110,"sgetinit filename",fs,0);
3530 case '@': /* End Of Parameters */
3532 debug(F100,"sgetinit EOP","",0);
3535 errpkt((CHAR *)"Unknown GET Parameter");
3536 debug(F100,"sgetinit unknown parameter","",0);
3543 if (!fs) fs = ""; /* A filename is required */
3546 n = 0; /* Check for quoted name */
3547 if ((n = strlen(fs)) > 1) {
3548 /* Note: this does not allow for multiple quoted names */
3549 if ((fs[0] == '{' && fs[n-1] == '}') ||
3550 (fs[0] == '"' && fs[n-1] == '"')) {
3553 debug(F111,"sgetinit unquoted filename",fs,n);
3555 n = 0; /* This means no quoting */
3559 debug(F111,"sgetinit",fs,usepipes);
3560 if (usepipes && ENABLED(en_hos) && *fs == '!') {
3561 cmarg = fs + 1; /* Point past the bang */
3565 debug(F111,"sgetinit pipesend",cmarg,pipesend);
3567 if (!pipesend) { /* If it's not a pipe */
3568 #endif /* PIPESEND */
3569 if (n == 0) { /* If the name was not quoted */
3571 nfils = fnparse(fs); /* Allow it to be a list of names */
3572 debug(F111,"sgetinit A",fs,nfils);
3574 /* This doesn't work if a GET-PATH is set. */
3575 if (nfils == 1 && !iswild(fs)) { /* Single file */
3577 if ((x = zchki(fs)) < 0) { /* Check if it's sendable */
3579 case -1: m = "File not found"; break;
3580 case -2: m = "Not a regular file"; break;
3581 case -3: m = "Read access denied"; break;
3587 #endif /* COMMENT */
3588 } else { /* If it was quoted */
3589 #endif /* NOMSEND */
3592 if (matchdot) nzxopts |= ZX_MATCHDOT;
3593 #endif /* UNIXOROSK */
3594 if (recursive) nzxopts |= ZX_RECURSE;
3595 /* Treat as a single filespec */
3596 nfils = 0 - nzxpand(fs,nzxopts);
3597 debug(F111,"sgetinit B",fs,nfils);
3602 #endif /* PIPESEND */
3604 if (!done) { /* Need more O packets... */
3605 debug(F100,"sgetinit O-Packet TBC","",0); /* To Be Continued */
3608 debug(F100,"sgetinit O-Packet done - havefs","",havefs);
3609 if (!havefs) { /* Done - make sure we have filename */
3610 errpkt((CHAR *)"GET without filename");
3614 winlo = 0; /* Back to packet 0 again. */
3615 debug(F101,"sgetinit winlo","",winlo);
3616 nakstate = 0; /* Now I'm the sender! */
3617 if (reget) sendmode = SM_RESEND;
3618 if (sinit() > 0) { /* Send Send-Init */
3621 #endif /* STREAMING */
3622 timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
3623 return(0); /* If successful, switch state */
3624 } else return(-1); /* Else back to server command wait */