1 char *fnsv = "C-Kermit functions, 9.0.233, 3 Jun 2011";
3 char *nm[] = { "Disabled", "Local only", "Remote only", "Enabled" };
5 /* C K C F N S -- System-independent Kermit protocol support functions. */
7 /* ...Part 1 (others moved to ckcfn2,3 to make this module smaller) */
10 Author: Frank da Cruz <fdc@columbia.edu>,
11 Columbia University Academic Information Systems, New York City.
13 Copyright (C) 1985, 2011,
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.
19 System-dependent primitives defined in:
21 ck?tio.c -- terminal (communications) i/o
22 cx?fio.c -- file i/o, directory structure
24 #include "ckcsym.h" /* Needed for Stratus VOS */
25 #include "ckcasc.h" /* ASCII symbols */
26 #include "ckcdeb.h" /* Debug formats, typedefs, etc. */
27 #include "ckcker.h" /* Symbol definitions for Kermit */
28 #include "ckcxla.h" /* Character set symbols */
29 #include "ckcnet.h" /* VMS definition of TCPSOCKET */
37 int docrc = 0; /* Accumulate CRC for \v(crc16) */
38 long crc16 = 0L; /* File CRC = \v(crc16) */
39 int gnferror = 0; /* gnfile() failure reason */
42 extern int byteorder, xflg, what, fmask, cxseen, czseen, nscanfile, sysindex;
43 extern int xcmdsrc, dispos, matchfifo;
51 #endif /* CKSYMLINK */
52 #endif /* VMSORUNIX */
61 extern int apcactive, adl_ask;
68 /* (move these prototypes to the appropriate .h files...) */
73 _PROTOTYP( int getvnum, (char *) );
77 _PROTOTYP( static int bgetpkt, (int) );
79 _PROTOTYP( int lookup, (struct keytab[], char *, int, int *) );
82 _PROTOTYP( int zzstring, (char *, char **, int *) );
96 /* Externals from ckcmai.c */
98 extern int srvcdmsg, srvidl, idletmo;
99 extern char * cdmsgfile[];
100 extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
101 rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr, xitsta;
102 extern int pktnum, bctr, bctu, bctf, bctl, clfils, sbufnum, protocol,
103 size, osize, spktl, nfils, ckwarn, timef, spsizf, sndtyp, rcvtyp, success;
104 extern int parity, turn, network, whatru, fsecs, justone, slostart,
105 ckdelay, displa, mypadn, moving, recursive, nettype;
108 tfc, fsize, sendstart, rs_len, flci, flco, tlci, tlco, calibrate;
109 extern long filrej, oldcps, cps, peakcps, ccu, ccp, filestatus;
110 extern int fblksiz, frecl, frecfm, forg, fcctrl, fdispla, skipbup;
111 extern int spackets, rpackets, timeouts, retrans, crunched, wmax, wcur;
112 extern int hcflg, binary, fncnv, b_save, f_save, server;
113 extern int nakstate, discard, rejection, local, xfermode, interrupted;
114 extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
115 extern int fnspath, fnrpath, eofmethod, diractive, whatru2, wearealike;
116 extern int atcapr, atcapb, atcapu;
117 extern int lpcapr, lpcapb, lpcapu;
118 extern int swcapr, swcapb, swcapu;
119 extern int lscapr, lscapb, lscapu;
120 extern int rscapr, rscapb, rscapu;
121 extern int rptena, rptmin;
122 extern int sseqtbl[];
123 extern int numerrs, nzxopts;
128 extern int carrier, ttprty;
129 extern int g_fnrpath;
132 #endif /* TCPSOCKET */
135 extern int sndxin, sndxhi, sndxlo;
138 extern int g_binary, g_fncnv;
141 extern CKFLOAT fpfsecs;
145 extern struct zattr iattr;
150 #endif /* PIPESEND */
154 extern int streamrq, streaming, streamed, streamok;
155 #endif /* STREAMING */
156 extern int reliable, clearrq, cleared, urclear;
159 atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
160 attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
162 extern int bigsbsiz, bigrbsiz;
164 extern char *filefile;
165 extern char whoareu[], * cksysid;
169 extern char * getpath[];
170 extern int fromgetpath;
171 #endif /* NOSERVER */
175 #endif /* CK_LOGIN */
177 extern int srvcmdlen;
178 extern CHAR *srvcmd, * epktmsg;
179 extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, myrptq;
180 extern CHAR *data, padbuf[], stchr, mystch;
183 extern char *cmarg, *cmarg2, **cmlist, filnam[], ofilnam[];
184 extern char *rfspec, *prfspec, *rrfspec, *prrfspec, *sfspec, *psfspec, *rfspec;
189 extern struct filelist * filehead, * filenext;
193 _PROTOTYP( int lslook, (unsigned int b) ); /* Locking Shift Lookahead */
194 _PROTOTYP( int szeof, (CHAR *s) );
195 _PROTOTYP( VOID fnlist, (void) );
200 /* Character set Translation */
203 extern int tcharset, fcharset, dcset7, dcset8;
204 extern int fcs_save, tcs_save;
205 extern int ntcsets, xlatype, cseqtab[];
206 extern struct csinfo tcsinfo[], fcsinfo[];
207 extern int r_cset, s_cset, afcset[];
209 extern int ucsorder, fileorder;
212 _PROTOTYP( CHAR ident, (CHAR) ); /* Identity translation function */
214 /* Arrays of and pointers to character translation functions */
217 extern CHAR (*rx)(CHAR); /* Pointer to input character translation function */
218 extern CHAR (*sx)(CHAR); /* Pointer to output character translation function */
219 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Byte-to-Byte Send */
220 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Byte-to-Byte Recv */
222 extern int (*xut)(USHORT); /* Translation function UCS to TCS */
223 extern int (*xuf)(USHORT); /* Translation function UCS to FCS */
224 extern USHORT (*xtu)(CHAR); /* Translation function TCS to UCS */
225 extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */
228 #else /* The same declarations again for non-ANSI comilers... */
232 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();
233 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();
237 extern USHORT (*xtu)();
238 extern USHORT (*xfu)();
240 #endif /* CK_ANSIC */
243 /* (PWP) external def. of things used in buffered file input and output */
246 extern char *zinbuffer, *zoutbuffer;
248 extern char zinbuffer[], zoutbuffer[];
250 extern char *zinptr, *zoutptr;
251 extern int zincnt, zoutcnt, zobufsize, xfrxla;
253 extern long crcta[], crctb[]; /* CRC-16 generation tables */
254 extern int rseqtbl[]; /* Rec'd-packet sequence # table */
258 /* Criteria used by gnfile()... */
260 char sndafter[19] = { NUL, NUL };
261 char sndbefore[19] = { NUL, NUL };
262 char sndnafter[19] = { NUL, NUL };
263 char sndnbefore[19] = { NUL, NUL };
264 char *sndexcept[NSNDEXCEPT] = { NULL, NULL };
265 char *rcvexcept[NSNDEXCEPT] = { NULL, NULL };
266 CK_OFF_T sndsmaller = (CK_OFF_T)-1;
267 CK_OFF_T sndlarger = (CK_OFF_T)-1;
269 /* Variables defined in this module but shared by other modules. */
272 char * ofperms = ""; /* Output file permissions */
273 int autopath = 0; /* SET RECEIVE PATHNAMES AUTO flag */
283 16, 45, 98, 3, 52, 41, 14, 7, 76,165,122, 11,104, 77,166, 15,
284 160, 93, 18, 19,112, 85, 54, 23,232,213, 90, 27, 12, 81,126, 31,
285 4,205, 34, 35,144, 73,110, 39, 28,133,218, 43,156, 65,102, 47,
286 84, 61, 50, 51,208,117, 86, 55, 8,245, 74, 59, 44,125,222, 63,
287 80, 1,162, 67,116,105,206, 71,120, 9,250, 75, 88, 97, 6, 79,
288 100,221, 82, 83, 36, 89, 94, 87, 40, 21,106, 91,236,145,150, 95,
289 228, 33,130, 99,148,137,198,103,108,169, 42,107,184,129, 78,111,
290 0, 49,114,115, 32,121,254,119,172, 57,138,123,152,177, 22,127,
291 240,193, 2,131,176, 5, 38,135,204,229, 10,139,200,161,174,143,
292 128, 17,146,147, 68,153, 30,151, 72,217,170,155, 24,209, 62,159,
293 64,225,194,163,244,201, 70,167,216,197,234,171,188,109,230,175,
294 212,113,178,179,132,185,190,183,136,249,202,187, 92,241,118,191,
295 48,237, 66,195, 96,233,142,199,248, 37, 58,203, 60, 13,134,207,
296 20, 29,210,211,164,149,182,215,220, 25, 26,219,124,157,246,223,
297 180,141,226,227,192,101,238,231, 56, 69,154,235,252,173, 46,239,
298 224,253,242,243,196, 53,214,247,168,181,186,251,140,189,158,255
300 #endif /* CALIBRATE */
302 char * rf_err = "Error receiving file"; /* rcvfil() error message */
305 short ctlp[256] = { /* Control-Prefix table */
306 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* C0 */
307 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* G0 */
308 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
309 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* DEL */
310 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* C1 */
311 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* G1 */
312 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
313 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 /* 255 */
315 #endif /* CK_SPEED */
317 int sndsrc; /* Flag for where to get names of files to send: */
318 /* -1: znext() function */
320 /* >0: list in cmlist or other list */
323 int memstr; /* Flag for input from memory string */
324 int funcstr; /* Flag for input from function */
328 int gnf_binary = 0; /* Prevailing xfer mode for gnfile */
333 #define MYINITLEN 100
335 CHAR myinit[MYINITLEN]; /* Copy of my Send-Init data */
337 /* Variables local to this module */
342 #endif /* XYZ_INTERNAL */
344 "rename", "replace", "backup", "append", "discard", "ask",
345 "update", "dates-differ", ""
349 static char *memptr; /* Pointer for memory strings */
358 static int lastchar = 0;
359 #endif /* CK_CTRLZ */
362 static int (*funcptr)(void); /* Pointer for function strings */
364 static int (*funcptr)();
365 #endif /* CK_ANSIC */
369 static char cmdstr[50]; /* System command string. */
375 #endif /* BIGBUFOK */
376 static char cmdstr[CMDSTRL+1];
379 static int drain; /* For draining stacked-up ACKs. */
381 static int first; /* Flag for first char from input */
382 static CHAR t; /* Current character */
384 static CHAR next; /* Next character */
387 static int ebqsent = 0; /* 8th-bit prefix bid that I sent */
388 static int lsstate = 0; /* Locking shift state */
389 static int lsquote = 0; /* Locking shift quote */
393 /* E N C S T R -- Encode a string from memory. */
396 Call this instead of getpkt() if source is a string, rather than a file.
397 Note: Character set translation is never done in this case.
403 CHAR encbuf[ENCBUFL];
405 /* This is gross, but the pdp11 root segment is out of space */
406 /* Will allocate it in ckuusr.c. */
407 extern CHAR encbuf[];
412 Encode packet data from a string in memory rather than from a file.
413 Returns the length of the encoded string on success, -1 if the string
414 could not be completely encoded into the currently negotiated data
422 #endif /* CK_ANSIC */
425 Recoded 30 Jul 94 to use the regular data buffer and the negotiated
426 maximum packet size. Previously we were limited to the length of encbuf[].
427 Also, to return a failure code if the entire encoded string would not fit.
428 Modified 14 Jul 98 to return length of encoded string.
430 int m, rc, slen; char *p;
431 if (!data) { /* Watch out for null pointers. */
432 debug(F100,"SERIOUS ERROR: encstr data == NULL","",0);
435 if (!s) s = (CHAR *)""; /* Ditto. */
436 slen = strlen((char *)s); /* Length of source string. */
437 debug(F111,"encstr",s,slen);
438 rc = 0; /* Return code. */
439 m = memstr; p = memptr; /* Save these. */
440 memptr = (char *)s; /* Point to the string. */
441 /* debug(F101,"encstr memptr 1","",memptr); */
442 memstr = 1; /* Flag memory string as source. */
443 first = 1; /* Initialize character lookahead. */
444 *data = NUL; /* In case s is empty */
445 debug(F101,"encstr spsiz","",spsiz);
446 rc = getpkt(spsiz,0); /* Fill a packet from the string. */
447 debug(F101,"encstr getpkt rc","",rc);
448 if (rc > -1 && memptr < (char *)(s + slen)) { /* Means we didn't encode */
449 rc = -1; /* the whole string. */
450 debug(F101,"encstr string too big","",size);
452 debug(F101,"encstr getpkt rc","",rc);
453 memstr = m; /* Restore memory string flag */
454 memptr = p; /* and pointer */
455 first = 1; /* Put this back as we found it. */
459 /* Output functions passed to 'decode': */
461 int /* Put character in server command buffer */
465 putsrv(c) register char c;
466 #endif /* CK_ANSIC */
469 *srvptr = '\0'; /* Make sure buffer is null-terminated */
473 int /* Output character to console. */
477 puttrm(c) register char c;
478 #endif /* CK_ANSIC */
480 extern int rcdactive;
482 extern char * qbufp; /* If REMOTE QUERY active, */
483 extern int query, qbufn; /* also store response in */
484 if (query && qbufn++ < 1024) { /* query buffer. */
488 if (!query || !xcmdsrc)
491 This routine is used (among other things) for printing the server's answer
492 to a REMOTE command. But REMOTE CD is special because it isn't really
493 asking for an answer from the server. Thus some people want to suppress
494 the confirmation message (e.g. when the server sends back the actual path
495 of the directory CD'd to), and expect to be able to do this with SET QUIET
496 ON. But they would not want SET QUIET ON to suppress the other server
497 replies, which are pointless without their answers. Thus the "rcdactive"
498 flag (REMOTE CD command is active). Thu Oct 10 16:38:21 2002
500 if (!(quiet && rcdactive)) /* gross, yuk */
506 int /* Output char to file. */
508 putmfil(char c) /* Just like putfil but to ZMFILE */
509 #else /* rather than ZOFILE... */
510 putmfil(c) register char c;
511 #endif /* CK_ANSIC */
513 debug(F000,"putfil","",c);
514 if (zchout(ZMFILE, (char) (c & fmask)) < 0) {
516 debug(F101,"putfil zchout write error, setting czseen","",1);
522 int /* Output char to nowhere. */
526 putnowhere(c) register char c;
527 #endif /* CK_ANSIC */
533 int /* Output char to file. */
537 putfil(c) register char c;
538 #endif /* CK_ANSIC */
540 debug(F000,"putfil","",c);
541 if (zchout(ZOFILE, (char) (c & fmask)) < 0) {
542 czseen = 1; /* If write error... */
543 debug(F101,"putfil zchout write error, setting czseen","",1);
550 The following function is a wrapper for putfil(). The only reason for its
551 existence is to be passed as a function pointer to decode(), which treats
552 putfil() itself specially -- bypassing it and using an internal macro
553 instead to speed things up. Use zputfil() instead of putfil() in cases where
554 we do not want this to happen, e.g. when we need to send output to the file
555 with a mixture of zchout() and zsout()/zsoutl() calls (as is the case with
556 incoming short-form REMOTE command replies redirected to a file), which would
557 otherwise result in data written to the file out of order.
563 zputfil(c) register char c;
564 #endif /* CK_ANSIC */
571 /* D E C O D E -- Kermit packet decoding procedure */
574 Call with string to be decoded and an output function.
575 Returns 0 on success, -1 on failure (e.g. disk full).
577 This is the "inner loop" when receiving files, and must be coded as
578 efficiently as possible. Note some potential problems: if a packet
579 is badly formed, having a prefixed sequence ending prematurely, this
580 function, as coded, could read past the end of the packet. This has
581 never happened, thus the additional (time-consuming) tests have not
585 static CHAR *xdbuf; /* Global version of decode()'s buffer pointer */
586 /* for use by translation functions. */
588 /* Function for pushing a character onto decode()'s input stream. */
595 #endif /* CK_ANSIC */
597 xdbuf--; /* Back up the pointer. */
598 *xdbuf = c; /* Stuff the character. */
603 Trimmed-down packet decoder for binary-mode no-parity transfers.
604 decode() is the full version.
608 bdecode(CHAR *buf, int (*fn)(char))
610 bdecode(buf,fn) register CHAR *buf; register int (*fn)();
611 #endif /* CK_ANSIC */
613 register unsigned int a, a7; /* Various copies of current char */
614 int ccpflg; /* For Ctrl-unprefixing stats */
615 int t; /* Int version of character */
617 long z; /* For CRC calculation */
618 CHAR c; /* Current character */
620 if (!binary || parity || fn != putfil) /* JUST IN CASE */
621 return(decode(buf,fn,1));
622 debug(F100,"BDECODE","",0);
624 xdbuf = buf; /* Global copy of source pointer. */
626 len = rln; /* Number of bytes in data field */
628 a = *xdbuf++ & 0xff; /* Get next character */
630 rpt = 0; /* Initialize repeat count. */
631 if (a == rptq && rptflg) { /* Got a repeat prefix? */
632 rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
634 a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
637 ccpflg = 0; /* Control prefix flag. */
638 if (a == ctlq) { /* If control prefix, */
639 a = *xdbuf++ & 0xFF; /* get its operand */
641 a7 = a & 0x7F; /* and its low 7 bits. */
642 if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */
643 a = ctl(a); /* if in control range. */
645 ccpflg = 1; /* Note that we did this */
646 ccp++; /* Count for stats */
648 } else a7 = a & 0x7f; /* Not control quote */
649 if (a7 < 32 || a7 == 127) /* A bare control character? */
650 if (!ccpflg) ccu++; /* Count it */
652 for (; rpt > 0; rpt--) { /* Output the char RPT times */
658 #endif /* CALIBRATE */
660 if (xflg && !remfile) { /* Write to virtual screen */
668 t = zmchout(a & fmask); /* zmchout is a macro */
670 debug(F101,"bdecode write error - errno","",errno);
673 ffc++; /* Count the character */
674 if (docrc && !remfile) { /* Update file CRC */
675 c = a; /* Force conversion to unsigned char */
677 crc16 = (crc16 >> 8) ^
678 (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
683 #endif /* CK_CTRLZ */
687 #endif /* CKTUNING */
690 /* P N B Y T E -- Output next byte to file or other destination */
692 static CK_OFF_T offc = 0L;
696 pnbyte(CHAR c, int (*fn)(char))
698 pnbyte(c,fn) CHAR c; int (*fn)();
699 #endif /* CK_ANSIC */
706 if (xflg && !remfile) { /* Write to virtual screen */
716 if (fn == putfil) { /* Execute output function */
717 rc = zmchout(c); /* to-file macro (fast) */
719 rc = putchar(c); /* to-screen macro (fast) */
721 rc = (*fn)(c); /* function call (not as fast) */
727 Both xgnbyte() and xpnbyte() increment ffc (the file byte counter).
728 During file transfer, only one of these functions is called. However,
729 the TRANSLATE command is likely to call them both. offc, therefore,
730 contains the output byte count, necessary for handling the UCS-2 BOM.
731 NOTE: It might be safe to just test for W_SEND, FTP or not.
733 if ((what & (W_FTP|W_SEND)) != (W_FTP|W_SEND)) {
734 offc++; /* Count the byte */
735 ffc++; /* Count the byte */
738 if (docrc && !xflg && !remfile) { /* Update file CRC */
740 crc16 = (crc16 >> 8) ^
741 (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
748 X P N B Y T E -- Translate and put next byte to file.
750 Only for Unicode. Call with next untranslated byte from incoming
751 byte stream, which can be in any Transfer Character Set: UCS-2, UTF-8,
752 Latin-1, Latin-Hebrew, etc. Translates to the file character set and
753 writes bytes to the output file. Call with character to translate
754 as an int, plus the transfer character set (to translate from) and the
755 file character set (to translate to), or -1,0,0 to reset the UCS-2 byte
756 number (which should be done at the beginning of a file). If the transfer
757 (source) character-set is UCS-2, bytes MUST arrive in Big-Endian order.
760 0: Nothing to write (mid-sequence)
761 >0: Number of bytes written.
764 static int jstate = 0, jx = 0; /* For outputting JIS-7 */
765 static char jbuf[16] = { NUL, NUL };
770 xpnbyte(int a, int tcs, int fcs, int (*fn)(char))
772 xpnbyte(a,tcs,fcs,fn) int a, tcs, fcs; int (*fn)();
773 #endif /* CK_ANSIC */
776 extern int ucsbom; /* Byte order */
778 /* CHAR c; */ /* Unsigned char worker */
779 static union ck_short uc, eu, sj; /* UCS-2, EUC, and Shift-JIS workers */
780 USHORT ch; /* ditto... */
781 USHORT * us = NULL; /* ditto... */
782 int c7, rc, haveuc = 0; /* Return code and UCS-2 flag */
783 int utferror = 0; /* UTF-8 error */
784 static int bn = 0; /* UCS-2 byte number */
785 int swapping = 0; /* Swapping UCS bytes to output? */
786 /* swapping must be 0 or 1 */
787 if (a == -1 && (tcs | fcs) == 0) { /* Reset in case previous run */
788 bn = 0; /* left bn at 1... */
790 debug(F101,"xpnbyte RESET","",bn);
793 debug(F001,"xpnbyte a","",a);
798 byteorder = hardware byte order of this machine.
799 ucsorder = override by SET FILE UCS BYTE-ORDER command.
800 fileorder = byte order of UCS-2 input file detected from BOM.
801 swapping applies only when output charset is UCS-2.
803 if (ucsorder != 1 && ucsorder != 0) /* Also just in case... */
804 ucsorder = byteorder;
805 if ((byteorder && !ucsorder) || (!byteorder && fileorder))
806 swapping = 1; /* Swapping bytes to output */
809 debug(F101,"xpnbyte ucsorder","",ucsorder);
810 debug(F101,"xpnbyte swapping","",swapping);
813 if (tcs == TC_UTF8) { /* 'a' is from a UTF-8 stream */
815 if (fcs == TC_UTF8) /* Output is UTF-8 too */
816 return(pnbyte(ch,fn)); /* so just copy. */
817 rc = utf8_to_ucs2(ch,&us); /* Otherwise convert to UCS-2 */
818 if (rc == 0) { /* Done with this sequence */
819 uc.x_short = *us; /* We have a Unicode */
821 } else if (rc < 0) { /* Error */
822 debug(F101,"xpnbyte UTF-8 conversion error","",rc);
823 haveuc = 1; /* Replace by U+FFFD */
826 } else /* Sequence incomplete */
828 } else if (tcs == TC_UCS2) { /* 'a' is UCS-2 */
829 /* Here we have incoming UCS-2 in guaranteed Big Endian order */
830 /* so we must exchange bytes if local machine is Little Endian. */
831 switch (bn) { /* Which byte? */
832 case 0: /* High... */
833 uc.x_char[byteorder] = (unsigned)a & 0xff;
835 return(0); /* Wait for next */
837 uc.x_char[1-byteorder] = (unsigned)a & 0xff;
838 bn = 0; /* Done with sequence */
839 haveuc = 1; /* Have a Unicode */
844 #ifdef KANJI /* Whether UNICODE is defined or not */
845 if (tcs == TC_JEUC) { /* Incoming Japanese EUC */
847 static int kanji = 0; /* Flags set in case 0 for case 1 */
849 switch (bn) { /* Byte number */
852 if ((a & 0x80) == 0) {
853 sj.x_short = (unsigned)a & 0xff; /* Single byte */
855 } else { /* Double byte */
857 if (c7 > 0x20 && c7 < 0x7f) { /* Kanji */
858 eu.x_char[byteorder] = (CHAR) a; /* Store first byte */
859 bn++; /* Set up for second byte */
863 } else if (a == 0x8e) { /* SS2 -- Katakana prefix */
864 eu.x_char[byteorder] = (CHAR) a; /* Save it */
877 eu.x_char[1-byteorder] = (CHAR) a;
878 sj.x_short = eu_to_sj(eu.x_short);
881 sj.x_short = (CHAR) (a | 0x80);
883 } else { /* (shouldn't happen) */
887 /* Come here with one Shift-JIS character */
893 uc.x_short = sj_to_un(sj.x_short); /* Convert to Unicode */
901 uc.x_short = (unsigned)a & 0xff; /* Latin-1 or whatever... */
903 /* Come here with uc = the character to be translated. */
904 /* If (haveuc) it's UCS-2 in native order, otherwise it's a byte. */
906 debug(F101,"xpnbyte haveuc","",haveuc);
908 if (haveuc) { /* If we have a Unicode... */
909 debug(F001,"xpnbyte uc.x_short","[A]",uc.x_short);
910 debug(F101,"xpnbyte feol","",feol);
911 if (what & W_XFER) { /* If transferring a file */
912 if (feol && uc.x_short == CR) { /* handle eol conversion. */
914 } else if (feol && uc.x_short == LF) {
918 debug(F001,"xpnbyte uc.x_short","[B]",uc.x_short);
919 if (fcs == FC_UCS2) { /* And FCS is UCS-2 */
920 /* Write out the bytes in the appropriate byte order */
924 extern int k95stdout,wherex[],wherey[];
925 extern unsigned char colorcmd;
931 #endif /* IKSDONLY */
932 if (!offc && ucsbom) { /* Beginning of file? */
936 if (fn == NULL && !k95stdout && !inserver) {
939 /* Don't print the BOM to the display */
940 output.bytes[0] = (!ucsorder ? 0xff : 0xfe);
941 output.bytes[1] = (!ucsorder ? 0xfe : 0xff);
943 VscrnWrtUCS2StrAtt(VCMD,
953 #endif /* IKSDONLY */
955 if ((rc = pnbyte((ucsorder ? 0xff : 0xfe),fn)) < 0)
956 return(rc); /* BOM */
957 if ((rc = pnbyte((ucsorder ? 0xfe : 0xff),fn)) < 0)
965 if (fn == NULL && !k95stdout && !inserver) {
967 output.bytes[0] = (!ucsorder ? 0xfd : 0xff);
968 output.bytes[1] = (!ucsorder ? 0xff : 0xfd);
970 VscrnWrtUCS2StrAtt(VCMD,
979 #endif /* IKSDONLY */
981 if ((rc = pnbyte((ucsorder ? 0xfd : 0xff),fn)) < 0)
983 if ((rc = pnbyte((ucsorder ? 0xff : 0xfd),fn)) < 0)
990 if (fn == NULL && !k95stdout && !inserver) {
992 output.bytes[0] = uc.x_char[swapping];
993 output.bytes[1] = uc.x_char[1-swapping];
995 VscrnWrtUCS2StrAtt(VCMD,
1004 #endif /* IKSDONLY */
1006 if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
1008 if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
1013 } else if (fcs == FC_UTF8) { /* Convert to UTF-8 */
1017 if ((rc = pnbyte((ucsorder ? 0xbd : 0xff),fn)) < 0)
1019 if ((rc = pnbyte((ucsorder ? 0xff : 0xbd),fn)) < 0)
1022 if ((count = ucs2_to_utf8(uc.x_short,&buf)) < 1)
1024 debug(F011,"xpnbyte buf",buf,count);
1025 for (i = 0; i < count; i++)
1026 if ((rc = pnbyte(buf[i],fn)) < 0)
1031 } else { /* Translate UCS-2 to byte */
1032 if (uc.x_short == 0x2028 || uc.x_short == 0x2029) {
1036 return(pnbyte((CHAR)feol,fn));
1037 if ((rc = pnbyte((CHAR)CR,fn)) < 0)
1039 if ((rc = pnbyte((CHAR)LF,fn)) < 0)
1042 return(utferror ? 3 : 2);
1043 } else if (xuf) { /* UCS-to-FCS function */
1047 if ((rc = (*xuf)(uc.x_short)) < 0) /* These can fail... */
1050 ch = (unsigned)((unsigned)rc & 0xffff);
1059 /* Also see the non-Unicode Kanji section further down in this function. */
1061 } else if (fcsinfo[fcs].alphabet == AL_JAPAN) {
1063 /* Translate UCS-2 to Japanese set */
1064 debug(F001,"xpnbyte uc","",uc.x_short);
1065 sj.x_short = un_to_sj(uc.x_short); /* First to Shift-JIS */
1066 debug(F001,"xpnbyte sj","",sj.x_short);
1068 switch (fcs) { /* File character set */
1069 case FC_SHJIS: /* Shift-JIS -- just output it */
1070 if (sj.x_char[byteorder]) /* But not high byte if zero */
1071 if ((rc = pnbyte((CHAR)sj.x_char[byteorder],fn)) < 0)
1073 if ((rc = pnbyte((CHAR)sj.x_char[1-byteorder],fn)) < 0)
1076 case FC_JEUC: /* EUC-JP */
1077 eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
1078 debug(F001,"xpnbyte eu","",eu.x_short);
1079 if (eu.x_short == 0xffff) { /* Bad */
1080 if ((rc = pnbyte(UNK,fn)) < 0)
1084 int count = 0; /* Write high byte if not zero */
1085 if (eu.x_char[byteorder]) {
1086 if ((rc=pnbyte((CHAR)eu.x_char[byteorder],fn)) < 0)
1090 /* Always write low byte */
1091 if ((rc = pnbyte((CHAR)eu.x_char[1-byteorder],fn)) < 0)
1098 case FC_JIS7: /* JIS-7 */
1099 case FC_JDEC: /* DEC Kanji */
1100 eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
1101 if (eu.x_short == 0xffff) { /* Bad */
1102 debug(F001,"xpnbyte bad eu","",eu.x_short);
1103 if ((rc = pnbyte(UNK,fn)) < 0)
1108 /* Use another name - 'a' hides parameter */
1109 /* It's OK as is but causes compiler warnings */
1110 char a = eu.x_char[1-byteorder]; /* Low byte */
1111 debug(F001,"xpnbyte eu","",eu.x_short);
1112 if (eu.x_char[byteorder] == 0) { /* Roman */
1114 case 1: /* Current state is Katakana */
1115 jbuf[0] = 0x0f; /* SI */
1119 case 2: /* Current state is Kanji */
1120 jbuf[0] = 0x1b; /* ESC */
1121 jbuf[1] = 0x28; /* ( */
1122 jbuf[2] = 0x4a; /* J */
1126 default: /* Current state is Roman */
1131 jstate = 0; /* New state is Roman */
1132 } else if (eu.x_char[byteorder] == 0x8e) { /* Kana */
1135 case 2: /* from Kanji */
1136 jbuf[jx++] = 0x1b; /* ESC */
1137 jbuf[jx++] = 0x28; /* ( */
1138 jbuf[jx++] = 0x4a; /* J */
1139 case 0: /* from Roman */
1140 jbuf[jx++] = 0x0e; /* SO */
1141 default: /* State is already Kana*/
1142 jbuf[jx++] = (a & 0x7f); /* and the char */
1145 jstate = 1; /* New state is Katakana */
1146 } else { /* Kanji */
1149 case 1: /* Current state is Katakana */
1150 jbuf[jx++] = 0x0f; /* SI */
1151 case 0: /* Current state is Roman */
1152 jbuf[jx++] = 0x1b; /* ESC */
1153 jbuf[jx++] = 0x24; /* $ */
1154 jbuf[jx++] = 0x42; /* B */
1155 default: /* Current state is already Kanji */
1156 jbuf[jx++] = eu.x_char[byteorder] & 0x7f;
1157 jbuf[jx++] = eu.x_char[1-byteorder] & 0x7f;
1160 jstate = 2; /* Set state to Kanji */
1162 for (i = 0; i < jx; i++) /* Output the result */
1163 if ((rc = pnbyte(jbuf[i],fn)) < 0)
1165 return(jx); /* Return its length */
1169 } else { /* No translation function */
1172 if ((rc = pnbyte((ucsorder ? 0xfd : 0xff),fn)) < 0)
1174 if ((rc = pnbyte((ucsorder ? 0xff : 0xfd),fn)) < 0)
1178 if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
1180 if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
1186 } else { /* Byte to Unicode */
1187 if (xtu) { /* TCS-to-UCS function */
1188 if (((tcsinfo[tcs].size > 128) && (uc.x_short & 0x80)) ||
1189 tcsinfo[tcs].size <= 128)
1190 uc.x_short = (*xtu)(uc.x_short);
1192 if (fcs == FC_UCS2) { /* And FCS is UCS-2 */
1193 /* Write out the bytes in the appropriate byte order */
1194 if (!offc && ucsbom) { /* Beginning of file? */
1195 if ((rc = pnbyte((ucsorder ? 0xff : 0xfe),fn)) < 0) /* BOM */
1197 if ((rc = pnbyte((ucsorder ? 0xfe : 0xff),fn)) < 0)
1200 if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
1202 if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
1205 } else if (fcs == FC_UTF8) { /* Convert to UTF-8 */
1208 if ((count = ucs2_to_utf8(uc.x_short,&buf)) < 1)
1210 for (i = 0; i < count; i++)
1211 if ((rc = pnbyte(buf[i],fn)) < 0)
1215 debug(F100,"xpnbyte impossible combination","",0);
1222 This almost, but not quite, duplicates the Kanji section above.
1223 There is no doubt a way to combine the sections more elegantly,
1224 but probably only at the expense of additional execution overhead.
1225 As matters stand, be careful to reflect any changes in this section
1226 to the other Kanji section above.
1228 if (tcs == TC_JEUC) { /* Incoming Japanese EUC */
1230 switch (fcs) { /* File character set */
1231 case FC_SHJIS: /* Shift-JIS -- just output it */
1232 if (sj.x_char[byteorder]) /* But not high byte if zero */
1233 if ((rc = pnbyte((CHAR)sj.x_char[byteorder],fn)) < 0)
1236 if ((rc = pnbyte((CHAR)sj.x_char[1-byteorder],fn)) < 0)
1240 case FC_JEUC: /* EUC-JP */
1241 eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
1242 debug(F001,"xpnbyte FC_JEUC eu","",eu.x_short);
1243 if (eu.x_short == 0xffff) { /* Bad */
1244 if ((rc = pnbyte(UNK,fn)) < 0)
1248 int count = 0; /* Write high byte if not zero */
1249 if (eu.x_char[byteorder]) {
1250 if ((rc = pnbyte((CHAR)eu.x_char[byteorder],fn)) < 0)
1254 /* Always write low byte */
1255 if ((rc = pnbyte((CHAR)eu.x_char[1-byteorder],fn)) < 0)
1262 case FC_JIS7: /* JIS-7 */
1263 case FC_JDEC: /* DEC Kanji */
1264 eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
1265 if (eu.x_short == 0xffff) { /* Bad */
1266 debug(F001,"xpnbyte FC_JIS7 bad eu","",eu.x_short);
1267 if ((rc = pnbyte(UNK,fn)) < 0)
1272 char a = eu.x_char[1-byteorder]; /* Low byte */
1273 debug(F001,"xpnbyte FC_JIS7 eu","",eu.x_short);
1274 if (eu.x_char[byteorder] == 0) { /* Roman */
1276 case 1: /* Current state is Katakana */
1277 jbuf[0] = 0x0f; /* SI */
1281 case 2: /* Current state is Kanji */
1282 jbuf[0] = 0x1b; /* ESC */
1283 jbuf[1] = 0x28; /* ( */
1284 jbuf[2] = 0x4a; /* J */
1288 default: /* Current state is Roman */
1293 jstate = 0; /* New state is Roman */
1294 } else if (eu.x_char[byteorder] == 0x8e) { /* Kana */
1297 case 2: /* from Kanji */
1298 jbuf[jx++] = 0x1b; /* ESC */
1299 jbuf[jx++] = 0x28; /* ( */
1300 jbuf[jx++] = 0x4a; /* J */
1301 case 0: /* from Roman */
1302 jbuf[jx++] = 0x0e; /* SO */
1303 default: /* State is already Kana*/
1304 jbuf[jx++] = (a & 0x7f); /* and the char */
1307 jstate = 1; /* New state is Katakana */
1308 } else { /* Kanji */
1311 case 1: /* Current state is Katakana */
1312 jbuf[jx++] = 0x0f; /* SI */
1313 case 0: /* Current state is Roman */
1314 jbuf[jx++] = 0x1b; /* ESC */
1315 jbuf[jx++] = 0x24; /* $ */
1316 jbuf[jx++] = 0x42; /* B */
1317 default: /* Current state is already Kanji */
1318 jbuf[jx++] = eu.x_char[byteorder] & 0x7f;
1319 jbuf[jx++] = eu.x_char[1-byteorder] & 0x7f;
1322 jstate = 2; /* Set state to Kanji */
1324 for (i = 0; i < jx; i++) /* Output the result */
1325 if ((rc = pnbyte(jbuf[i],fn)) < 0)
1327 return(jx); /* Return its length */
1330 if (sj.x_short < 0x80)
1337 #endif /* UNICODE */
1338 debug(F100,"xpnbyte BAD FALLTHRU","",0);
1344 /* D E C O D E -- Kermit Data-packet decoder */
1348 decode(CHAR *buf, int (*fn)(char), int xlate)
1350 decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate;
1351 #endif /* CK_ANSIC */
1353 register unsigned int a, a7, a8, b8; /* Various copies of current char */
1354 int t; /* Int version of character */
1355 int ssflg; /* Character was single-shifted */
1356 int ccpflg; /* For Ctrl-unprefixing stats */
1361 Catch the case in which we are asked to decode into a file that is not open,
1362 for example, if the user interrupted the transfer, but the other Kermit
1365 if ((cxseen || czseen || discard) && (fn == putfil))
1370 if (binary && !parity)
1371 return(bdecode(buf,fn));
1372 #endif /* CKTUNING */
1373 #endif /* COMMENT */
1374 debug(F100,"DECODE","",0);
1376 xdbuf = buf; /* Make global copy of pointer. */
1377 rpt = 0; /* Initialize repeat count. */
1379 len = rln; /* Number of bytes in data field */
1380 while (len > 0) { /* Loop for each byte */
1381 a = *xdbuf++ & 0xff; /* Get next character */
1383 if (a == rptq && rptflg) { /* Got a repeat prefix? */
1384 rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
1386 a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
1389 b8 = lsstate ? 0200 : 0; /* 8th-bit value from SHIFT-STATE */
1390 if (ebqflg && a == ebq) { /* Have 8th-bit prefix? */
1391 b8 ^= 0200; /* Yes, invert the 8th bit's value, */
1392 ssflg = 1; /* remember we did this, */
1393 a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
1397 if (a == ctlq) { /* If control prefix, */
1398 a = *xdbuf++ & 0xFF; /* get its operand */
1400 a7 = a & 0x7F; /* and its low 7 bits. */
1401 if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */
1402 a = ctl(a); /* if in control range. */
1404 ccpflg = 1; /* Note that we did this */
1405 ccp++; /* Count for stats */
1407 } else a7 = a & 0x7f; /* Not control quote */
1408 if (a7 < 32 || a7 == 127) { /* Control character? */
1409 if (!ccpflg) ccu++; /* A bare one, count it */
1410 if (lscapu) { /* If doing locking shifts... */
1411 if (lsstate) /* If SHIFTED */
1412 a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */
1413 else /* otherwise */
1414 a8 = a | b8; /* OR in 8th bit */
1415 /* If we're not in a quoted sequence */
1416 if (!lsquote && (!lsstate || !ssflg)) {
1417 if (a8 == DLE) { /* Check for DLE quote */
1418 lsquote = 1; /* prefixed by single shift! */
1420 } else if (a8 == SO) { /* Check for Shift-Out */
1421 lsstate = 1; /* SHIFT-STATE = SHIFTED */
1423 } else if (a8 == SI) { /* or Shift-In */
1424 lsstate = 0; /* SHIFT-STATE = UNSHIFTED */
1430 a |= b8; /* OR in the 8th bit */
1431 if (rpt == 0) rpt = 1; /* If no repeats, then one */
1433 if (!binary) { /* If in text mode, */
1434 if (tcharset != TC_UCS2) {
1435 if (feol && a == CR) /* Convert CRLF to newline char */
1437 if (feol && a == LF)
1440 if (xlatype == XLA_BYTE) /* Byte-for-byte - do it now */
1441 if (xlate && rx) a = (*rx)((CHAR) a);
1443 #endif /* NOCSETS */
1444 /* (PWP) Decoding speedup via buffered output and a macro... */
1446 for (; rpt > 0; rpt--) { /* Output the char RPT times */
1452 #endif /* CALIBRATE */
1454 /* Note: The Unicode and Kanji sections can probably be combined now; */
1455 /* the Unicode method (xpnbyte()) covers Kanji too. */
1458 if (!binary && xlatype == XLA_UNICODE)
1459 t = xpnbyte((unsigned)((unsigned)a & 0xff),
1465 #endif /* UNICODE */
1467 if (!binary && tcharset == TC_JEUC &&
1468 fcharset != FC_JEUC) { /* Translating from J-EUC */
1470 if (xkanji(a,fn) < 0) /* to something else? */
1477 if (xflg && !remfile) { /* Write to virtual screen */
1485 t = zmchout(a & fmask); /* zmchout is a macro */
1488 debug(F101,"decode write errno","",errno);
1492 if (xlatype != XLA_UNICODE || binary) {
1493 ffc++; /* Count the character */
1494 if (docrc && !xflg && !remfile) { /* Update file CRC */
1495 c = a; /* Force conversion to unsigned char */
1496 z = crc16 ^ (long)c;
1497 crc16 = (crc16 >> 8) ^
1498 (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
1501 #endif /* UNICODE */
1503 } else { /* Output to something else. */
1504 a &= fmask; /* Apply file mask */
1505 for (; rpt > 0; rpt--) { /* Output the char RPT times */
1511 #endif /* CALIBRATE */
1512 if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */
1517 #endif /* CK_CTRLZ */
1522 /* G E T P K T -- Fill a packet data field */
1525 Gets characters from the current source -- file or memory string.
1526 Encodes the data into the packet, filling the packet optimally.
1527 Set first = 1 when calling for the first time on a given input stream
1531 bufmax -- current send-packet size
1532 xlate -- flag: 0 to skip character-set translation, 1 to translate
1534 Uses global variables:
1535 t -- current character.
1536 first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
1537 next -- next character (not used any more).
1538 data -- pointer to the packet data buffer.
1539 size -- number of characters in the data buffer.
1540 memstr - flag that input is coming from a memory string instead of a file.
1541 memptr - pointer to string in memory.
1542 (*sx)() character set translation function
1545 The size as value of the function, and also sets global "size",
1546 and fills (and null-terminates) the global data array.
1549 -1 on fatal (internal) error.
1550 -3 on timeout (e.g. when reading data from a pipe).
1552 Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
1553 Incorporates old getchx() and encode() inline to reduce function calls,
1554 uses buffered input for much-improved efficiency, and clears up some
1555 confusion with line termination (CRLF vs LF vs CR).
1557 Rewritten again by Frank da Cruz to incorporate locking shift mechanism,
1558 May 1991. And again in 1998 for efficiency, etc, with a separate
1559 bgetpkt() split out for binary-mode no-parity transfers.
1563 Note: Separate Kanji support dates from circa 1991 and now (1999) can most
1564 likely be combined with the the Unicode support: the xgnbyte()/xpnbyte()
1565 mechanism works for both Unicode and Kanji.
1572 #endif /* CK_ANSIC */
1575 return((*funcptr)());
1584 #endif /* CK_ANSIC */
1587 if ((x = *memptr++)) return(x);
1593 Lookahead function to decide whether locking shift is worth it. Looks at
1594 the next four input characters to see if all of their 8th bits match the
1595 argument. Call with 0 or 0200. Returns 1 on match, 0 if they don't match.
1596 If we don't happen to have at least 4 more characters waiting in the input
1597 buffer, returns 1. Note that zinptr points two characters ahead of the
1598 current character because of repeat-count lookahead.
1601 lslook(b) unsigned int b; { /* Locking Shift Lookahead */
1603 if (zincnt < 3) /* If not enough chars in buffer, */
1604 return(1); /* force shift-state switch. */
1605 b &= 0200; /* Force argument to proper form. */
1606 for (i = -1; i < 3; i++) /* Look at next 5 characters to */
1607 if (((*(zinptr+i)) & 0200) != b) /* see if all their 8th bits match. */
1608 return(0); /* They don't. */
1609 return(1); /* They do. */
1612 /* Routine to compute maximum data length for packet to be filled */
1615 maxdata() { /* Get maximum data length */
1617 debug(F101,"maxdata spsiz 1","",spsiz);
1618 if (spsiz < 0) /* How could this happen? */
1620 debug(F101,"maxdata spsiz 2","",spsiz);
1621 n = spsiz - 5; /* Space for Data and Checksum */
1622 if (n > 92 && n < 96) n = 92; /* "Short" Long packets don't pay */
1623 if (n > 92 && lpcapu == 0) /* If long packets needed, */
1624 n = 92; /* make sure they've been negotiated */
1625 len = n - bctl; /* Space for data */
1626 if (n > 92) len -= 3; /* Long packet needs header chksum */
1627 debug(F101,"maxdata len 1","",len);
1628 if (len < 0) len = 10;
1629 debug(F101,"maxdata len 2","",len);
1633 static CHAR leftover[9] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0' };
1634 static int nleft = 0;
1638 When CKTUNING is defined we use this special trimmed-down version of getpkt
1639 to speed up binary-mode no-parity transfers. When CKTUNING is not defined,
1640 or for text-mode or parity transfers, we use the regular getpkt() function.
1641 Call just like getpkt() but test first for transfer mode and parity. NOTE:
1642 This routine is only to be called when sending a real file -- not for
1643 filenames, server responses, etc, because it only reads from the input file.
1644 See getpkt() for more detailed commentary.
1647 bgetpkt(bufmax) int bufmax; {
1648 register CHAR rt = t, rnext;
1649 register CHAR *dp, *odp, *p1, *p2;
1650 register int x = 0, a7;
1652 CHAR xxrc, xxcq; /* Pieces of prefixed sequence */
1654 long z; /* A long worker (for CRC) */
1656 if (!binary || parity || memstr) /* JUST IN CASE caller didn't test */
1657 return(getpkt(bufmax,!binary));
1660 debug(F100,"SERIOUS ERROR: bgetpkt data == NULL","",0);
1663 dp = data; /* Point to packet data buffer */
1664 size = 0; /* And initialize its size */
1665 bufmax = maxdata(); /* Get maximum data length */
1669 debug(F101,"bgetpkt bufmax","",bufmax);
1672 if (first == 1) { /* If first character of this file.. */
1673 ffc = (CK_OFF_T)0; /* reset file character counter */
1675 /* Moved to below */
1676 first = 0; /* Next character won't be first */
1677 #endif /* COMMENT */
1678 *leftover = '\0'; /* Discard any interrupted leftovers */
1681 /* Get first character of file into rt, watching out for null file */
1688 rt = cal_a[rand() & 0xff];
1689 #endif /* NORANDOM */
1692 #endif /* CALIBRATE */
1694 if ((x = zminchar()) < 0) { /* EOF or error */
1695 if (x == -3) { /* Timeout. */
1697 debug(F101,"bgetpkt timeout size","",size);
1698 return((size == 0) ? x : size);
1702 if (x == -2) { /* Error */
1703 debug(F100,"bgetpkt: input error","",0);
1704 cxseen = 1; /* Interrupt the file transfer */
1706 debug(F100,"bgetpkt empty file","",0);
1710 first = 0; /* Next char will not be the first */
1711 ffc++; /* Count a file character */
1712 rt = (CHAR) x; /* Convert int to char */
1713 if (docrc && (what & W_SEND)) { /* Accumulate file crc */
1714 z = crc16 ^ (long)rt;
1715 crc16 = (crc16 >> 8) ^
1716 (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
1718 rt &= fmask; /* Apply SET FILE BYTESIZE mask */
1720 } else if (first == -1 && nleft == 0) { /* EOF from last time */
1725 Here we handle characters that were encoded for the last packet but
1726 did not fit, and so were saved in the "leftover" array.
1729 for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */
1731 *leftover = '\0'; /* Delete leftovers */
1734 if (first == -1) /* Handle EOF */
1735 return(size = (dp - data));
1737 /* Now fill up the rest of the packet. */
1739 rpt = 0; /* Initialize character repeat count */
1741 while (first > -1) { /* Until EOF... */
1743 if (calibrate) { /* We generate our own "file" */
1744 if (ffc >= calibrate) { /* EOF */
1747 } else { /* Generate next character */
1748 if (cal_j > CAL_M * ffc)
1749 cal_j = cal_a[ffc & 0xff];
1750 x = (unsigned)cal_a[(cal_j & 0xff)];
1751 if (x == rt) x ^= 2;
1754 cal_j += (unsigned int)(ffc + CAL_O);
1756 #endif /* CALIBRATE */
1757 if ((x = zminchar()) < 0) { /* Check for EOF */
1758 if (x == -3) { /* Timeout. */
1761 debug(F101,"bgetpkt timeout size","",size);
1762 return((size == 0) ? x : size);
1764 first = -1; /* Flag eof for next time. */
1765 if (x == -2) cxseen = 1; /* If error, cancel this file. */
1767 ffc++; /* Count the character */
1768 if (docrc && (what & W_SEND)) { /* Accumulate file crc */
1769 z = crc16 ^ (long)((CHAR)x & 0xff);
1770 crc16 = (crc16 >> 8) ^
1771 (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
1774 rnext = (CHAR) (x & fmask); /* Apply file mask */
1776 At this point, the character we just read is in rnext,
1777 and the character we are about to encode into the packet is in rt.
1779 odp = dp; /* Remember where we started. */
1780 xxrc = xxcq = NUL; /* Clear these. */
1782 Now encode the character according to the options that are in effect:
1783 ctlp[]: whether this control character needs prefixing.
1784 rptflg: repeat counts enabled.
1785 Other options don't apply in this routine.
1787 if (rptflg && (rt == rnext) && (first == 0)) { /* Got a run... */
1788 if (++rpt < 94) { /* Below max, just count */
1789 continue; /* go back and get another */
1790 } else if (rpt == 94) { /* Reached max, must dump */
1791 xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
1792 rptn += rpt; /* Accumulate it for statistics */
1793 rpt = 0; /* And reset it */
1795 } else if (rpt > 0) { /* End of run */
1796 xxrc = (CHAR)tochar(++rpt); /* The count */
1797 rptn += rpt; /* For stats */
1798 rpt = 0; /* Reset repeat count */
1800 a7 = rt & 0177; /* Get low 7 bits of character */
1803 ctlp[(unsigned)(rt & 0xff)] /* Lop off any "sign" extension */
1805 (a7 < SP) || (a7 == DEL)
1806 #endif /* CK_SPEED */
1807 ) { /* Do control prefixing if necessary */
1808 xxcq = myctlq; /* The prefix */
1809 ccp++; /* Count it */
1810 rt = (CHAR) ctl(rt); /* Uncontrollify the character */
1813 else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
1815 #endif /* CK_SPEED */
1817 if (a7 == myctlq) /* Always prefix the control prefix */
1820 if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */
1821 xxcq = myctlq; /* prefix it if doing repeat counts */
1823 /* Now construct the prefixed sequence */
1825 if (xxrc) { /* Repeat count */
1827 if (xxrc == (CHAR) '"' && !xxcq) { /* 2 in a row & not prefixed */
1828 *dp++ = rt; /* So just do this */
1829 } else { /* More than two or prefixed */
1830 *dp++ = (CHAR) rptq; *dp++ = xxrc; /* Emit repeat sequence */
1832 #else /* CHECK THIS */
1833 if (xxrc == (CHAR) '"' && !xxcq) { /* 2 in a row & not prefixed */
1835 *dp++ = rt; /* So just do this */
1836 } else if (*(dp-1) == rt) {
1837 *dp++ = (CHAR) rptq;
1838 *dp++ = xxrc; /* Emit repeat sequence */
1840 *dp++ = rt; /* So just do this */
1842 } else { /* More than two or prefixed */
1843 *dp++ = (CHAR) rptq;
1844 *dp++ = xxrc; /* Emit repeat sequence */
1846 #endif /* COMMENT */
1848 if (xxcq) { *dp++ = myctlq; } /* Control prefix */
1849 *dp++ = rt; /* Finally, the character itself */
1850 rt = rnext; /* Next character is now current. */
1852 /* Done encoding the character. Now take care of packet buffer overflow. */
1854 size = dp - data; /* How many bytes we put in buffer. */
1855 if (size >= bufmax) { /* If too big, save some for next. */
1856 *dp = '\0'; /* Mark the end. */
1857 if (size > bufmax) { /* if packet is overfull */
1858 /* Copy the part that doesn't fit into the leftover buffer, */
1859 /* taking care not to split a prefixed sequence. */
1864 for (i = 0; i < nleft; i++)
1866 size = odp - data; /* Return truncated packet. */
1867 *odp = '\0'; /* Mark the new end */
1869 t = rt; /* Save for next time */
1872 } /* Otherwise, keep filling. */
1873 size = dp - data; /* End of file */
1874 *dp = '\0'; /* Mark the end of the data. */
1875 return(size); /* Return partially filled last packet. */
1877 #endif /* CKTUNING */
1880 dofilcrc(c) int c; { /* Accumulate file crc */
1882 z = crc16 ^ (long)c;
1883 crc16 = (crc16 >> 8) ^
1884 (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
1887 /* For SENDing from an array... */
1890 agnbyte() { /* Get next byte from array */
1893 static int save = 0; /* For CRLF */
1894 static char ** ap = NULL; /* Array pointer */
1895 static char * p = NULL; /* Character pointer */
1896 static int i = 0, n = 0; /* Array index and limit */
1897 extern int a_dim[]; /* Array dimension */
1899 if (!ap) { /* First time thru */
1900 ap = sndarray; /* Set up array pointers */
1901 if (!ap || (i = sndxlo) > a_dim[sndxin]) {
1906 p = ap[i]; /* Point to first element in range */
1907 n = sndxhi; /* Index of last element in range */
1908 if (sndxhi > a_dim[sndxin]) /* Adjust if necessary */
1911 if (save) { /* If anything saved */
1912 c = save; /* unsave it */
1913 save = 0; /* and return it */
1916 if (i > n) { /* No more elements */
1921 if (!p) /* Source pointer is NULL */
1922 c = NUL; /* this means an empty line */
1923 else /* Source pointer not NULL */
1924 c = *p++; /* Next char */
1925 if (!c) { /* Char is empty? */
1926 if (!binary) { /* Text: end of line. */
1927 if (feol) { /* Supply NL */
1929 } else { /* or CRLF */
1936 while (i++ < n) { /* Binary - get next element */
1938 if (!p) /* Empty line? */
1939 continue; /* Ignore it and get another */
1940 c = *p++; /* Get next char */
1941 if (!c) /* Emtpy char? */
1942 continue; /* Ignore it and get another */
1943 return(c & 0xff); /* Not empty - return it */
1947 return(-1); /* Done */
1949 return(c & 0xff); /* Char is not empty */
1958 static CHAR xlabuf[32] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1959 static int xlacount = 0;
1960 static int xlaptr = 0;
1961 /* static USHORT lastucs2 = 0; */
1964 X G N B Y T E -- Get next translated byte from the input file.
1966 Returns the next byte that is to be put into the packet, already translated.
1967 This isolates getpkt() from having to know anything about translation,
1968 single- vs multibyte character sets, one-to-many vs many-to-one, etc, but it
1969 has rather high overhead, so don't call it unless you know translation is
1970 needed to or from Unicode, Japanese, or other multibyte character set.
1973 fcs: File character set (source, file we are reading from)
1974 tcs: Target character set (use an FC_xxx code, not a TC_xxx code)
1976 >= 0: A translated byte suitable for writing.
1977 < 0: Fatal error (such as EOF on input source).
1978 As of Sat Sep 7 18:37:41 2002:
1979 When the output character-set is UCS-2, bytes are ALWAYS returned in
1980 big-endian order (previously they could also be returned in LE order
1981 under certain conditions, which was just way too confusing).
1985 xgnbyte(int tcs, int fcs, int (*fn)(void))
1986 #else /* CK_ANSIC */
1987 xgnbyte(tcs,fcs,fn) int tcs, fcs, (*fn)();
1988 #endif /* CK_ANSIC */
1990 _PROTOTYP( int (*xx), (USHORT) ) = NULL;
1991 int haveuc = 0; /* Flag for have Unicode character */
1993 int havesj = 0; /* Have Shift-JIS character */
1994 int haveeu = 0; /* Have EUC-JP character */
1996 int rc = -1, x = 0, flag = 0;
1999 unsigned int xc, thischar;
2000 static int swapping = 0;
2005 #endif /* UNICODE */
2007 union ck_short sj, eu; /* Shift-JIS character */
2015 if (deblog && !ffc) {
2016 debug(F101,"xgnbyte initial swap","",swapping);
2020 if (xlacount-- > 0) { /* We already have some */
2021 x = xlabuf[xlaptr++];
2022 debug(F001,"xgnbyte from buf","",x);
2025 if (xlatype != XLA_NONE) { /* Not not translating... */
2028 if (fcs == FC_UCS2) { /* UCS-2: Read two bytes */
2029 if (!ffc) /* Beginning of file? */
2030 swapping = 0; /* Reset byte-swapping flag */
2033 x = fn ? (*fn)() : zminchar(); /* Get first byte */
2034 debug(F001,"zminchar swapping","",swapping);
2035 debug(F001,"zminchar C0","",x);
2036 flag = 1; /* Remember we called zminchar() */
2037 if (x > -1) { /* Didn't fail */
2038 ffc++; /* Count a file byte */
2039 uc.x_char[swapping] = x & 0xff;
2041 if (docrc && (what & W_SEND))
2044 x = fn ? (*fn)() : zminchar(); /* Get second byte */
2045 if (x > -1) { /* If didn't fail */
2046 debug(F001,"zminchar C1","",x);
2047 ffc++; /* count another file byte */
2048 uc.x_char[1-swapping] = x & 0xff;
2049 haveuc = 1; /* And remember we have Unicode */
2051 if (docrc && (what & W_SEND))
2054 if (ffc == (CK_OFF_T)2) { /* Second char of file */
2055 debug(F001,"xgnbyte 1st UCS2","",uc.x_short);
2056 debug(F111,"xgnbyte fileorder","A",fileorder);
2057 if (fileorder < 0) /* Byte order of this file */
2058 fileorder = ucsorder; /* Default is ucsorder */
2061 debug(F111,"xgnbyte fileorder","B",fileorder);
2062 if (uc.x_short == (USHORT)0xfeff) {
2065 "xgnbyte UCS2 goodbom swap","",swapping);
2066 fileorder = byteorder; /* Note: NOT 0 */
2068 } else if (uc.x_short == (USHORT)0xfffe) {
2071 "xgnbyte UCS2 badbom swap","",swapping);
2072 fileorder = (1 - byteorder); /* Note: NOT 1 */
2074 } else if ((byteorder && !fileorder) || /* No BOM */
2075 (!byteorder && fileorder > 0)) {
2076 /* fileorder might have been set by scanfile() */
2079 uc.x_char[0] = uc.x_char[1];
2082 debug(F111,"xgnbyte UCS2 noBOM swap","A",swapping);
2085 debug(F111,"xgnbyte UCS2 noBOM swap","B",swapping);
2087 debug(F111,"xgnbyte fileorder","C",fileorder);
2093 debug(F001,"xgnbyte UCS2","",uc.x_short);
2095 } else if (fcs == FC_UTF8) { /* File is UTF-8 */
2096 CHAR ch = 0; /* Data types needed for API... */
2099 flag = 1; /* We (will) have called zminchar() */
2100 /* Read source bytes */
2101 while ((x = fn ? (*fn)() : zminchar()) > -1) {
2102 ffc++; /* Got a byte - count it */
2104 if (docrc && (what & W_SEND))
2108 rc = utf8_to_ucs2(ch,&us); /* Convert to UCS-2 */
2109 if (rc == 0) { /* Done */
2113 } else if (rc < 0) { /* Error */
2115 debug(F101,"xgnbyte UTF-8 input error","",rc);
2123 debug(F001,"xgnbyte UTF8->UCS2","",uc.x_short);
2125 #endif /* UNICODE */
2130 #endif /* UNICODE */
2131 if (fcsinfo[fcs].alphabet == AL_JAPAN) { /* Japanese source file */
2133 if (fcs == FC_JIS7) { /* If file charset is JIS-7 */
2134 if (!ffc) /* If first byte of file */
2135 j7init(); /* Initialize JIS-7 parser */
2136 x = getj7(); /* Get a JIS-7 byte */
2137 } else /* Otherwise */
2138 x = fn ? (*fn)() : zminchar(); /* Just get byte */
2139 if (x < 0) { /* Propogate EOF or error */
2140 debug(F100,"XGNBYTE EOF","",0);
2143 debug(F001,"XGNBYTE x","",x);
2146 if (docrc && (what & W_SEND)) dofilcrc(x); /* Do CRC */
2148 switch (fcs) { /* What next depends on charset */
2149 case FC_SHJIS: /* Shift-JIS */
2150 if ((x <= 0x80) || /* Any 7-bit char... */
2151 (x >= 0xa0 && x <= 0xdf)) { /* or halfwidth Katakana */
2152 sj.x_short = (USHORT) x; /* we read one byte. */
2153 } else { /* Anything else */
2154 if ((y = fn ? (*fn)() : zminchar()) < 0) /* get another */
2157 if (docrc && (what & W_SEND)) dofilcrc(y);
2160 sj.x_char[byteorder] = (CHAR) x;
2161 sj.x_char[1-byteorder] = (CHAR) y;
2165 case FC_JIS7: /* JIS-7 */
2166 case FC_JDEC: /* DEC Kanji */
2167 case FC_JEUC: /* EUC-JP */
2168 if ((x & 0x80) == 0) { /* Convert to Shift-JIS */
2169 sj.x_short = (USHORT) x; /* C0 or G0: one byte */
2170 eu.x_short = (USHORT) x;
2174 if (c7 > 0x20 && c7 < 0x7f) { /* Kanji: two bytes */
2175 if ((y = (fcs == FC_JEUC) ?
2176 (fn ? (*fn)() : zminchar()) :
2182 if (docrc && (what & W_SEND)) dofilcrc(y);
2184 eu.x_char[byteorder] = (CHAR) x;
2185 eu.x_char[1-byteorder] = (CHAR) y;
2186 sj.x_short = eu_to_sj(eu.x_short);
2188 } else if (x == 0x8e) { /* SS2 Katakana prefix: 2 bytes */
2189 if ((y = (fcs == FC_JIS7) ?
2191 (fn ? (*fn)() : zminchar())
2196 if (docrc && (what & W_SEND)) dofilcrc(y);
2198 sj.x_short = y | 0x80;
2199 debug(F001,"XGNBYTE KANA SJ","",sj.x_short);
2201 /* Something that translates to U+FFFD */
2202 sj.x_short = UNKSJIS;
2207 havesj = 1; /* Have Shift-JIS */
2209 uc.x_short = sj_to_un(sj.x_short); /* Translate to UCS-2 */
2210 haveuc = 1; /* Have Unicode */
2211 #endif /* UNICODE */
2212 flag = 1; /* Have a char */
2216 if (!flag) { /* If no character was read yet... */
2217 if ((x = (fn ? (*fn)() : zminchar())) > -1) /* read one now */
2219 debug(F101,"xgnbyte zminchar 1","",x);
2226 thischar = uc.x_short;
2227 /* lastucs2 = uc.x_short; */
2229 #endif /* UNICODE */
2231 debug(F001,"xgnbyte thischar",haveuc ? "[UNICODE]" : "[other]",thischar);
2233 #ifdef CK_CTRLZ /* SET EOF CTRLZ */
2234 if (eofmethod == XYEOF_Z && !binary && thischar == 26) {
2235 debug(F100,"xgnbyte EOF on Ctrl-Z 1","",0);
2238 #endif /* CK_CTRLZ */
2241 if (!haveuc) /* If not Unicode... */
2242 #endif /* UNICODE */
2243 x &= fmask; /* Apply SET FILE BYTESIZE mask */
2245 switch (xlatype) { /* Translation type... */
2247 case XLA_UNICODE: { /* Unicode is involved */
2250 Here we must choose the appropriate translation function. If we are being
2251 called by getpkt() (i.e. when transferring a file), we are translating from
2252 Unicode to the Transfer Character Set and therefore must use the function
2253 pointed to by xut. Otherwise, e.g. during TRANSLATE, CONNECT, TRANSMIT, etc,
2254 we are translating from Unicode to the File Character Set and so must call
2255 the function pointed to by xuf. There might be a cleaner way to set this
2256 up but I don't think so. For example, setxlatype() might have been called
2257 too soon and so might not have known whether it was a file transfer or a
2261 (Many years later...) In testing this code I noticed that TRANSLATE'ing
2262 Russian text from UTF-8 to ISO Latin/Cyrillic produced all question marks.
2263 Rereading the previous paragraph it seems to me we are (I am) overloading
2264 this function with responsibilites, satisfying the needs of file transfer
2265 (local file charset -> transfer charset for outbound packet) and local file
2266 conversion. In the case of TRANSLATE, we call (xgnbyte(), xpnbyte()) in a
2267 loop, expecting the xgnbyte() will feed UCS2 to xpnbyte(). But the
2268 following code does what xpnbyte() is going to do, returning (in this case)
2269 an ISO Latin/Cyrillic byte stream, which xpnbyte() believes to be UCS2, and
2270 comes up with nonsense. Not wanting to rip the whole thing apart and start
2271 over, I made the following change that should do no harm, upon observing
2272 that if the input character set is UTF-8 or UCS-2, then when we get here it
2273 has already been converted to UCS2, so if we are not transferring a file, we
2274 don't need to do anything else except put the bytes in the right place to be
2275 returned, which is done further along.
2279 xx = (what & W_SEND) ? xut : xuf;
2281 /* New code 2011-06-03 */
2282 if (what & W_SEND) {
2285 if (fcs == FC_UCS2 || fcs == FC_UTF8)
2290 #endif /* COMMENT */
2293 if (haveuc) { /* File is Unicode */
2294 /* See Unicode TR13, "Converting to Other Character Sets" */
2295 if (uc.x_short == 0x2028 || /* Line Separator? */
2296 uc.x_short == 0x2029 || /* Paragraph Separator */
2297 (feol && (uc.x_short == (USHORT)feol))
2299 debug(F001,"xgnbyte uc eol","",uc.x_short);
2301 eolflag = 1; /* Don't translate and handle later */
2303 if (xx && !eolflag) { /* UCS-to-TCS function (UCS->byte) */
2304 rc = (*xx)(uc.x_short); /* These can fail... */
2305 debug(F101,"xgnbyte xx rc","",rc);
2306 if (rc < 0) /* If it can't be translated */
2307 uc.x_short = UNK; /* Put unknown-character symbol */
2309 uc.x_short = (unsigned)((unsigned)rc & 0xffff);
2310 debug(F101,"xgnbyte xx uc","",uc.x_short);
2313 if (tcs == FC_JEUC) { /* Translating to EUC-JP */
2316 debug(F001,"xgnbyte UCS->EUC UCS","",uc.x_short);
2317 if (!havesj) /* If we don't already have it */
2318 sj = un_to_sj(uc.x_short); /* convert to Shift-JIS */
2319 eu.x_short = sj_to_eu(sj);
2320 debug(F001,"xgnbyte UCS->EUC EUC","",eu.x_short);
2324 if (what & W_SEND) {
2325 xlabuf[xlacount++] = LF;
2331 if (eu.x_char[byteorder]) { /* Two bytes */
2332 rc = eu.x_char[byteorder];
2333 xlabuf[xlacount++] = eu.x_char[1-byteorder];
2334 debug(F001,"xgnbyte UCS->EUC xlabuf[0]","",xlabuf[0]);
2335 } else { /* One byte */
2336 rc = eu.x_char[1-byteorder];
2338 debug(F101,"xgnbyte UCS->EUC xlacount","",xlacount);
2339 debug(F001,"xgnbyte UCS->EUC rc","",rc);
2343 if (tcs != FC_UCS2 && tcs != FC_UTF8) {
2344 if (uc.x_short & 0xff00) { /* Decoding error */
2345 debug(F001,"xgnbyte decoding error","",uc.x_short);
2348 return((unsigned int)(uc.x_short & 0xff));
2352 } else { /* File is not Unicode */
2354 /* Translate from single FCS byte to UCS-2 */
2356 This is a bit nonobvious... The blah_u() (Blah-to-Unicode) routines are
2357 called only with pieces of character sets, in the ISO 2022 sense. So,
2358 for example, if ch is a Latin-1 character, we call the translation
2359 routine only if it is in the right half; if it's in the left half, it
2360 isn't translated, and in fact will give the wrong result if sent to the
2361 translation function. That's because those functions were designed for
2362 use with the ISO 2022 G0..G3 sets, not for file transfer. On the other
2363 hand, if it's a 7-bit character set, we *do* call the translation
2364 function. (To put it another way, the left half of any 8-bit character
2365 set is ASCII and therefore doesn't need to be translated but 7-bit sets
2366 such as ISO 646 German do need translation).
2368 ch = (unsigned)(thischar & 0xff);
2369 if (((fcsinfo[fcs].size > 128) && (ch & 0x80)) ||
2370 fcsinfo[fcs].size <= 128) {
2371 if (xfu) { /* FCS-to-UCS function */
2377 /* At this point we have a UCS-2 character in native format */
2378 /* (Big Endian or Little Endian) in xc, which is an unsigned int. */
2380 debug(F001,"xgnbyte xc","",xc);
2382 if (tcs == FC_UTF8) { /* Now convert to UTF-8 */
2383 USHORT c; /* NOTE: this is FC_UTF8 on purpose! */
2392 if (eolflag) { /* We detected EOL in source file */
2393 if (what & W_SEND) { /* Convert to CRLF */
2396 return((unsigned int)CR);
2398 } else { /* Or to local line-end */
2400 return((unsigned int)feol);
2401 #endif /* COMMENT */
2405 if ((x = ucs2_to_utf8(c,&buf)) < 1) {
2406 debug(F101,"xgnbyte ucs2_to_utf8 error","",c);
2409 debug(F101,"xgnbyte UTF8 buf[0]","",buf[0]);
2410 for (i = 1; i < x; i++) {
2411 xlabuf[k+i-1] = buf[i];
2412 debug(F111,"xgnbyte UTF8 xlabuf",ckitoa(i-1),buf[i]);
2416 debug(F101,"xgnbyte UTF8 xlacount","",xlacount);
2417 return((unsigned int)buf[0]);
2418 } else { /* Or keep it as UCS-2 */
2425 debug(F101,"xgnbyte error","",k);
2427 if (eolflag) { /* We detected EOL in source file */
2428 if (what & W_SEND) { /* Convert to CRLF */
2433 debug(F101,"xgnbyte send CRLF","",k);
2434 return(0); /* Return NUL */
2435 } else { /* Or to local line-end */
2437 /* This bypasses byte swapping that we might need */
2438 xlabuf[k++] = (CHAR)feol;
2440 debug(F101,"xgnbyte send feol","",k);
2441 return(0); /* Return NUL */
2444 #endif /* COMMENT */
2447 /* In which order should we return the bytes? */
2449 if ( (what & W_SEND) || (what & W_FTP) || (fileorder == 0)) {
2450 #endif /* COMMENT */
2451 /* ALWAYS RETURN IN BIG ENDIAN ORDER... 7 Sep 2002 */
2452 /* xgnbyte() is almost always used to feed xpnbyte() */
2453 /* which requires bytes in BE order. In cases where */
2454 /* xgnbyte is used in isolation, the caller can swap */
2455 /* bytes itself afterwards. */
2456 xlabuf[k++] = (xc >> 8) & 0xff; /* Big Endian */
2457 xlabuf[k++] = xc & 0xff;
2458 debug(F001,"xgnbyte->UCS2BE",
2459 ckitox((int)xlabuf[0]),xlabuf[1]);
2461 } else { /* Little Endian */
2462 xlabuf[k++] = xc & 0xff;
2463 xlabuf[k++] = (xc >> 8) & 0xff;
2464 debug(F001,"xgnbyte->UCS2LE",
2465 ckitox((int)xlabuf[0]),xlabuf[1]);
2467 #endif /* COMMENT */
2471 debug(F101,"xgnbyte c","",c);
2472 debug(F101,"xgnbyte xlaptr","",xlaptr);
2473 debug(F011,"xgnbyte xlabuf",xlabuf,xlacount);
2474 return((unsigned int)c);
2477 #endif /* UNICODE */
2479 return((fn ? (*fn)() : zminchar()));
2480 case XLA_BYTE: /* Byte-for-Byte translation */
2491 #endif /* UNICODE */
2492 return((unsigned int)rt);
2495 case XLA_JAPAN: /* Come here with Shift-JIS */
2496 if (tcs == FC_JEUC) { /* It better be... */
2500 printf("BAD BAD\n");
2503 if (!haveeu) /* We might already have EUC too */
2504 eu.x_short = sj_to_eu(sj.x_short);
2505 if (eu.x_char[byteorder]) {
2506 xlabuf[xlacount++] = eu.x_char[1-byteorder];
2507 return(eu.x_char[byteorder]);
2509 return(eu.x_char[1-byteorder]);
2516 debug(F101,"xgnbyte bad xlatype","",xlatype);
2521 If there is a return() statement here, some compilers complain
2522 about "statement not reached". If there is no return() statement,
2523 other compilers complain that "Non-void function should return a value".
2524 There is no path through this function that falls through to here.
2526 debug(F100,"xgnbyte switch failure","",0);
2528 #endif /* COMMENT */
2530 #endif /* NOCSETS */
2534 /* G E T P K T -- Fill a packet data field from the indicated source. */
2538 bufmax: Maximum length of entire packet.
2539 xlate: Flag for whether to translate charsets when in text mode.
2540 Returns: Number of characters written to packet data field, 0 or more,
2541 Or -1 on failure (internal error),
2542 or -3 on timeout (e.g. when reading from a pipe).
2544 This is the full version allowing for parity and text-mode conversions;
2545 i.e. it works in all cases. Also see bgetpkt(), a special lean/mean/fast
2546 packet encoder that works only for binary-mode no-parity transfers.
2548 static int uflag = 0;
2551 getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
2552 register CHAR rt = t, rnext = NUL; /* Register shadows of the globals */
2553 register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
2554 register int x; /* Loop index. */
2555 register int a7; /* Low 7 bits of character */
2557 CHAR xxls, xxdl, xxrc, xxss, xxcq; /* Pieces of prefixed sequence */
2559 if (binary) xlate = 0; /* We don't translate if binary */
2562 debug(F100,"SERIOUS ERROR: getpkt data == NULL","",0);
2565 dp = data; /* Point to packet data buffer */
2566 size = 0; /* And initialize its size */
2568 Assume bufmax is the receiver's total receive-packet buffer length.
2569 Our whole packet has to fit into it, so we adjust the data field length.
2570 We also decide optimally whether it is better to use a short-format or
2571 long-format packet when we're near the borderline.
2573 bufmax = maxdata(); /* Get maximum data length */
2575 if (first == 1) { /* If first character of this file.. */
2577 /* Special end-of-line handling for Unicode */
2578 if (tcharset == TC_UCS2 || tcharset == TC_UTF8)
2580 #endif /* UNICODE */
2581 debug(F101,"getpkt first uflag","",uflag);
2582 debug(F101,"getpkt first rt","",rt);
2583 if (!memstr && !funcstr) /* and real file... */
2584 ffc = (CK_OFF_T)0; /* reset file character counter */
2586 /* Moved to below... */
2587 first = 0; /* Next character won't be first */
2588 #endif /* COMMENT */
2589 *leftover = '\0'; /* Discard any interrupted leftovers */
2592 setxlatype(tcharset,fcharset); /* Set up charset translations */
2593 #endif /* NOCSETS */
2595 /* Get first character of file into rt, watching out for null file */
2598 if (calibrate && !memstr) {
2602 x = rt = cal_a[rand() & 0xff];
2603 #endif /* NORANDOM */
2607 #endif /* CALIBRATE */
2609 if (xlate && tcharset == TC_JEUC) { /* Kanji text */
2611 if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
2615 debug(F100,"getpkt zkanji: input error","",0);
2617 } else debug(F100,"getpkt zkanji: empty string/file","",0);
2624 if (docrc && (what & W_SEND)) /* Accumulate file crc */
2627 } else { /* Not Kanji text */
2629 if (memstr) { /* Reading data from memory string */
2630 /* This will not be Unicode */
2631 if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
2634 debug(F100,"getpkt: empty string","",0);
2638 } else if (funcstr) { /* Reading data from a function */
2639 /* This will not be Unicode */
2640 if ((x = (*funcptr)()) < 0) { /* End of input */
2642 size = 0; /* Empty */
2645 ffc++; /* Count a file character */
2646 rt = (CHAR) x; /* Convert int to char */
2648 debug(F000,"getpkt funcstr","",rt);
2650 } else { /* Reading data from a file */
2652 if (xlate && !binary) { /* Could be Unicode */
2653 if (xlatype == XLA_UNICODE) {
2654 /* Get next translated byte */
2655 x = xgnbyte(cseqtab[tcharset],fcharset,NULL);
2656 debug(F101,"getpkt xgnbyte","",x);
2657 } else { /* Not Unicode */
2658 x = zminchar(); /* Get next byte, translate below */
2659 debug(F101,"getpkt zminchar A","",x);
2661 } else { /* Just get next byte */
2662 #endif /* NOCSETS */
2664 debug(F101,"getpkt zminchar B","",x);
2667 #endif /* NOCSETS */
2668 if (x < 0) { /* End of file or input error */
2669 if (x == -3) { /* Timeout. */
2671 debug(F101,"getpkt timeout size","",size);
2672 return((size == 0) ? x : size);
2676 if (x == -2) { /* Error */
2677 debug(F100,"getpkt: input error","",0);
2678 cxseen = 1; /* Interrupt the file transfer */
2680 debug(F100,"getpkt empty file","",0);
2684 first = 0; /* Next character won't be first */
2685 rt = (CHAR) x; /* Convert int to char */
2687 if (xlatype != XLA_UNICODE || binary) {
2691 if (docrc && (what & W_SEND))
2694 #endif /* NOCSETS */
2697 debug(F101,"getpkt 1st char","",rt);
2699 if (/* !haveuc && */ docrc && (what & W_SEND)) /* File CRC */
2705 /* PWP: handling of feol is done later (in the while loop)... */
2707 } else if ((first == -1) && (nleft == 0)) { /* EOF from last time */
2710 debug(F101,"getpkt eof crc16","",crc16);
2711 debug(F101,"getpkt eof ffc","",ffc);
2717 Here we handle characters that were encoded for the last packet but
2718 did not fit, and so were saved in the "leftover" array.
2720 debug(F101,"getpkt nleft","",nleft);
2722 for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */
2724 *leftover = '\0'; /* Delete leftovers */
2727 if (first == -1) /* Handle EOF */
2728 return(size = (dp - data));
2730 /* Now fill up the rest of the packet. */
2732 rpt = 0; /* Initialize character repeat count */
2734 while (first > -1) { /* Until EOF... */
2736 if (calibrate && !memstr) { /* We generate our own "file" */
2737 if (ffc >= calibrate) { /* EOF */
2740 } else { /* Generate next character */
2741 if (cal_j > CAL_M * ffc)
2742 cal_j = cal_a[ffc & 0xff];
2743 x = (unsigned)cal_a[(cal_j & 0xff)];
2744 if (x == rt) x ^= 2;
2746 cal_j += (unsigned int)(ffc + CAL_O);
2749 #endif /* CALIBRATE */
2751 if (xlate && tcharset == TC_JEUC) {
2752 if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
2754 if (x == -2) cxseen = 1;
2755 } else if (!memstr) ffc++;
2756 rnext = (CHAR) (x & fmask);
2759 if (memstr) { /* Get next char from memory string */
2760 if ((x = *memptr++) == '\0') /* End of string means EOF */
2761 first = -1; /* Flag EOF for next time. */
2762 rnext = (CHAR) (x & fmask); /* Apply file mask */
2763 } else if (funcstr) { /* Get next char from function */
2764 if ((x = (*funcptr)()) < 0) /* End of string means EOF */
2765 first = -1; /* Flag EOF for next time. */
2766 rnext = (CHAR) (x & fmask); /* Apply file mask */
2767 } else { /* From file... */
2769 if (xlate && !binary) { /* Could be Unicode */
2770 if (xlatype == XLA_UNICODE) {
2771 /* Get next translated byte */
2772 x = xgnbyte(cseqtab[tcharset],fcharset,NULL);
2773 } else { /* Not Unicode */
2774 x = zminchar(); /* Get next byte, translate below */
2775 /* debug(F101,"xgnbyte B zminchar","",x); */
2777 } else { /* Just get next byte */
2778 #endif /* NOCSETS */
2780 /* debug(F101,"xgnbyte C zminchar","",x); */
2783 #endif /* NOCSETS */
2784 if (x < 0) { /* Check for EOF */
2785 if (x == -3) { /* Timeout reading from pipe */
2788 debug(F101,"getpkt timeout size","",size);
2789 return((size == 0) ? x : size);
2791 first = -1; /* Flag eof for next time. */
2792 if (x == -2) cxseen = 1; /* If error, cancel this file. */
2794 rnext = (CHAR) (x & fmask); /* Apply file mask */
2796 if (xlatype != XLA_UNICODE) {
2797 #endif /* NOCSETS */
2802 #endif /* NOCSETS */
2803 if (docrc && (what & W_SEND))
2808 #endif /* NOCSETS */
2814 At this point, the character we just read is in rnext,
2815 and the character we are about to encode into the packet is in rt.
2817 odp = dp; /* Remember where we started. */
2818 xxls = xxdl = xxrc = xxss = xxcq = NUL; /* Clear these. */
2820 Now encode the character according to the options that are in effect:
2821 ctlp[]: whether this control character needs prefixing.
2822 binary: text or binary mode.
2823 rptflg: repeat counts enabled.
2824 ebqflg: 8th-bit prefixing enabled.
2825 lscapu: locking shifts enabled.
2827 if (rptflg) { /* Repeat processing is on? */
2830 * If the next char is really CRLF, then we cannot
2831 * be doing a repeat (unless CR,CR,LF which becomes
2832 * "~ <n-1> CR CR LF", which is OK but not most efficient).
2833 * I just plain don't worry about this case. The actual
2834 * conversion from NL to CRLF is done after the rptflg if...
2836 (!feol || binary || (feol && (rnext != feol))) &&
2837 (rt == rnext) && (first == 0)) { /* Got a run... */
2838 if (++rpt < 94) { /* Below max, just count */
2839 continue; /* go back and get another */
2840 } else if (rpt == 94) { /* Reached max, must dump */
2841 xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
2842 rptn += rpt; /* Accumulate it for statistics */
2843 rpt = 0; /* And reset it */
2845 } else if (rpt > 1) { /* More than two */
2846 xxrc = (CHAR) tochar(++rpt); /* and count. */
2848 rpt = 0; /* Reset repeat counter. */
2851 If (rpt == 1) we must encode exactly two characters.
2852 This is done later, after the first character is encoded.
2855 /* If it's the newline character... */
2856 if (!uflag && !binary && feol && (rt == feol)) {
2857 if (lscapu && lsstate) { /* If SHIFT-STATE is SHIFTED */
2858 if (ebqflg) { /* If single shifts enabled, */
2859 *dp++ = (CHAR) ebq; /* insert a single shift. */
2860 } else { /* Otherwise must shift in. */
2861 *dp++ = myctlq; /* Insert shift-out code */
2863 lsstate = 0; /* Change shift state */
2868 *dp++ = myctlq; /* Insert carriage return directly */
2872 *dp++ = CR; /* Perhaps literally */
2875 #else /* !CK_SPEED */
2876 *dp++ = myctlq; /* Insert carriage return directly */
2879 #endif /* CK_SPEED */
2880 rt = LF; /* Now make next char be linefeed. */
2883 Now handle the 8th bit of the file character. If we have an 8-bit
2884 connection, we preserve the 8th bit. If we have a 7-bit connection,
2885 we employ either single or locking shifts (if they are enabled).
2887 a7 = rt & 0177; /* Get low 7 bits of character */
2888 if (rt & 0200) { /* 8-bit character? */
2889 if (lscapu) { /* Locking shifts enabled? */
2890 if (!lsstate) { /* Not currently shifted? */
2891 x = lslook(0200); /* Look ahead */
2892 if (x != 0 || ebqflg == 0) { /* Locking shift decision */
2893 xxls = 'N'; /* Need locking shift-out */
2894 lsstate = 1; /* and change to shifted state */
2895 } else if (ebqflg) { /* Not worth it */
2896 xxss = (CHAR) ebq; /* Use single shift */
2899 rt = (CHAR) a7; /* Replace character by 7-bit value */
2900 } else if (ebqflg) { /* 8th bit prefixing is on? */
2901 xxss = (CHAR) ebq; /* Insert single shift */
2902 rt = (CHAR) a7; /* Replace character by 7-bit value */
2905 In case we have a 7-bit connection and this is an 8-bit character, AND
2906 neither locking shifts nor single shifts are enabled, then the character's
2907 8th bit will be destroyed in transmission, and a block check error will
2910 } else if (lscapu) { /* 7-bit character */
2912 if (lsstate) { /* Comes while shifted out? */
2913 x = lslook(0); /* Yes, look ahead */
2914 if (x || ebqflg == 0) { /* Time to shift in. */
2915 xxls = 'O'; /* Set shift-in code */
2916 lsstate = 0; /* Exit shifted state */
2917 } else if (ebqflg) { /* Not worth it, stay shifted out */
2918 xxss = (CHAR) ebq; /* Insert single shift */
2922 /* If data character is significant to locking shift protocol... */
2923 if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
2924 xxdl = 'P'; /* Insert datalink escape */
2929 Thwart YET ANOTHER unwanted, unneeded, and unloved sign
2930 extension. This one was particularly nasty because it prevented
2931 255 (Telnet IAC) from being prefixed on some platforms -- e.g.
2932 VMS with VAX C -- but not others, thus causing file transfers to
2933 fail on Telnet connections by sending bare IACs. Not to mention
2934 the stray memory reference. Signed chars are a BAD idea.
2936 ctlp[(unsigned)(rt & 0xff)] /* Lop off any "sign" extension */
2938 (a7 < SP) || (a7 == DEL)
2939 #endif /* CK_SPEED */
2940 ) { /* Do control prefixing if necessary */
2941 xxcq = myctlq; /* The prefix */
2942 ccp++; /* Count it */
2943 rt = (CHAR) ctl(rt); /* Uncontrollify the character */
2946 else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
2948 #endif /* CK_SPEED */
2950 if (a7 == myctlq) /* Always prefix the control prefix */
2953 if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */
2954 xxcq = myctlq; /* prefix it if doing repeat counts */
2956 if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th-bit prefix */
2957 xxcq = myctlq; /* if doing 8th-bit prefixes */
2959 /* Now construct the entire sequence */
2961 if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
2962 odp2 = dp; /* (Save this place) */
2963 if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
2964 if (xxrc) { *dp++ = (CHAR) rptq; *dp++ = xxrc; } /* Repeat count */
2965 if (xxss) { *dp++ = (CHAR) ebq; } /* Single shift */
2966 if (xxcq) { *dp++ = myctlq; } /* Control prefix */
2967 *dp++ = rt; /* Finally, the character itself */
2969 if (rpt == 1) { /* Exactly two copies? */
2971 p2 = dp; /* Save place temporarily */
2972 for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
2974 if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
2975 if ((p2-data) < bufmax) odp = p2; /* Check packet bounds */
2977 rt = rnext; /* Next character is now current. */
2979 /* Done encoding the character. Now take care of packet buffer overflow. */
2981 if ((dp-data) >= bufmax) { /* If too big, save some for next. */
2983 debug(F000,"getpkt EOP","",rt);
2985 size = (dp-data); /* Calculate the size. */
2986 *dp = '\0'; /* Mark the end. */
2987 if (memstr) { /* No leftovers for memory strings */
2988 if (rt) /* Char we didn't encode yet */
2989 memptr--; /* (for encstr()) */
2992 if ((dp-data) > bufmax) { /* if packet is overfull */
2993 /* copy the part that doesn't fit into the leftover buffer, */
2994 /* taking care not to split a prefixed sequence. */
2997 for (i = 0, p1 = leftover, p2 = odp; i < nleft; i++) {
2999 if (memstr) memptr--; /* (for encstr) */
3001 debug(F111,"getpkt leftover",leftover,size);
3002 debug(F101,"getpkt osize","",(odp-data));
3003 size = (odp-data); /* Return truncated packet. */
3004 *odp = '\0'; /* Mark the new end */
3006 t = rt; /* Save for next time */
3009 } /* Otherwise, keep filling. */
3010 size = (dp-data); /* End of file */
3011 *dp = '\0'; /* Mark the end of the data. */
3012 debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
3013 return(size); /* return partially filled last packet. */
3016 /* T I N I T -- Initialize a transaction */
3018 int epktrcvd = 0, epktsent = 0;
3021 Call with 1 to reset everything before S/I/Y negotiation, or 0 to
3022 reset only the things that are not set in the S/I/Y negotiation.
3023 Returns -1 on failure (e.g. to create packet buffers), 0 on success.
3026 tinit(flag) int flag; {
3030 #endif /* CK_TIMERS */
3034 debug(F101,"tinit flag","",flag);
3040 diractive = 0; /* DIR / REMOTE DIR not active */
3041 interrupted = 0; /* Not interrupted */
3042 fatalio = 0; /* No fatal i/o error */
3045 pipesend = 0; /* This takes care of multiple GETs sent to a server. */
3047 bestlen = 0; /* For packet length optimization */
3048 maxsend = 0; /* Biggest data field we can send */
3050 streamok = 0; /* Streaming negotiated */
3051 streaming = 0; /* Streaming being done now */
3052 #endif /* STREAMING */
3054 binary = b_save; /* ... */
3055 gnf_binary = binary; /* Per-file transfer mode */
3056 retrans = 0; /* Packet retransmission count */
3057 sndtyp = 0; /* No previous packet */
3058 xflg = 0; /* Reset x-packet flag */
3059 memstr = 0; /* Reset memory-string flag */
3060 memptr = NULL; /* and buffer pointer */
3061 funcstr = 0; /* Reset "read from function" flag */
3062 funcptr = NULL; /* and function pointer */
3063 autopar = 0; /* Automatic parity detection flag */
3065 /* This stuff is only for BEFORE S/I/Y negotiation, not after */
3068 if (bctf) { /* Force Block Check 3 on all packets */
3069 bctu = bctl = 3; /* Set block check type to 3 */
3071 bctu = bctl = 1; /* Reset block check type to 1 */
3073 myinit[0] = '\0'; /* Haven't sent init string yet */
3074 rqf = -1; /* Reset 8th-bit-quote request flag */
3075 ebq = MYEBQ; /* Reset 8th-bit quoting stuff */
3076 ebqflg = 0; /* 8th bit quoting not enabled */
3077 ebqsent = 0; /* No 8th-bit prefix bid sent yet */
3078 sq = 'Y'; /* 8th-bit prefix bid I usually send */
3079 spsiz = spsizr; /* Initial send-packet size */
3080 debug(F101,"tinit spsiz","",spsiz);
3081 wslots = 1; /* One window slot */
3082 wslotn = 1; /* No window negotiated yet */
3083 justone = 0; /* (should this be zero'd here?) */
3084 whoareu[0] = NUL; /* Partner's system type */
3087 what = W_INIT; /* Doing nothing so far... */
3089 fncnv = f_save; /* Back to what user last said */
3090 pktnum = 0; /* Initial packet number to send */
3091 cxseen = czseen = discard = 0; /* Reset interrupt flags */
3092 *filnam = '\0'; /* Clear file name */
3093 spktl = 0; /* And its length */
3094 nakstate = 0; /* Assume we're not in a NAK state */
3095 numerrs = 0; /* Transmission error counter */
3096 idletmo = 0; /* No idle timeout yet */
3097 if (server) { /* If acting as server, */
3098 if (srvidl > 0) /* If an idle timeout is given */
3101 timint = srvtim; /* use server timeout interval. */
3102 } else { /* Otherwise */
3103 timint = chktimo(rtimo,timef); /* and use local timeout value */
3105 debug(F101,"tinit timint","",timint);
3108 if (rttflg && timint > 0) /* Using round-trip timers? */
3111 #endif /* CK_TIMERS */
3114 winlo = 0; /* Packet 0 is at window-low */
3115 debug(F101,"tinit winlo","",winlo);
3116 x = mksbuf(1); /* Make a 1-slot send-packet buffer */
3117 if (x < 0) return(x);
3118 x = getsbuf(0); /* Allocate first send-buffer. */
3119 debug(F101,"tinit getsbuf","",x);
3120 if (x < 0) return(x);
3122 x = mkrbuf(wslots); /* & a 1-slot receive-packet buffer. */
3123 if (x < 0) return(x);
3124 lsstate = 0; /* Initialize locking shift state */
3125 if (autopath) { /* SET RECEIVE PATHNAMES AUTO fixup */
3126 fnrpath = PATH_AUTO;
3133 pktinit() { /* Initialize packet sequence */
3134 pktnum = 0; /* number & window low. */
3136 debug(F101,"pktinit winlo","",winlo);
3139 /* R I N I T -- Respond to S or I packet */
3145 tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
3146 tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
3147 tlog(F110,"Collision action:", fncnam[fncact],0);
3149 debug(F101,"rinit fncact","",fncact);
3150 filcnt = filrej = 0; /* Init file counters */
3154 if ((local) && (!quiet)) /* Only do this if local & not quiet */
3155 consta_mt(); /* Start the asynch read task */
3156 #endif /* datageneral */
3160 /* R E S E T C -- Reset per-transaction character counters */
3164 rptn = 0; /* Repeat counts */
3165 fsecs = flci = flco = (CK_OFF_T)0; /* File chars in and out */
3168 #endif /* GFTIMER */
3169 tfc = tlci = tlco = (CK_OFF_T)0; /* Total file, line chars in & out */
3170 ccu = ccp = 0L; /* Control-char statistics */
3172 fsize = (CK_OFF_T)-1; /* File size */
3174 if (!(what & W_SEND))
3175 fsize = (CK_OFF_T)-1;
3176 debug(F101,"resetc fsize","",fsize);
3177 #endif /* COMMENT */
3178 timeouts = retrans = 0; /* Timeouts, retransmissions */
3179 spackets = rpackets = 0; /* Packet counts out & in */
3180 crunched = 0; /* Crunched packets */
3181 wcur = 0; /* Current window size */
3182 wmax = 0; /* Maximum window size used */
3183 peakcps = 0; /* Peak chars per second */
3186 /* S I N I T -- Get & verify first file name, then send Send-Init packet */
3189 1 if send operation begins successfully
3190 0 if send operation fails
3193 char *cmargbuf = NULL;
3195 char cmargbuf[CKMAXPATH+1];
3196 #endif /* DYNAMIC */
3202 sndsrc = (nfils < 0) ? -1 : nfils; /* Source for filenames */
3204 if (!cmargbuf && !(cmargbuf = malloc(CKMAXPATH+1)))
3205 fatal("fnlist: no memory for cmargbuf");
3206 #endif /* DYNAMIC */
3207 cmargbuf[0] = NUL; /* Initialize name buffer */
3209 debug(F101,"fnlist nfils","",nfils);
3210 debug(F110,"fnlist cmarg",cmarg,0);
3211 debug(F110,"fnlist cmarg2",cmarg2,0);
3212 if (!cmarg2) cmarg2 = "";
3213 if (nfils == 0) { /* Sending from stdin or memory. */
3214 if ((cmarg2 != NULL) && (*cmarg2)) {
3215 cmarg = cmarg2; /* If F packet, "as-name" is used */
3216 cmarg2 = ""; /* if provided */
3218 cmarg = "stdin"; /* otherwise just use "stdin" */
3219 ckstrncpy(cmargbuf,cmarg,CKMAXPATH+1);
3220 cmargp[0] = cmargbuf;
3229 int x; /* Worker int */
3230 char *tp, *xp, *m; /* Worker string pointers */
3232 filcnt = filrej = 0; /* Initialize file counters */
3239 if (usepipes && protocol == PROTO_K && *cmarg == '!') {
3243 #endif /* PIPESEND */
3248 xp = filehead->fl_name;
3250 #endif /* NOMSEND */
3258 debug(F110,"sinit xp",xp,0);
3259 x = gnfile(); /* Get first filename. */
3260 debug(F111,"sinit gnfile",ckitoa(gnferror),x);
3261 if (x == 0) x = gnferror; /* If none, get error reason */
3262 m = NULL; /* Error message pointer */
3263 debug(F101,"sinit gnfil","",x);
3265 case -6: m = "No files meet selection criteria"; break;
3266 case -5: m = "Too many files match wildcard"; break;
3267 case -4: m = "Cancelled"; break;
3268 case -3: m = "Read access denied"; break;
3269 case -2: m = "File is not readable"; break;
3271 case -1: m = iswild(filnam) ? "No files match" : "File not found";
3273 case 0: m = "No filespec given!"; break;
3276 case -1: m = iswild(filnam) ? "No files match" : "File not found";
3278 #endif /* COMMENT */
3282 debug(F101,"sinit nfils","",nfils);
3283 debug(F110,"sinit filnam",filnam,0);
3284 if (x < 1) { /* Didn't get a file. */
3285 debug(F111,"sinit msg",m,x);
3286 if (server) { /* Doing GET command */
3287 errpkt((CHAR *)m); /* so send Error packet. */
3288 } else if (!local) { /* Doing SEND command */
3289 interrupted = 1; /* (To suppress hint) */
3290 printf("?%s\r\n",m);
3292 xxscreen(SCR_EM,0,0l,m); /* so print message. */
3294 tlog(F110,xp,m,0L); /* Make transaction log entry. */
3295 freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */
3296 return(0); /* Return failure code */
3298 if (!local && !server && ckdelay > 0) /* OS-9 sleep(0) == infinite */
3299 sleep(ckdelay); /* Delay if requested */
3301 if ((local) && (!quiet)) /* Only do this if local & not quiet */
3302 consta_mt(); /* Start the async read task */
3303 #endif /* datageneral */
3304 freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */
3305 sipkt('S'); /* Send the Send-Init packet. */
3306 ztime(&tp); /* Get current date/time */
3307 tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
3308 tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
3310 debug(F111,"sinit ok",filnam,0);
3316 sipkt(char c) /* Send S or I packet. */
3322 extern int sendipkts;
3323 debug(F101,"sipkt pktnum","",pktnum); /* (better be 0...) */
3324 ttflui(); /* Flush pending input. */
3326 If this is an I packet and SET SEND I-PACKETS is OFF, don't send it;
3327 set sstate to 'Y' which makes the next input() call return 'Y' as if we
3328 had received an ACK to the I packet we didn't send. This is to work
3329 around buggy Kermit servers that can't handle I packets.
3331 if ((sendipkts == 0) && (c == 'I')) { /* I packet but don't send I pkts? */
3332 sstate = 'Y'; /* Yikes! */
3333 return(0); /* (see input()..)*/
3335 k = sseqtbl[pktnum]; /* Find slot for this packet */
3336 if (k < 0) { /* No slot? */
3337 k = getsbuf(winlo = pktnum); /* Make one. */
3338 debug(F101,"sipkt getsbuf","",k);
3340 rp = rpar(); /* Get protocol parameters. */
3341 if (!rp) rp = (CHAR *)"";
3342 x = spack(c,pktnum,(int)strlen((char *)rp),rp); /* Send them. */
3346 /* X S I N I T -- Retransmit S-packet */
3348 For use in the GET-SEND sequence, when we start to send, but receive another
3349 copy of the GET command because the receiver didn't get our S packet.
3350 This retransmits the S packet and frees the receive buffer for the ACK.
3351 This special case is necessary because packet number zero is being re-used.
3357 debug(F101,"xsinit k","",k);
3363 /* R C V F I L -- Receive a file */
3366 Incoming filename is in data field of F packet.
3367 This function decodes it into the srvcmd buffer, substituting an
3368 alternate "as-name", if one was given.
3369 Then it does any requested transformations (like converting to
3370 lowercase), and finally if a file of the same name already exists,
3371 takes the desired collision action.
3376 char ofn1[CKMAXPATH+4]; /* Buffer for output file name */
3377 char * ofn2; /* Pointer to backup file name */
3378 int ofn1x; /* Flag output file already exists */
3379 CK_OFF_T ofn1len = (CK_OFF_T)0;
3380 int opnerr; /* Flag for open error */
3382 int /* Returns success ? 1 : 0 */
3383 rcvfil(n) char *n; {
3389 char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */
3390 #endif /* OS2ONLY */
3396 extern char * rcvfilter;
3397 #endif /* PIPESEND */
3401 csave = calibrate; /* So we can decode filename */
3402 calibrate = (CK_OFF_T)0;
3403 #endif /* CALIBRATE */
3405 ofperms = ""; /* Reset old-file permissions */
3406 opnerr = 0; /* No open error (yet) */
3407 ofn2 = NULL; /* No new name (yet) */
3408 lsstate = 0; /* Cancel locking-shift state */
3409 srvptr = srvcmd; /* Decode file name from packet. */
3412 xpnbyte(-1,0,0,NULL); /* Reset UCS-2 byte counter. */
3413 #endif /* UNICODE */
3415 debug(F110,"rcvfil rdatap",rdatap,0);
3416 decode(rdatap,putsrv,0); /* Don't xlate charsets. */
3419 if (dest == DEST_N) {
3421 cmarg2 = "CALIBRATE";
3423 #endif /* CALIBRATE */
3424 if (*srvcmd == '\0') /* Watch out for null F packet. */
3425 ckstrncpy((char *)srvcmd,"NONAME",srvcmdlen);
3426 makestr(&prrfspec,(char *)srvcmd); /* New preliminary filename */
3428 if (*srvcmd == '~') {
3429 dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
3431 ckstrncpy((char *)srvcmd,dirp,srvcmdlen);
3435 if (isalpha(*srvcmd) && srvcmd[1] == ':' && srvcmd[2] == '\0')
3436 ckstrncat((char *)srvcmd,"NONAME",srvcmdlen);
3442 /* File dialog when downloading... */
3445 (apcactive == APC_LOCAL && adl_ask) || /* Autodownload with ASK */
3447 (clcmds && haveurl) /* Or "kermit:" or "iksd:" URL */
3450 char fnbuf[CKMAXPATH+1]; /* Result buffer */
3453 if (clcmds && haveurl)
3454 preface = "\r\nIncoming file from Kermit server...\r\n\
3455 Please confirm output file specification or supply an alternative:";
3457 preface = "\r\nIncoming file from remote Kermit...\r\n\
3458 Please confirm output file specification or supply an alternative:";
3460 x = uq_file(preface, /* Preface */
3461 NULL, /* Prompt (let uq_file() built it) */
3462 3, /* Output file */
3463 NULL, /* Help text */
3464 (char *)srvcmd, /* Default */
3465 fnbuf, /* Result buffer */
3466 CKMAXPATH+1 /* Size of result buffer */
3468 if (x < 1) { /* Refused */
3469 rf_err = "Refused by user";
3472 ckstrncpy((char *)srvcmd,fnbuf,CKMAXPATH+1);
3473 if (isabsolute((char *)srvcmd)) { /* User gave an absolute path */
3474 g_fnrpath = fnrpath; /* Save current RECEIVE PATHNAMES */
3475 fnrpath = PATH_ABS; /* switch to ABSOLUTE */
3481 if (!ENABLED(en_cwd)) { /* CD is disabled */
3482 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
3483 if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
3484 rf_err = "Access denied";
3489 /* Wrong place for this -- handle cmarg2 first -- see below... */
3491 if (zchko((char *)srvcmd) < 0) { /* Precheck for write access */
3492 debug(F110,"rcvfil access denied",srvcmd,0);
3493 rf_err = "Write access denied";
3494 discard = opnerr = 1;
3497 xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
3498 debug(F110,"rcvfil srvcmd 1",srvcmd,0);
3499 tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
3500 #endif /* COMMENT */
3502 skipthis = 0; /* This file in our exception list? */
3503 for (i = 0; i < NSNDEXCEPT; i++) {
3504 if (!rcvexcept[i]) {
3507 if (ckmatch(rcvexcept[i],(char *)srvcmd,filecase,1)) {
3514 if (deblog && skipthis) {
3515 debug(F111,"rcvfil rcvexcept",rcvexcept[i],i);
3516 debug(F110,"rcvfil skipping",srvcmd,0);
3520 if (skipthis) { /* Skipping this file */
3523 rf_err = "Exception list";
3524 debug(F101,"rcvfil discard","",discard);
3525 tlog(F100," refused: exception list","",0);
3529 /* File is not in exception list */
3531 if (!cmarg2) /* No core dumps please */
3533 debug(F110,"rcvfil cmarg2",cmarg2,0);
3535 if (*cmarg2) { /* Check for alternate name */
3537 int y; char *s; /* Pass it thru the evaluator */
3538 extern int cmd_quoting;
3541 ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* for \v(filename) */
3543 zzstring(cmarg2,&s,&y);
3546 if (!*srvcmd) /* If we got something */
3548 ckstrncpy((char *)srvcmd,cmarg2,srvcmdlen);
3550 debug(F110,"rcvfil srvcmd 2",srvcmd,0);
3553 /* If it starts with "bang", it's a pipe, not a file. */
3554 if (usepipes && protocol == PROTO_K && *srvcmd == '!' && !rcvfilter) {
3556 s = srvcmd+1; /* srvcmd[] is not a pointer. */
3557 while (*s) { /* So we have to slide the contents */
3558 *(s-1) = *s; /* over 1 space to the left. */
3564 #endif /* PIPESEND */
3568 This is commented out because we need to know whether the name we are
3569 using was specified by the local user as an override, or came from the
3570 incoming packet. In the former case, we don't do stuff to it (like
3571 strip the pathname) that we might do to it in the latter.
3573 cmarg2 = ""; /* Done with alternate name */
3574 #endif /* COMMENT */
3576 if ((int)strlen((char *)srvcmd) > CKMAXPATH) /* Watch out for overflow */
3577 *(srvcmd + CKMAXPATH - 1) = NUL;
3579 /* At this point, srvcmd[] contains the incoming filename or as-name. */
3580 /* So NOW we check for write access. */
3582 if (zchko((char *)srvcmd) < 0) { /* Precheck for write access */
3583 debug(F110,"rcvfil access denied",srvcmd,0);
3584 rf_err = "Write access denied";
3585 discard = opnerr = 1;
3588 xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
3589 debug(F110,"rcvfil srvcmd 1",srvcmd,0);
3590 tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
3595 If we have an as-name, this overrides the internal name if we are doing
3596 a labeled-mode transfer.
3600 lf_opts &= ~LBL_NAM;
3603 #endif /* CK_LABELED */
3605 debug(F111,"rcvfil pipesend",srvcmd,pipesend);
3608 /* Skip all the filename manipulation and collision actions */
3612 ckstrncpy(&ofn1[1],(char *)srvcmd,CKMAXPATH+1);
3613 ckstrncpy(n,ofn1,CKMAXPATH+1);
3614 ckstrncpy(fspec,ofn1,CKMAXPATH+1);
3615 makestr(&prfspec,fspec); /* New preliminary filename */
3616 debug(F110,"rcvfil pipesend",ofn1,0);
3619 #endif /* PIPESEND */
3621 This is to avoid passing email subjects through nzrtol().
3622 We haven't yet received the A packet so we don't yet know it's e-mail,
3623 so in fact we go ahead and convert it anyway, but later we get the
3624 original back from ofilnam[].
3627 ckstrncpy(ofilnam,(char *)srvcmd,CKMAXPATH+1);
3631 ckstrncpy((char *)ofn1,(char *)srvcmd,CKMAXPATH+1);
3633 nzrtol((char *)srvcmd, /* Filename from packet */
3634 (char *)ofn1, /* Where to put result */
3635 fncnv, /* Filename conversion */
3636 fnrpath, /* Pathname handling */
3637 CKMAXPATH /* Size of result buffer */
3640 debug(F101,"rcvfil fnrpath","",fnrpath); /* Handle pathnames */
3641 if (fnrpath == PATH_OFF && !*cmarg2) { /* RECEIVE PATHNAMES OFF? */
3643 zstrip((char *)srvcmd,&t); /* If there is a pathname, strip it */
3644 debug(F110,"rcvfil PATH_OFF zstrip",t,0);
3645 if (!t) /* Be sure we didn't strip too much */
3646 sprintf(ofn1,"FILE%02ld",filcnt);
3647 else if (*t == '\0')
3648 sprintf(ofn1,"FILE%02ld",filcnt);
3650 ckstrncpy(ofn1,t,CKMAXPATH+1);
3651 ckstrncpy((char *)srvcmd,ofn1,srvcmdlen); /* Now copy it back. */
3654 SET RECEIVE PATHNAMES RELATIVE...
3655 The following doesn't belong here but doing it right would require
3656 defining and implementing a new file routine for all ck?fio.c modules.
3660 else if (fnrpath == PATH_REL && !*cmarg2) {
3661 if (isabsolute((char *)srvcmd)) {
3663 ckstrncpy(&of1n[1],(char *)srvcmd,CKMAXPATH+1);
3664 ckstrncpy((char *)srvcmd,ofn1,srvcmdlen);
3665 debug(F110,"rcvfil PATH_REL",ofn1,0);
3670 else if (fnrpath == PATH_REL && !*cmarg2) {
3671 if (isabsolute((char *)srvcmd)) {
3672 char *p = (char *)srvcmd;
3673 if (isalpha(*p) && *(p+1) == ':')
3675 if (*p == '\\' || *p == '/')
3677 ckstrncpy(ofn1,p,CKMAXPATH+1);
3678 ckstrncpy((char *)srvcmd,ofn1,srvcmdlen);
3679 debug(F110,"rcvfil OS2 PATH_REL",ofn1,0);
3683 #endif /* UNIXOROSK */
3685 /* Now srvcmd contains incoming filename with path possibly stripped */
3687 if (fncnv) /* FILE NAMES CONVERTED? */
3688 zrtol((char *)srvcmd,(char *)ofn1); /* Yes, convert to local form */
3690 ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* No, copy literally. */
3695 char * p = NULL, * q;
3698 debug(F110,"rcvfil rcvfilter ",rcvfilter,0);
3700 if ((p = (char *) malloc(nn + 1))) {
3703 /* We have already processed srvcmd and placed it into ofn1 */
3704 ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* For \v(filename) */
3705 #endif /* COMMENT */
3706 debug(F110,"rcvfile pipesend filter",rcvfilter,0);
3707 zzstring(rcvfilter,&p,&nn);
3708 debug(F111,"rcvfil pipename",q,nn);
3711 "?Sorry, receive filter + filename too long, %d max.\n",
3714 rf_err = "Name too long";
3718 ckstrncpy((char *)srvcmd,q,MAXRP);
3723 #endif /* PIPESEND */
3725 /* Now the incoming filename, possibly converted, is in ofn1[]. */
3728 /* Don't refuse the file just because the name is illegal. */
3729 if (!IsFileNameValid(ofn1)) { /* Name is OK for OS/2? */
3732 zstrip(ofn1, &zs); /* Not valid, strip unconditionally */
3734 if (iattr.longname.len && /* Free previous longname, if any */
3736 free(iattr.longname.val);
3737 iattr.longname.len = strlen(zs); /* Store in attribute structure */
3738 iattr.longname.val = (char *) malloc(iattr.longname.len + 1);
3739 if (iattr.longname.val) /* Remember this (illegal) name */
3740 strcpy(iattr.longname.val, zs); /* safe */
3742 #endif /* OS2ONLY */
3743 debug(F110,"rcvfil: invalid file name",ofn1,0);
3744 ChangeNameForFAT(ofn1); /* Change to an acceptable name */
3745 debug(F110,"rcvfil: FAT file name",ofn1,0);
3747 } else { /* Name is OK. */
3749 debug(F110,"rcvfil: valid file name",ofn1,0);
3751 if (iattr.longname.len &&
3752 iattr.longname.val) /* Free previous longname, if any */
3753 free(iattr.longname.val);
3754 iattr.longname.len = 0;
3755 iattr.longname.val = NULL; /* This file doesn't need a longname */
3756 #endif /* OS2ONLY */
3759 debug(F110,"rcvfil as",ofn1,0);
3761 /* Filename collision action section. */
3763 dirflg = /* Is it a directory name? */
3768 #endif /* CK_TMPDIR */
3770 debug(F101,"rcvfil dirflg","",dirflg);
3771 ofn1len = zchki(ofn1); /* File already exists? */
3772 debug(F111,"rcvfil ofn1len",ofn1,ofn1len);
3773 ofn1x = (ofn1len != (CK_OFF_T)-1);
3777 strcmp(ofn1,"/dev/null") && /* It's not the null device? */
3780 strcmp(ofn1,"/nil") &&
3783 !stdouf ) && /* Not copying to standard output? */
3784 ofn1x || /* File of same name exists? */
3785 dirflg ) { /* Or file is a directory? */
3786 debug(F111,"rcvfil exists",ofn1,fncact);
3788 ofperms = zgperm((char *)ofn1); /* Get old file's permissions */
3789 debug(F110,"rcvfil perms",ofperms,0);
3790 #endif /* CK_PERMS */
3792 debug(F101,"rcvfil fncact","",fncact);
3793 switch (fncact) { /* Yes, do what user said. */
3794 case XYFX_A: /* Append */
3796 debug(F100,"rcvfil append","",0);
3798 rf_err = "Can't append to a directory";
3799 tlog(F100," error - can't append to directory","",0);
3800 discard = opnerr = 1;
3803 tlog(F110," appending to",ofn1,0);
3806 case XYFX_Q: /* Query (Ask) */
3807 break; /* not implemented */
3808 #endif /* COMMENT */
3809 case XYFX_B: /* Backup (rename old file) */
3811 rf_err = "Can't rename existing directory";
3812 tlog(F100," error - can't rename directory","",0);
3813 discard = opnerr = 1;
3816 znewn(ofn1,&ofn2); /* Get new unique name */
3817 tlog(F110," backup:",ofn2,0);
3818 debug(F110,"rcvfil backup ofn1",ofn1,0);
3819 debug(F110,"rcvfil backup ofn2",ofn2,0);
3823 In case this is a FAT file system, we can't change only the FAT name, we
3824 also have to change the longname from the extended attributes block.
3825 Otherwise, we'll have many files with the same longname and if we copy them
3826 to an HPFS volume, only one will survive.
3828 if (os2getlongname(ofn1, &longname) > -1) {
3829 if (strlen(longname)) {
3831 extern int ck_znewn;
3832 sprintf(tmp,".~%d~",ck_znewn);
3834 (char *) malloc(strlen(longname) + strlen(tmp) + 1);
3836 strcpy(newlongname, longname); /* safe (prechecked) */
3837 strcat(newlongname, tmp); /* safe (prechecked) */
3838 os2setlongname(ofn1, newlongname);
3843 } else debug(F100,"rcvfil os2getlongname failed","",0);
3844 #endif /* OS2ONLY */
3845 #endif /* CK_LABELED */
3848 /* Do this later, in opena()... */
3849 if (zrename(ofn1,ofn2) < 0) {
3850 rf_err = "Can't transform filename";
3851 debug(F110,"rcvfil rename fails",ofn1,0);
3852 discard = opnerr = 1;
3855 #endif /* COMMENT */
3858 case XYFX_D: /* Discard (refuse new file) */
3861 rejection = 1; /* Horrible hack: reason = name */
3862 debug(F101,"rcvfil discard","",discard);
3863 tlog(F100," refused: name","",0);
3866 case XYFX_R: /* Rename incoming file */
3867 znewn(ofn1,&ofn2); /* Make new name for it */
3869 if (iattr.longname.len) {
3871 extern int ck_znewn;
3872 sprintf(tmp,".~%d~",ck_znewn);
3874 (char *) malloc(iattr.longname.len + strlen(tmp) + 1);
3876 strcpy(newlongname, iattr.longname.val); /* safe */
3877 strcat(newlongname, tmp); /* safe */
3879 "Rename Incoming: newlongname",newlongname,0);
3880 if (iattr.longname.len &&
3882 free(iattr.longname.val);
3883 iattr.longname.len = strlen(newlongname);
3884 iattr.longname.val = newlongname;
3885 /* free(newlongname) here ? */
3888 #endif /* OS2ONLY */
3890 case XYFX_X: /* Replace old file */
3891 debug(F100,"rcvfil overwrite","",0);
3893 rf_err = "Can't overwrite existing directory";
3894 tlog(F100," error - can't overwrite directory","",0);
3895 discard = opnerr = 1;
3900 #endif /* COMMENT */
3902 tlog(F110,"overwriting",ofn1,0);
3904 case XYFX_U: /* Refuse if older */
3905 debug(F110,"rcvfil update",ofn1,0);
3907 rf_err = "File has same name as existing directory";
3908 tlog(F110," error - directory exists:",ofn1,0);
3909 discard = opnerr = 1;
3911 /* Don't send an error packet, just refuse the file */
3913 #endif /* COMMENT */
3915 break; /* Not here, we don't have */
3916 /* the attribute packet yet. */
3919 debug(F101,"rcvfil bad collision action","",fncact);
3923 debug(F110,"rcvfil ofn1",ofn1,0);
3924 debug(F110,"rcvfil ofn2",ofn2,0);
3925 debug(F110,"rcvfil ofperms",ofperms,0);
3926 if (fncact == XYFX_R && ofn1x && ofn2) { /* Renaming incoming file? */
3927 xxscreen(SCR_AN,0,0l,ofn2); /* Display renamed name */
3928 ckstrncpy(n, ofn2, CKMAXPATH+1); /* Return it */
3930 xxscreen(SCR_AN,0,0l,ofn1); /* Display regular name */
3931 ckstrncpy(n, ofn1, CKMAXPATH+1); /* and return it. */
3935 /* Create directory(s) if necessary. */
3936 if (!discard && fnrpath != PATH_OFF) { /* RECEIVE PATHAMES ON? */
3938 debug(F110,"rcvfil calling zmkdir",ofn1,0); /* Yes */
3939 if ((x = zmkdir(ofn1)) < 0) {
3940 debug(F100,"zmkdir fails","",0);
3941 tlog(F110," error - directory creation failure:",ofn1,0);
3942 rf_err = "Directory creation failure.";
3948 tlog(F110," path created:",ofn1,0);
3952 debug(F110,"rcvfil CK_MKDIR not defined",ofn1,0);
3953 #endif /* CK_MKDIR */
3956 ckstrncpy(fspec,ofn1,CKMAXPATH+1);
3958 zfnqfp(ofn1,fspeclen,fspec);
3959 debug(F110,"rcvfil fspec",fspec,0);
3962 /* See comments with VMS zfnqfp()... */
3964 /* zfnqfp() does not return the version number */
3969 if (ofn1[x-1] == ';') {
3971 ckstrncpy(&ofn1[x],ckitoa(v),CKMAXPATH-x);
3976 #endif /* COMMENT */
3977 fspec[fspeclen] = NUL;
3978 makestr(&prfspec,fspec); /* New preliminary filename */
3982 #endif /* PIPESEND */
3984 debug(F110,"rcvfilx: n",n,0);
3985 debug(F110,"rcvfilx: ofn1",ofn1,0);
3986 ffc = (CK_OFF_T)0; /* Init per-file counters */
3988 rs_len = (CK_OFF_T)0;
3990 fsecs = gtimer(); /* Time this file started */
3992 fpfsecs = gftimer();
3993 debug(F101,"rcvfil fpfsecs","",fpfsecs);
3994 #endif /* GFTIMER */
3997 return(1); /* Successful return */
4001 /* R E O F -- Receive End Of File packet for incoming file */
4004 Closes the received file.
4007 -1 if file could not be closed.
4008 2 if disposition was mail, mail was sent, but temp file not deleted.
4009 3 if disposition was print, file was printed, but not deleted.
4010 -2 if disposition was mail and mail could not be sent
4011 -3 if disposition was print and file could not be printed
4012 -4 if MOVE-TO: failed
4013 -5 if RENAME-TO: failed
4016 reof(f,yy) char *f; struct zattr *yy; {
4017 extern char * rcv_move, * rcv_rename;
4018 extern int o_isopen;
4019 int rc = 0; /* Return code */
4023 debug(F111,"reof fncact",f,fncact);
4024 debug(F101,"reof discard","",discard);
4025 success = 1; /* Assume status is OK */
4026 lsstate = 0; /* Cancel locking-shift state */
4027 if (discard) { /* Handle attribute refusals, etc. */
4028 debug(F101,"reof discarding","",0);
4029 success = 0; /* Status = failed. */
4030 if (rejection == '#' || /* Unless rejection reason is */
4031 rejection == 1 || /* date or name (SET FILE COLLISION */
4032 rejection == '?') /* UPDATE or DISCARD) */
4034 debug(F101,"reof success","",success);
4035 filrej++; /* Count this rejection. */
4036 discard = 0; /* We never opened the file, */
4037 return(0); /* so we don't close it. */
4041 debug(F101,"reof cxseen","",cxseen);
4042 debug(F101,"reof czseen","",czseen);
4043 debug(F110,"reof rdatap",rdatap,0);
4047 if (cxseen == 0) /* Got cancel directive? */
4048 cxseen = (*rdatap == 'D');
4049 if (cxseen || czseen) /* (for hints) */
4051 success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */
4052 if (!success) /* "Uncount" this file */
4054 debug(F101,"reof o_isopen","",o_isopen);
4056 if (o_isopen) { /* If an output file was open... */
4060 debug(F101,"reof lastchar","",lastchar);
4061 if (!binary && eofmethod == XYEOF_Z && lastchar != 26 &&
4062 (!xflg || (xflg && remfile)))
4063 pnbyte((char)26,putfil);
4065 #endif /* CK_CTRLZ */
4067 rc = clsof(cxseen || czseen); /* Close the file (resets cxseen) */
4068 debug(F101,"reof closf","",rc);
4069 if (rc < 0) { /* If failure to close, FAIL */
4070 if (success) filrej++;
4074 /* Set file modification date and/or permissions */
4079 if (success && yy->longname.len)
4080 os2setlongname(f, yy->longname.val);
4081 #endif /* CK_LABELED */
4082 #endif /* OS2ONLY */
4084 if (success == 0) { /* And program return code */
4086 } else if (success == 1) { /* File rec'd successfully */
4087 makestr(&rrfspec,prrfspec); /* Record it for wheremsg */
4088 makestr(&rfspec,prfspec);
4091 /* Handle dispositions from attribute packet... */
4095 if (!calibrate && yy->disp.len != 0) {
4100 See ckcpro.w. In UNIX we don't use temp files any more -- we pipe the
4101 stuff right into mail or lpr.
4103 if (c == 'M') { /* Mail to user. */
4104 rc = zmail(p,filnam); /* Do the system's mail command */
4105 if (rc < 0) success = 0; /* Remember status */
4106 tlog(F110,"mailed",filnam,0L);
4107 tlog(F110," to",p,0L);
4108 zdelet(filnam); /* Delete the file */
4109 } else if (c == 'P') { /* Print the file. */
4110 rc = zprint(p,filnam); /* Do the system's print command */
4111 if (rc < 0) success = 0; /* Remember status */
4112 tlog(F110,"printed",filnam,0L);
4113 tlog(F110," with options",p,0L);
4116 /* spooler deletes file after print complete in VOS & VMS */
4117 if (zdelet(filnam) && rc == 0) rc = 3; /* Delete the file */
4118 #endif /* STRATUS */
4123 #endif /* NOFRILLS */
4127 !calibrate && c != 'M' && c != 'P') {
4128 if (rcv_move) { /* If /MOVE-TO was given... */
4129 char * p = rcv_move;
4131 /* No need for this - it's a directory name */
4132 char tmpbuf[CKMAXPATH+1];
4133 extern int cmd_quoting; /* for \v(filename) */
4134 if (cmd_quoting) { /* But only if cmd_quoting is on */
4138 debug(F111,"reof /move-to",rcv_move,0);
4139 zzstring(rcv_move,&p,&n);
4142 #endif /* COMMENT */
4144 Here we could create the directory if it didn't exist (and it was relative)
4145 but there would have to be a user-settable option to say whether to do this.
4147 rc = zrename(filnam,p);
4148 debug(F111,"reof MOVE zrename",rcv_move,rc);
4150 tlog(F110," moving received file to",rcv_move,0);
4153 tlog(F110," FAILED to move received file to",rcv_move,0);
4155 } else if (rcv_rename) { /* Or /RENAME-TO: */
4156 char *s = rcv_rename; /* This is the renaming string */
4158 char tmpnam[CKMAXPATH+16];
4159 extern int cmd_quoting; /* for \v(filename) */
4160 if (cmd_quoting) { /* But only if cmd_quoting is on */
4161 int n; /* Pass it thru the evaluator */
4164 zzstring(rcv_rename,&s,&n);
4169 rc = zrename(filnam,s);
4170 debug(F111,"reof RENAME zrename",s,rc);
4172 tlog(F110," renaming received file to",s,0);
4175 tlog(F110," FAILED to rename received file to",s,0);
4181 debug(F101,"reof success","",success);
4182 debug(F101,"reof returns","",rc);
4184 filnam[0] = NUL; /* Erase the filename */
4188 /* R E O T -- Receive End Of Transaction */
4192 cxseen = czseen = discard = 0; /* Reset interruption flags */
4193 tstats(); /* Finalize transfer statistics */
4196 /* S F I L E -- Send File header or teXt header packet */
4199 Call with x nonzero for X packet, zero for F packet.
4200 If X == 0, filename to send is in filnam[], and if cmarg2 is not null
4201 or empty, the file should be sent under this name rather than filnam[].
4202 If sndfilter not NULL, it is the name of a send filter.
4203 Returns 1 on success, 0 on failure.
4212 char pktnam[PKTNL+1]; /* Local copy of name */
4216 extern int filepeek;
4218 extern char * sndfilter;
4222 debug(F110,"sfile send filter ",sndfilter,0);
4224 #endif /* PIPESEND */
4226 notafile = calibrate || sndarray || pipesend || x;
4227 debug(F101,"sfile x","",x);
4228 debug(F101,"sfile notafile","",notafile);
4231 if (tcs_save > -1) { /* Character sets */
4232 tcharset = tcs_save;
4234 debug(F101,"sfile restored tcharset","",tcharset);
4236 if (fcs_save > -1) {
4237 fcharset = fcs_save;
4239 debug(F101,"sfile restored fcharset","",fcharset);
4241 setxlatype(tcharset,fcharset); /* Translation type */
4242 #endif /* NOCSETS */
4244 /* cmarg2 or filnam (with that precedence) have the file's name */
4246 lsstate = 0; /* Cancel locking-shift state */
4248 /* Do this after making sure we can open the file */
4249 if (nxtpkt() < 0) return(0); /* Bump packet number, get buffer */
4250 #endif /* COMMENT */
4251 pktnam[0] = NUL; /* Buffer for name we will send */
4252 if (x == 0) { /* F-Packet setup */
4253 if (!cmarg2) cmarg2 = "";
4256 /* debug(F111,"sfile cmarg2",cmarg2,cmarg2); */
4257 debug(F101,"sfile binary 1","",binary);
4258 debug(F101,"sfile wearealike","",wearealike);
4259 debug(F101,"sfile xfermode","",xfermode);
4260 debug(F101,"sfile filepeek","",filepeek);
4262 debug(F101,"sfile s_cset","",s_cset);
4263 debug(F101,"sfile tcharset","",tcharset);
4264 debug(F101,"sfile xfrxla","",xfrxla);
4265 #endif /* NOCSETS */
4268 if (xfermode == XMODE_A /* TRANSFER MODE AUTOMATIC */
4270 && !addlist /* And not working from a SEND-LIST */
4271 #endif /* NOMSEND */
4273 /* Other Kermit is on a like system and no charset translation */
4276 && (tcharset == TC_TRANSP || xfrxla == 0)
4277 #endif /* NOCSETS */
4280 if (binary != XYFT_I)
4283 if (binary != XYFT_L)
4284 #endif /* CK_LABELED */
4285 binary = XYFT_B; /* Send all files in binary mode */
4288 /* Otherwise select transfer mode based on file info */
4290 else if (!notafile /* but not if sending from pipe */
4292 && binary != XYFT_L /* and not if FILE TYPE LABELED */
4293 #endif /* CK_LABELED */
4295 && binary != XYFT_I /* or FILE TYPE IMAGE */
4299 fileorder = -1; /* File byte order */
4300 #endif /* UNICODE */
4301 if (filepeek && !notafile) { /* Real file, FILE SCAN is ON */
4303 k = scanfile(filnam,&x,nscanfile); /* Scan the file */
4304 debug(F101,"sfile scanfile","",k);
4306 case FT_TEXT: /* Unspecified text */
4307 debug(F100,"sfile scanfile text","",0);
4308 binary = XYFT_T; /* SET FILE TYPE TEXT */
4311 case FT_7BIT: /* 7-bit text */
4312 binary = XYFT_T; /* SET FILE TYPE TEXT */
4313 /* If SEND CHARSET-SELECTION AUTO */
4314 /* and SET TRANSFER TRANSLATION is ON */
4315 debug(F100,"sfile scanfile text7","",0);
4316 if (s_cset == XMODE_A && xfrxla) {
4317 if (fcsinfo[fcharset].size != 128) {
4318 fcs_save = fcharset; /* Current FCS not 7bit */
4319 fcharset = dcset7; /* Use default 7bit set */
4320 debug(F101,"sfile scanfile 7 fcharset",
4323 /* And also switch to appropriate TCS */
4324 if (afcset[fcharset] > -1 &&
4325 afcset[fcharset] <= MAXTCSETS) {
4326 tcs_save = tcharset;
4327 tcharset = afcset[fcharset];
4328 debug(F101,"sfile scanfile 7 tcharset","",
4331 setxlatype(tcharset,fcharset);
4335 case FT_8BIT: /* 8-bit text */
4336 binary = XYFT_T; /* SET FILE TYPE TEXT */
4337 /* If SEND CHARSET-SELEC AUTO */
4338 /* and SET TRANSFER TRANSLATION is ON */
4339 debug(F100,"sfile scanfile text8","",0);
4340 if (s_cset == XMODE_A && xfrxla) {
4341 if (fcsinfo[fcharset].size != 256) {
4342 fcs_save = fcharset; /* Current FCS not 8bit */
4343 fcharset = dcset8; /* Use default 8bit set */
4344 debug(F101,"sfile scanfile 8 fcharset",
4347 /* Switch to corresponding transfer charset */
4348 if (afcset[fcharset] > -1 &&
4349 afcset[fcharset] <= MAXTCSETS) {
4350 tcs_save = tcharset;
4351 tcharset = afcset[fcharset];
4352 debug(F101,"sfile scanfile 8 tcharset","",
4355 setxlatype(tcharset,fcharset);
4359 case FT_UTF8: /* UTF-8 text */
4360 case FT_UCS2: /* UCS-2 text */
4361 debug(F101,"sfile scanfile Unicode","",k);
4363 /* If SEND CHARSET-SELEC AUTO */
4364 /* and SET TRANSFER TRANSLATION is ON */
4365 if (s_cset == XMODE_A && xfrxla) {
4366 fcs_save = fcharset;
4367 tcs_save = tcharset;
4368 fcharset = (k == FT_UCS2) ? FC_UCS2 : FC_UTF8;
4369 if (k == FT_UCS2 && x > -1)
4372 /* Switch to associated transfer charset if any */
4373 if (afcset[fcharset] > -1 &&
4374 afcset[fcharset] <= MAXTCSETS)
4375 tcharset = afcset[fcharset];
4376 if (tcharset == TC_TRANSP) /* If none */
4377 tcharset = TC_UTF8; /* use UTF-8 */
4378 setxlatype(tcharset,fcharset);
4379 debug(F101,"sfile Unicode tcharset","",tcharset);
4381 #endif /* UNICODE */
4382 #endif /* NOCSETS */
4384 debug(F101,"sfile scanfile binary","",k);
4387 /* Default: Don't change anything */
4391 debug(F101,"sfile binary 2","",binary);
4392 debug(F101,"sfile sendmode","",sendmode);
4394 if (*cmarg2) { /* If we have a send-as name... */
4396 #ifndef NOSPL /* and a script programming language */
4397 extern int cmd_quoting;
4398 if (cmd_quoting) { /* and it's not turned off */
4399 y = PKTNL; /* pass as-name thru the evaluator */
4401 zzstring(cmarg2,&s,&y);
4403 /* This ruins macros like BSEND */
4404 if (!pktnam[0]) /* and make sure result is not empty */
4405 sprintf(pktnam,"FILE%02ld",filcnt);
4406 #endif /* COMMENT */
4409 ckstrncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */
4411 debug(F110,"sfile pktnam",pktnam,0);
4413 /* We don't do this any more because now we have filename templates */
4414 cmarg2 = ""; /* and blank it out for next time. */
4415 #endif /* COMMENT */
4417 if (!*pktnam) { /* No as-name... */
4420 debug(F101,"sfile fnspath","",fnspath);
4421 debug(F101,"sfile fncnv","",fncnv);
4424 if (notafile) { /* If not an actual file */
4425 xfncnv = 0; /* Don't convert name */
4426 xpath = PATH_OFF; /* Leave path off */
4427 } else if (xfncnv &&
4428 (!strcmp(whoareu,"U1") || !strcmp(whoareu,"UN"))
4430 /* Less-strict conversion if partner is UNIX or Win32 */
4433 debug(F101,"sfile xpath","",xpath);
4434 debug(F101,"sfile xfncnv","",xfncnv);
4435 nzltor(filnam,pktnam,xfncnv,xpath,PKTNL);
4437 #else /* Not NZLTOR */
4439 debug(F101,"sfile fnspath","",fnspath);
4440 if (fnspath == PATH_OFF /* Stripping path names? */
4441 && (!notafile) /* (of actual files) */
4444 zstrip(filnam,&t); /* Strip off the path. */
4445 debug(F110,"sfile zstrip",t,0);
4446 if (!t) t = "UNKNOWN"; /* Be cautious... */
4447 else if (*t == '\0')
4449 ckstrncpy(pktnam,t,PKTNL); /* Copy stripped name literally. */
4450 } else if (fnspath == PATH_ABS && !notafile) {
4451 /* Converting to absolute form */
4452 zfnqfp(filnam,PKTNL,pktnam);
4454 ckstrncpy(pktnam,filnam,PKTNL);
4456 /* pktnam[] has the packet name, filnam[] has the original name. */
4457 /* But we still need to convert pktnam if FILE NAMES CONVERTED. */
4459 debug(F101,"sfile fncnv","",fncnv);
4460 if (fncnv && !notafile) { /* If converting names of files */
4461 zltor(pktnam,(char *)srvcmd); /* convert it to common form, */
4462 ckstrncpy(pktnam,(char *)srvcmd,PKTNL);
4467 if (!*pktnam) /* Failsafe... */
4468 sprintf(pktnam,"FILE%02ld",filcnt);
4469 debug(F110,"sfile filnam 1",filnam,0);
4470 debug(F110,"sfile pktnam 1",pktnam,0);
4472 /* If we have a send filter, substitute the current filename into it */
4475 char * p = NULL, * q;
4478 if ((p = (char *) malloc(n + 1))) {
4480 debug(F110,"sfile pipesend filter",sndfilter,0);
4481 zzstring(sndfilter,&p,&n);
4482 debug(F111,"sfile pipename",q,n);
4485 "?Sorry, send filter + filename too long, %d max.\n",
4491 ckstrncpy(filnam,q,CKMAXPATH+1);
4496 #endif /* PIPESEND */
4498 debug(F110,"sfile filnam 2",filnam,0); /* Log debugging info */
4499 debug(F110,"sfile pktnam 2",pktnam,0);
4500 if (openi(filnam) == 0) /* Try to open the input file */
4505 The following check is done after openi() is called, since openi() itself
4506 can change the transfer mode (as in VMS).
4508 if ((binary == XYFT_T
4512 ) && sendmode == SM_RESEND) {
4513 /* Trying to RESEND/REGET a file first sent in TEXT mode. */
4514 debug(F111,"sfile error - Recover vs Text",filnam,binary);
4515 /* Set appropriate error messages and make log entries here */
4517 if (binary == XYFT_L)
4518 ckmakmsg((char *)epktmsg,
4520 "Recovery attempted in LABELED mode: ",
4527 ckmakmsg((char *)epktmsg,
4529 "Recovery attempted in TEXT mode: ",
4536 if (sendmode == SM_PSEND) /* PSENDing? */
4537 if (sendstart > (CK_OFF_T)0) /* Starting position */
4538 if (zfseek(sendstart) < 0) /* seek to it... */
4540 #endif /* CK_RESEND */
4541 s = pktnam; /* Name for packet data field */
4543 /* Never send a disk letter. */
4544 if (isalpha(*s) && (*(s+1) == ':'))
4548 } else { /* X-packet setup, not F-packet. */
4549 binary = XYFT_T; /* Text always */
4550 debug(F110,"sfile X packet",cmdstr,0); /* Log debugging info */
4551 s = cmdstr; /* Name for data field */
4554 /* Now s points to the string that goes in the packet data field. */
4556 debug(F101,"sfile binary","",binary); /* Log debugging info */
4557 encstr((CHAR *)s); /* Encode the name. */
4558 /* Send the F or X packet */
4559 /* If the encoded string did not fit into the packet, it was truncated. */
4561 if (nxtpkt() < 0) return(0); /* Bump packet number, get buffer */
4563 rc = spack((char) (x ? 'X' : 'F'), pktnum, size, data);
4568 setxlatype(tcharset,fcharset); /* Set up charset translations */
4569 #endif /* NOCSETS */
4571 if (x == 0) { /* Display for F packet */
4572 if (displa) { /* Screen */
4573 xxscreen(SCR_FN,'F',(long)pktnum,filnam);
4574 xxscreen(SCR_AN,0,0L,pktnam);
4575 xxscreen(SCR_FS,0,calibrate ? calibrate : fsize,"");
4578 tlog(F110,"Sending",filnam,0L); /* Transaction log entry */
4579 makestr(&psfspec,filnam); /* New filename */
4582 tlog(F110,"Sending",filnam,0L);
4583 makestr(&psfspec,filnam); /* New filename */
4585 if (notafile) { /* If not a file log simple name */
4586 tlog(F110,"Sending", filnam, 0L);
4587 } else { /* Log fully qualified filename */
4589 /* This section generates bad code in SCO 3.2v5.0.5's cc */
4590 char *p = NULL, *q = filnam;
4591 debug(F101,"sfile CKMAXPATH","",CKMAXPATH);
4592 if ((p = malloc(CKMAXPATH+1))) {
4593 debug(F111,"sfile calling zfnqfp",filnam,strlen(filnam));
4594 if (zfnqfp(filnam, CKMAXPATH, p)) {
4595 debug(F111,"sfile zfnqfp ok",p,strlen(p));
4600 char tmpbuf[CKMAXPATH+1];
4601 char *p = tmpbuf, *q = filnam;
4602 if (zfnqfp(filnam, CKMAXPATH, p))
4604 #endif /* COMMENT */
4605 debug(F111,"sfile q",q,strlen(q));
4606 tlog(F110,"Sending",q,0L);
4607 makestr(&psfspec,q); /* New preliminary filename */
4610 #endif /* COMMENT */
4614 tlog(F110," as",pktnam,0L);
4615 if (binary) { /* Log file mode in transaction log */
4616 tlog(F101," mode: binary","",(long) binary);
4617 } else { /* If text mode, check character set */
4618 tlog(F100," mode: text","",0L);
4620 if (tcharset == TC_TRANSP || xfrxla == 0) {
4621 tlog(F110," character set","transparent",0L);
4623 tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
4624 tlog(F110," file character set",fcsinfo[fcharset].name,0L);
4626 #endif /* NOCSETS */
4628 } else { /* Display for X-packet */
4630 xxscreen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */
4631 tlog(F110,"Sending from:",cmdstr,0L); /* Transaction log */
4633 intmsg(++filcnt); /* Count file, give interrupt msg */
4634 first = 1; /* Init file character lookahead. */
4635 ffc = (CK_OFF_T)0; /* Init file character counter. */
4636 cps = oldcps = 0L; /* Init cps statistics */
4638 fsecs = gtimer(); /* Time this file started */
4640 fpfsecs = gftimer();
4641 debug(F101,"SFILE fpfsecs","",fpfsecs);
4642 #endif /* GFTIMER */
4643 debug(F101,"SFILE fsecs","",fsecs);
4647 /* S D A T A -- Send a data packet */
4650 Returns -1 if no data to send (end of file), -2 if connection is broken.
4651 If there is data, a data packet is sent, and sdata() returns 1.
4653 In the streaming case, the window is regarded as infinite and we keep
4654 sending data packets until EOF or there appears to be a Kermit packet on the
4655 reverse channel. When not streaming and the window size is greater than 1,
4656 we keep sending data packets until window is full or characters start to
4657 appear from the other Kermit.
4659 In the windowing or streaming case, when there is no more data left to send
4660 (or when sending has been interrupted), sdata() does nothing and returns 0
4661 each time it is called until the acknowledgement sequence number catches up
4662 to the last data packet that was sent.
4669 debug(F101,"sdata entry, first","",first);
4670 debug(F101,"sdata drain","",drain);
4672 The "drain" flag is used with window size > 1. It means we have sent
4673 our last data packet. If called and drain is not zero, then we return
4674 0 as if we had sent an empty data packet, until all data packets have
4675 been ACK'd, then then we can finally return -1 indicating EOF, so that
4676 the protocol can switch to seof state. This is a kludge, but at least
4679 if (first == 1) drain = 0; /* Start of file, init drain flag. */
4681 if (drain) { /* If draining... */
4682 debug(F101,"sdata draining, winlo","",winlo);
4683 if (winlo == pktnum) /* If all data packets are ACK'd */
4684 return(-1); /* return EOF indication */
4685 else /* otherwise */
4686 return(0); /* pretend we sent a data packet. */
4688 debug(F101,"sdata sbufnum","",sbufnum);
4693 #endif /* STREAMING */
4698 debug(F101,"sdata countdown","",i);
4701 pktnum = (pktnum + 1) % 64;
4703 debug(F101,"sdata streaming pktnum","",pktnum);
4705 #endif /* STREAMING */
4706 x = nxtpkt(); /* Get next pkt number and buffer */
4707 debug(F101,"sdata nxtpkt pktnum","",pktnum);
4708 if (x < 0) return(0);
4711 #endif /* STREAMING */
4712 debug(F101,"sdata packet","",pktnum);
4713 if (chkint() < 0) /* Especially important if streaming */
4715 if (cxseen || czseen) { /* If interrupted, done. */
4718 debug(F100,"sdata cx/zseen windowing","",0);
4721 debug(F100,"sdata cx/zseen nonwindowing","",0);
4727 debug(F101,"sdata spsiz","",spsiz);
4728 debug(F101,"sdata binary","",binary);
4729 debug(F101,"sdata parity","",parity);
4733 if (binary && !parity && !memstr && !funcstr)
4734 len = bgetpkt(spsiz);
4736 len = getpkt(spsiz,1);
4738 len = getpkt(spsiz,1);
4739 #endif /* CKTUNING */
4741 if (len == -3) { /* Timed out (e.g.reading from pipe) */
4742 s = ""; /* Send an empty data packet. */
4744 } else if (len == 0) { /* Done if no data. */
4745 if (pktnum == winlo)
4747 drain = 1; /* But can't return -1 until all */
4748 debug(F101,"sdata eof, drain","",drain);
4749 return(0); /* ACKs are drained. */
4751 debug(F101,"sdata pktnum","",pktnum);
4752 debug(F101,"sdata len","",len);
4753 debug(F011,"sdata data",data,52);
4755 x = spack('D',pktnum,len,(CHAR *)s); /* Send the data packet. */
4756 debug(F101,"sdata spack","",x);
4757 if (x < 0) { /* Error */
4758 ttchk(); /* See if connection is still there */
4762 if (streaming) /* What an ACK would do. */
4764 #endif /* STREAMING */
4765 x = ttchk(); /* Peek at input buffer. */
4766 debug(F101,"sdata ttchk","",x); /* ACKs waiting, maybe? */
4767 if (x < 0) /* Or connection broken? */
4770 Here we check to see if any ACKs or NAKs have arrived, in which case we
4771 break out of the D-packet-sending loop and return to the state switcher
4772 to process them. This is what makes our windows slide instead of lurch.
4777 In the Atari ST version, ttchk() can only return 0 or 1. But note: x will
4778 probably always be > 0, since the as-yet-unread packet terminator from the
4779 last packet is probably still in the buffer, so sliding windows will
4780 probably never happen when the Atari ST is the file sender. The alternative
4781 is to say "if (0)", in which case the ST will always send a window full of
4782 packets before reading any ACKs or NAKs.
4788 In most other versions, ttchk() returns the actual count.
4789 It can't be a Kermit packet if it's less than five bytes long.
4795 return(1); /* Yes, stop sending data packets */
4796 } /* and go try to read the ACKs. */
4801 /* S E O F -- Send an End-Of-File packet */
4803 /* Call with a string pointer to character to put in the data field, */
4804 /* or else a null pointer or "" for no data. */
4807 There are two "send-eof" functions. seof() is used to send the normal eof
4808 packet at the end of a file's data (even if the file has no data), or when
4809 a file transfer is interrupted. sxeof() is used to send an EOF packet that
4810 occurs because of attribute refusal or interruption prior to entering data
4811 state. The difference is purely a matter of buffer allocation and packet
4812 sequence number management. Both functions act as "front ends" to the
4813 common send-eof function, szeof().
4816 /* Code common to both seof() and sxeof() */
4821 lsstate = 0; /* Cancel locking-shift state */
4822 if (!s) s = (CHAR *)"";
4823 debug(F111,"szeof",s,pktnum);
4825 x = spack('Z',pktnum,1,s);
4828 tlog(F100," *** interrupted, sending discard request","",0L);
4829 #endif /* COMMENT */
4832 x = spack('Z',pktnum,0,(CHAR *)"");
4839 discard = 0; /* Turn off per-file discard flag */
4840 #endif /* COMMENT */
4842 /* If we were sending from a pipe, we're not any more... */
4851 ckcpro.w, before calling seof(), sets window size back to 1 and then calls
4852 window(), which clears out the old buffers. This is OK because the final
4853 data packet for the file has been ACK'd. However, sdata() has already
4854 called nxtpkt(), which set the new value of pktnum which seof() will use.
4855 So all we need to do here is is allocate a new send-buffer.
4858 debug(F111,"seof",s,pktnum);
4859 if (getsbuf(pktnum) < 0) { /* Get a buffer for packet n */
4860 debug(F101,"seof can't get s-buffer","",pktnum);
4863 return(szeof((CHAR *)s));
4867 Version of seof() to be called when sdata() has not been called before. The
4868 difference is that this version calls nxtpkt() to allocate a send-buffer and
4869 get the next packet number.
4875 if (nxtpkt() < 0) /* Get next pkt number and buffer */
4876 debug(F101,"sxeof nxtpkt fails","",pktnum);
4878 debug(F101,"sxeof packet","",pktnum);
4879 return(szeof((CHAR *)s));
4882 /* S E O T -- Send an End-Of-Transaction packet */
4888 debug(F101,"seot nxtpkt","",x);
4889 if (x < 0) return(-1); /* Bump packet number, get buffer */
4890 x = spack('B',pktnum,0,(CHAR *)""); /* Send the EOT packet */
4893 cxseen = czseen = discard = 0; /* Reset interruption flags */
4894 tstats(); /* Log timing info */
4899 /* R P A R -- Fill the data array with my send-init parameters */
4903 CHAR dada[32]; /* Use this instead of data[]. */
4904 /* To avoid some kind of wierd */
4905 /* addressing foulup in spack()... */
4906 /* (which might be fixed now...) */
4914 max = maxdata(); /* Biggest data field I can send */
4915 debug(F101, "rpar max 1","",max);
4916 debug(F101, "rpar sprmlen","",sprmlen);
4917 if (sprmlen > 1 && sprmlen < max) /* User override */
4919 debug(F101, "rpar max 2","",max);
4921 if (rpsiz > MAXPACK) /* Biggest normal packet I want. */
4922 dada[0] = (char) tochar(MAXPACK); /* If > 94, use 94, but specify */
4923 else /* extended packet length below... */
4924 dada[0] = (char) tochar(rpsiz); /* else use what the user said. */
4925 dada[1] = (char) tochar(chktimo(pkttim,0)); /* When to time me out */
4926 dada[2] = (char) tochar(mypadn); /* How much padding I need (none) */
4927 dada[3] = (char) ctl(mypadc); /* Padding character I want */
4928 dada[4] = (char) tochar(eol); /* End-Of-Line character I want */
4929 dada[5] = myctlq; /* Control-Quote character I send */
4931 if (max < 6) { dada[6] = NUL; rqf = 0; ebq = sq = NUL; return(dada); }
4933 switch (rqf) { /* 8th-bit prefix (single-shift) */
4934 case -1: /* I'm opening the bids */
4935 case 1: /* Other Kermit already bid 'Y' */
4936 if (parity) ebq = sq = MYEBQ; /* So I reply with '&' if parity */
4937 break; /* otherwise with 'Y'. */
4938 case 2: /* Other Kermit sent a valid prefix */
4940 sq = ebq; /* Fall through on purpose */
4941 case 0: /* Other Kermit bid nothing */
4942 break; /* So I reply with 'Y'. */
4944 debug(F000,"rpar 8bq sq","",sq);
4945 debug(F000,"rpar 8bq ebq","",ebq);
4946 if (lscapu == 2) /* LOCKING-SHIFT FORCED */
4947 dada[6] = 'N'; /* requires no single-shift */
4948 else /* otherwise send prefix or 'Y' */
4949 dada[6] = (char) sq;
4950 ebqsent = dada[6]; /* And remember what I really sent */
4952 if (max < 7) { dada[7] = NUL; bctr = 1; return(dada); }
4954 dada[7] = (char) (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */
4956 if (max < 8) { dada[8] = NUL; rptflg = 0; return(dada); }
4959 if (rptflg) /* Run length encoding */
4960 dada[8] = (char) rptq; /* If receiving, agree */
4961 else /* by replying with same character. */
4962 dada[8] = (char) (rptq = myrptq); /* When sending use this. */
4963 } else dada[8] = SP; /* Not enabled, put a space here. */
4975 dada[9] = (char) tochar((lscapr ? lscapb : 0) | /* Locking shifts */
4976 (atcapr ? atcapb : 0) | /* Attribute packets */
4977 (lpcapr ? lpcapb : 0) | /* Long packets */
4978 (swcapr ? swcapb : 0) | /* Sliding windows */
4979 (rscapr ? rscapb : 0)); /* RESEND */
4980 if (max < 10) { wslotr = 1; return(dada); }
4981 dada[10] = (char) tochar(swcapr ? wslotr : 1); /* CAPAS+1 = Window size */
4983 if (max < 12) { rpsiz = 80; return(dada); }
4985 rpsiz = urpsiz - 1; /* Long packets ... */
4986 dada[11] = (char) tochar(rpsiz / 95); /* Long packet size, big part */
4987 dada[12] = (char) tochar(rpsiz % 95); /* Long packet size, little part */
4989 if (max < 16) return(dada);
4990 dada[13] = '0'; /* CAPAS+4 = WONT CHKPNT */
4991 dada[14] = '_'; /* CAPAS+5 = CHKINT (reserved) */
4992 dada[15] = '_'; /* CAPAS+6 = CHKINT (reserved) */
4993 dada[16] = '_'; /* CAPAS+7 = CHKINT (reserved) */
4994 if (max < 17) return(dada);
4999 if (server) x |= WMI_SERVE; /* Whether I am a server */
5000 if (binary) x |= WMI_FMODE; /* My file transfer mode is ... */
5001 if (fncnv) x |= WMI_FNAME; /* My filename conversion is ... */
5003 if (streamrq == SET_ON)
5005 else if (streamrq == SET_AUTO && reliable == SET_ON)
5008 Always offer to stream when in remote mode and STREAMING is AUTO
5009 and RELIABLE is not OFF (i.e. is ON or AUTO).
5011 else if (!local && streamrq == SET_AUTO && reliable != SET_OFF)
5013 #endif /* STREAMING */
5015 if (clearrq == SET_ON)
5017 else if (clearrq == SET_AUTO && /* SET CLEAR-CHANNEL AUTO */
5018 ((network && nettype == NET_TCPB /* TCP/IP */
5020 && ttnproto != NP_RLOGIN/* Rlogin is not clear */
5021 && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN)
5022 #endif /* RLOGCODE */
5025 || (network && nettype == NET_SSH)
5026 #endif /* SSHBUILTIN */
5028 || inserver /* We are IKSD */
5032 #endif /* TCPSOCKET */
5034 dada[17] = (char) tochar(x);
5035 #endif /* WHATAMI */
5036 i = 18; /* Position of next field */
5037 p = cksysid; /* WHOAMI (my system ID) */
5039 if (max - i < x + 1) return(dada);
5041 dada[i++] = (char) tochar(x);
5046 if (max < i+1) return(dada);
5047 #ifndef WHATAMI /* WHATAMI2 */
5050 debug(F101,"rpar xfermode","",xfermode);
5051 x = WMI2_FLAG; /* Is-Valid flag */
5052 if (xfermode != XMODE_A) /* If TRANSFER MODE is MANUAL */
5053 x |= WMI2_XMODE; /* set the XFERMODE bit */
5054 if (recursive > 0) /* If this is a recursive transfer */
5055 x |= WMI2_RECU; /* set the RECURSIVE bit */
5056 dada[i++] = tochar(x);
5057 debug(F101,"rpar whatami2","",x);
5058 #endif /* WHATAMI */
5060 dada[i] = '\0'; /* Terminate the init string */
5064 debug(F110,"rpar",dada,0);
5065 rdebu(dada,(int)strlen((char *)dada));
5068 ckstrncpy((char *)myinit,(char *)dada,MYINITLEN);
5069 return(dada); /* Return pointer to string. */
5073 spar(s) CHAR *s; { /* Set parameters */
5074 int x, y, lpsiz, biggest;
5075 extern int rprmlen, lastspmax;
5076 extern struct sysdata sysidlist[];
5083 #endif /* STREAMING */
5086 debug(F101, "spar biggest 1","",biggest);
5087 debug(F101, "spar rprmlen","",rprmlen);
5088 if (rprmlen > 1 && rprmlen < biggest)
5090 debug(F101, "rpar biggest 2","",biggest);
5091 debug(F110,"spar packet",s,0);
5093 s--; /* Line up with field numbers. */
5095 /* Limit on size of outbound packets */
5096 x = (biggest >= 1) ? xunchar(s[1]) : 80;
5097 lpsiz = spsizr; /* Remember what they SET. */
5098 if (spsizf) { /* SET-command override? */
5099 if (x < spsizr) spsiz = x; /* Ignore LEN unless smaller */
5100 } else { /* otherwise */
5101 spsiz = (x < 10) ? 80 : x; /* believe them if reasonable */
5103 spmax = spsiz; /* Remember maximum size */
5105 /* Timeout on inbound packets */
5107 timint = rtimo; /* SET SEND TIMEOUT value overrides */
5108 } else { /* Otherwise use requested value, */
5109 x = (biggest >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */
5110 timint = (x < 0) ? rtimo : x;
5112 timint = chktimo(timint,timef); /* Adjust if necessary */
5114 /* Outbound Padding */
5115 npad = 0; padch = '\0';
5117 npad = xunchar(s[3]);
5118 if (biggest >= 4) padch = (CHAR) ctl(s[4]); else padch = 0;
5122 for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
5125 /* Outbound Packet Terminator */
5126 seol = (CHAR) (biggest >= 5) ? xunchar(s[5]) : CR;
5127 if ((seol < 1) || (seol > 31)) seol = CR;
5129 /* Control prefix that the other Kermit is sending */
5130 x = (biggest >= 6) ? s[6] : '#';
5131 ctlq = (CHAR) (((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#');
5133 /* 8th-bit prefix */
5135 NOTE: Maybe this could be simplified using rcvtyp.
5136 If rcvtyp == 'Y' then we're reading the ACK,
5137 otherwise we're reading the other Kermit's initial bid.
5138 But his horrendous code has been working OK for years, so...
5140 rq = (biggest >= 7) ? s[7] : 0;
5141 if (rq == 'Y') rqf = 1;
5142 else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
5144 debug(F000,"spar 8bq rq","",rq);
5145 debug(F000,"spar 8bq sq","",sq);
5146 debug(F000,"spar 8bq ebq","",ebq);
5147 debug(F101,"spar 8bq rqf","",rqf);
5149 case 0: /* Field is missing from packet. */
5150 ebqflg = 0; /* So no 8th-bit prefixing. */
5152 case 1: /* Other Kermit sent 'Y' = Will Do. */
5154 When I am the file receiver, ebqsent is 0 because I didn't send a
5155 negotiation yet. If my parity is set to anything other than NONE,
5156 either because my user SET PARITY or because I detected parity bits
5157 on this packet, I reply with '&', otherwise 'Y'.
5159 When I am the file sender, ebqsent is what I just sent in rpar(),
5160 which can be 'Y', 'N', or '&'. If I sent '&', then this 'Y' means
5161 the other Kermit agrees to do 8th-bit prefixing.
5163 If I sent 'Y' or 'N', but then detected parity on the ACK packet
5164 that came back, then it's too late: there is no longer any way for
5165 me to tell the other Kermit that I want to do 8th-bit prefixing, so
5166 I must not do it, and in that case, if there is any 8-bit data in
5167 the file to be transferred, the transfer will fail because of block
5170 The following clause covers all of these situations:
5172 if (parity && (ebqsent == 0 || ebqsent == '&')) {
5177 case 2: /* Other Kermit sent a valid prefix */
5178 ebqflg = (ebq == sq || sq == 'Y');
5181 debug(F101,"spar setting parity to space","",ebq);
5182 if (!parity) parity = ttprty = 's';
5185 if (lscapu == 2) { /* But no single-shifts if LOCKING-SHIFT FORCED */
5193 if (s[8] == 'B') x = 4;
5194 else x = s[8] - '0';
5195 if ((x < 1) || (x > 5)) x = 1; /* "5" 20110605 */
5201 rptflg = 0; /* Assume no repeat-counts */
5202 if (biggest >= 9) { /* Is there a repeat-count field? */
5204 t = s[9]; /* Get its contents. */
5206 If I'm sending files, then I'm reading these parameters from an ACK, and so
5207 this character must agree with what I sent.
5209 if (rptena) { /* If enabled ... */
5210 if ((char) rcvtyp == 'Y') { /* Sending files, reading ACK. */
5211 if (t == myrptq) rptflg = 1;
5212 } else { /* I'm receiving files */
5213 if ((t > 32 && t < 63) || (t > 95 && t < 127)) {
5223 atcapu = lpcapu = swcapu = rscapu = 0; /* Assume none of these. */
5224 if (lscapu != 2) lscapu = 0; /* Assume no LS unless forced. */
5225 y = 11; /* Position of next field, if any */
5226 if (biggest >= 10) {
5228 debug(F101,"spar capas","",x);
5229 atcapu = (x & atcapb) && atcapr; /* Attributes */
5230 lpcapu = (x & lpcapb) && lpcapr; /* Long packets */
5231 swcapu = (x & swcapb) && swcapr; /* Sliding windows */
5232 rscapu = (x & rscapb) && rscapr; /* RESEND */
5233 debug(F101,"spar lscapu","",lscapu);
5234 debug(F101,"spar lscapr","",lscapr);
5235 debug(F101,"spar ebqflg","",ebqflg);
5236 if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0;
5237 debug(F101,"spar swcapr","",swcapr);
5238 debug(F101,"spar swcapu","",swcapu);
5239 debug(F101,"spar lscapu","",lscapu);
5240 for (y = 10; (xunchar(s[y]) & 1) && (biggest >= y); y++);
5241 debug(F101,"spar y","",y);
5245 debug(F101,"spar lpcapu","",lpcapu);
5247 if (biggest > y+1) {
5248 x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
5249 debug(F101,"spar lp len","",x);
5250 if (spsizf) { /* If overriding negotiations */
5251 spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
5252 } else { /* otherwise */
5253 spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
5255 if (spsiz < 10) spsiz = 80; /* Be defensive... */
5258 /* (PWP) save current send packet size for optimal packet size calcs */
5259 spmax = spsiz; /* Maximum negotiated length */
5260 lastspmax = spsiz; /* For stats */
5261 if (slostart && spsiz > 499) /* Slow start length */
5263 debug(F101,"spar slow-start spsiz","",spsiz);
5264 debug(F101,"spar lp spmax","",spmax);
5265 timint = chktimo(timint,timef); /* Recalculate the packet timeout */
5267 /* Sliding Windows... */
5269 if (swcapr) { /* Only if requested... */
5270 if (biggest > y) { /* See what other Kermit says */
5271 x = xunchar(s[y+1]);
5272 debug(F101,"spar window","",x);
5273 wslotn = (x > MAXWS) ? MAXWS : x;
5275 wslotn = negotiated size (from other Kermit's S or I packet).
5276 wslotr = requested window size (from this Kermit's SET WINDOW command).
5278 if (wslotn > wslotr) /* Use the smaller of the two */
5280 if (wslotn < 1) /* Watch out for bad negotiation */
5283 swcapu = 1; /* We do windows... */
5284 if (wslotn > maxtry) /* Retry limit must be greater */
5285 maxtry = wslotn + 1; /* than window size. */
5287 debug(F101,"spar window after adjustment","",x);
5288 } else { /* No window size specified. */
5289 wslotn = 1; /* We don't do windows... */
5290 debug(F101,"spar window","",x);
5292 debug(F101,"spar no windows","",wslotn);
5296 /* Now recalculate packet length based on number of windows. */
5297 /* The nogotiated number of window slots will be allocated, */
5298 /* and the maximum packet length will be reduced if necessary, */
5299 /* so that a windowful of packets can fit in the big buffer. */
5301 if (wslotn > 1) { /* Shrink to fit... */
5302 x = adjpkl(spmax,wslotn,bigsbsiz);
5306 if (slostart && spsiz > 499) spsiz = 244; /* Slow start again */
5307 debug(F101,"spar sending, redefine spmax","",spmax);
5311 debug(F101,"spar biggest","",biggest);
5312 if (biggest > y+7) { /* Get WHATAMI info if any */
5313 whatru = xunchar(s[y+8]);
5314 debug(F101,"spar whatru","",whatru);
5316 if (whatru & WMI_FLAG) { /* Only valid if this bit is set */
5318 if (whatru & WMI_STREAM) {
5319 if (streamrq == SET_ON ||
5320 (streamrq == SET_AUTO &&
5321 (reliable == SET_ON || (reliable == SET_AUTO && !local)
5324 #endif /* TN_COMPORT */
5329 streamok = 1; /* Streaming negotiated */
5330 slostart = 0; /* Undo slow-start machinations */
5334 streamed = streamok;
5335 debug(F101,"spar streamok","",streamok);
5336 debug(F101,"spar clearrq","",clearrq);
5337 if (clearrq == SET_ON ||
5338 (clearrq == SET_AUTO &&
5339 ((network && nettype == NET_TCPB
5341 && ttnproto != NP_RLOGIN/* Rlogin is not clear */
5342 && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN)
5343 #endif /* RLOGCODE */
5346 #endif /* TN_COMPORT */
5349 || (network && nettype == NET_SSH)
5350 #endif /* SSHBUILTIN */
5355 urclear = (whatru & WMI_CLEAR);
5356 debug(F101,"spar urclear","",urclear);
5360 #endif /* CK_SPEED */
5362 #endif /* STREAMING */
5364 #endif /* WHATAMI */
5366 if (biggest > y+8) { /* Get WHOAREYOU info if any */
5368 x = xunchar(s[y+9]); /* Length of it */
5371 debug(F101,"spar sysindex x","",x);
5372 debug(F101,"spar sysindex y","",y);
5373 debug(F101,"spar sysindex biggest","",biggest);
5375 if (x > 0 && x < 16 && biggest >= y) {
5376 strncpy(whoareu,(char *)s+z+10,x); /* Other Kermit's system ID */
5377 debug(F111,"spar whoareyou",whoareu,whoareu[0]);
5378 if (whoareu[0]) { /* Got one? */
5379 sysindex = getsysix((char *)whoareu);
5380 debug(F101,"spar sysindex",whoareu,sysindex);
5387 y++; /* Advance pointer */
5389 whatru2 = xunchar(s[y]); /* Next field is WHATAMI2 */
5390 debug(F101,"spar whatru2","",whatru2);
5391 if (whatru2 & WMI2_FLAG) { /* Valid only if this bit is set */
5392 if (server) { /* Server obeys client's xfer mode */
5393 xfermode = (whatru2 & WMI2_XMODE) ? XMODE_M : XMODE_A;
5394 debug(F101,"spar whatru2 xfermode","",xfermode);
5396 if (whatru2 & WMI2_RECU) { /* RECURSIVE transfer */
5397 if (fnrpath == PATH_AUTO) { /* If REC PATH AUTO */
5398 fnrpath = PATH_REL; /* Set it to RELATIVE */
5399 autopath = 1; /* and remember we did this */
5404 #endif /* WHATAMI */
5407 if (sysindex > -1) {
5409 p = sysidlist[sysindex].sid_name;
5410 tlog(F110,"Remote system type: ",p,0L);
5411 if (sysindex > 0) { /* If partnet's system type known */
5412 whoarewe(); /* see if we are a match. */
5414 /* Never unprefix XON and XOFF when sending to VMS */
5415 debug(F111,"proto whoareu",whoareu,sysindex);
5416 if (!strcmp((char *)whoareu,"D7")) {
5417 debug(F111,"proto special VMS prefixing","",0);
5418 ctlp[XON] = ctlp[XOFF] = 1;
5419 ctlp[XON+128] = ctlp[XOFF+128] = 1;
5420 ctlp[3] = 1; /* Ctrl-C might be dangerous too */
5421 ctlp[14] = ctlp[15] = 1; /* And SO/SI */
5422 ctlp[24] = ctlp[25] = 1; /* And ^X/^Y */
5423 ctlp[141] = 1; /* And CR+128 */
5425 #endif /* CK_SPEED */
5429 /* Record parameters in debug log */
5431 if (deblog) sdebu(biggest);
5433 numerrs = 0; /* Start counting errors here. */
5437 /* G N F I L E -- Get name of next file to send */
5439 Expects global sndsrc to be:
5440 -9: if we are generating a file internally for calibration.
5441 -1: next filename to be obtained by calling znext().
5442 0: no next file name
5443 1: (or greater) next filename to be obtained from **cmlist,
5444 or if addlist != 0, from the "filehead" linked list,
5445 or if filefile pointer not null from that file (which is already open).
5447 1, with name of next file in filnam.
5448 0, no more files, with filnam set to empty string.
5450 -2, file is not readable (but then we just skip to the next one if any)
5451 -3, read access denied
5453 -5, too many files match wildcard
5454 -6, no files selected
5456 If gnfile() returns 0, then the global variable gnferror should be checked
5457 to find out the most recent gnfile() error, and use that instead of the
5458 return code (for reasons to hard to explain).
5463 CK_OFF_T filesize = 0;
5467 char fullname[CKMAXPATH+1];
5469 dodirstoo = ((what & (W_FTP|W_SEND)) == (W_FTP|W_SEND)) && recursive;
5471 debug(F101,"gnfile sndsrc","",sndsrc);
5472 debug(F101,"gnfile filcnt","",filcnt);
5473 debug(F101,"gnfile what","",what);
5474 debug(F101,"gnfile recursive","",recursive);
5475 debug(F101,"gnfile dodirstoo","",dodirstoo);
5477 fsize = (CK_OFF_T)-1; /* Initialize file size */
5482 In VMS, zopeni() sets binary 0/1 automatically from the file
5483 attributes. Don't undo it here.
5485 debug(F101,"gnfile VMS binary","",binary);
5487 if (!(what & W_REMO) && (xfermode == XMODE_A)
5490 #endif /* NOMSEND */
5493 if (!stdinf) /* Not if sending from stdin */
5495 /* We don't do this in server mode because it undoes WHATAMI */
5496 if (!server || (server && ((whatru & WMI_FLAG) == 0)))
5497 #endif /* WHATAMI */
5498 binary = gnf_binary; /* Restore prevailing transfer mode */
5499 debug(F101,"gnfile binary = gnf_binary","",gnf_binary);
5504 debug(F101,"gnfile pipesend","",pipesend);
5505 if (pipesend) { /* First one */
5507 ckstrncpy(filnam,cmarg,CKMAXPATH+1);
5509 } else { /* There's only one... */
5515 #endif /* PIPESEND */
5519 debug(F100,"gnfile calibrate","",0);
5520 ckstrncpy(filnam,"CALIBRATION",CKMAXPATH);
5524 sndsrc = 0; /* For next time */
5528 #endif /* CALIBRATE */
5531 if (sndarray) { /* Sending from an array */
5532 extern char sndxnam[]; /* Pseudo filename */
5533 debug(F100,"gnfile array","",0);
5535 fsize = (CK_OFF_T)-1; /* Size unknown */
5537 ckstrncpy(filnam,sndxnam,CKMAXPATH);
5542 if (sndsrc == 0) { /* It's not really a file */
5543 if (nfils > 0) { /* It's a pipe, or stdin */
5544 ckstrncpy(filnam,*cmlist,CKMAXPATH+1); /* Copy its "name" */
5545 nfils = 0; /* There is no next file */
5546 return(1); /* OK this time */
5547 } else return(0); /* but not next time */
5550 /* If file group interruption (C-Z) occurred, fail. */
5553 tlog(F100,"Transaction cancelled","",0L);
5554 debug(F100,"gnfile czseen","",0);
5558 /* Loop through file list till we find a readable, sendable file */
5560 filesize = (CK_OFF_T)-1; /* Loop exit (file size) variable */
5561 while (filesize < 0) { /* Keep trying till we get one... */
5563 if (sndsrc > 0) { /* File list in cmlist or file */
5564 if (filefile) { /* Reading list from file... */
5565 if (zsinl(ZMFILE,filnam,CKMAXPATH) < 0) { /* Read a line */
5566 zclose(ZMFILE); /* Failed */
5567 debug(F110,"gnfile filefile EOF",filefile,0);
5568 makestr(&filefile,NULL);
5571 debug(F110,"gnfile filefile filnam",filnam,0);
5573 debug(F101,"gnfile nfils","",nfils);
5574 if (nfils-- > 0 || filefile) { /* Still some left? */
5577 if (filenext && filenext->fl_name) {
5578 ckstrncpy(filnam,filenext->fl_name,CKMAXPATH+1);
5580 filenext->fl_alias ?
5581 filenext->fl_alias :
5583 binary = filenext->fl_mode;
5585 printf("?Internal error expanding ADD list\n");
5588 filenext = filenext->fl_next;
5589 debug(F111,"gnfile addlist filnam",filnam,nfils);
5590 } else if (sndsrc > 0 && !filefile) {
5591 #endif /* NOMSEND */
5592 ckstrncpy(filnam,*cmlist++,CKMAXPATH+1);
5593 debug(F111,"gnfile cmlist filnam",filnam,nfils);
5596 #endif /* NOMSEND */
5599 debug(F101,"gnfile ngetpath","",ngetpath);
5600 #endif /* NOSERVER */
5604 if (server && !isabsolute(filnam) && (ngetpath > i)) {
5605 ckstrncpy(fullname,getpath[i],CKMAXPATH+1);
5606 ckstrncat(fullname,filnam,CKMAXPATH);
5607 debug(F111,"gnfile getpath",fullname,i);
5614 #endif /* NOSERVER */
5615 ckstrncpy(fullname,filnam,CKMAXPATH+1);
5616 debug(F110,"gnfile absolute",fullname,0);
5619 #endif /* NOSERVER */
5620 if (iswild(fullname)
5622 || recursive > 0 || !strcmp(fullname,".")
5623 #endif /* RECURSIVE */
5624 ) { /* It looks wild... */
5625 /* First check if a file with this name exists */
5626 debug(F110,"gnfile wild",fullname,0);
5627 if (zchki(fullname) >= 0) {
5629 Here we have a file whose name actually
5630 contains wildcard characters.
5635 nzxopts = ZX_FILONLY; /* (was 0: 25 Jul 2001 fdc) */
5637 nzxopts = recursive ? 0 : ZX_FILONLY; /* 30 Jul 2001 */
5638 #endif /* COMMENT */
5639 if (nolinks) nzxopts |= ZX_NOLINKS; /* (26 Jul 2001 fdc) */
5641 if (matchdot) nzxopts |= ZX_MATCHDOT;
5642 #endif /* UNIXOROSK */
5643 if (recursive) nzxopts |= ZX_RECURSE;
5644 x = nzxpand(fullname,nzxopts); /* Expand wildcards */
5645 debug(F101,"gnfile nzxpand","",x);
5648 xx = znext(fullname);
5649 debug(F111,"gnfile znext A",fullname,xx);
5652 if (x == 0) { /* None match */
5654 if (server && ngetpath > i)
5656 #endif /* NOSERVER */
5658 debug(F101,"gnfile gnferror A","",gnferror);
5662 if (x < 0) { /* Too many to expand */
5663 debug(F101,"gnfile gnferror B","",gnferror);
5667 sndsrc = -1; /* Change send-source to znext() */
5669 } else { /* We're out of files. */
5670 debug(F111,"gnfile done",ckitoa(gnferror),nfils);
5676 /* Otherwise, step to next element of internal wildcard expansion list. */
5681 debug(F111,"gnfile znext X",filnam,xx);
5683 debug(F111,"gnfile znext B",filnam,xx);
5687 debug(F111,"gnfile FTP MPUT /RECURSIVE",filnam,xx);
5693 debug(F111,"gnfile znext C",filnam,x);
5694 if (!filnam[0]) { /* If no more, */
5695 sndsrc = 1; /* go back to previous list */
5696 debug(F101,"gnfile setting sndsrc back","",sndsrc);
5699 ckstrncpy(fullname,filnam,CKMAXPATH+1);
5702 /* Get here with a filename. */
5705 debug(F110,"gnfile fullname",fullname,0);
5709 if (fullname[0] == '~') {
5710 dirp = tilde_expand((char *)fullname);
5711 if (*dirp) ckstrncpy(fullname,dirp,CKMAXPATH+1);
5714 filesize = zchki(fullname); /* Check if file readable */
5715 debug(F111,"gnfile zchki",fullname,filesize);
5716 retcode = filesize; /* Possible return code */
5717 if (filesize == (CK_OFF_T)-2 && dodirstoo) {
5721 gnferror = (int)filesize;
5722 debug(F101,"gnfile gnferror C","",gnferror);
5724 if (filesize == (CK_OFF_T)-1) { /* If not found */
5725 debug(F100,"gnfile -1","",0);
5727 if (server && ngetpath > i)
5729 #endif /* NOSERVER */
5730 debug(F110,"gnfile skipping:",fullname,0);
5731 tlog(F110,fullname,": open failure - skipped",0);
5732 xxscreen(SCR_FN,0,0l,fullname);
5733 xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname);
5735 if (tralog && !tlogfmt)
5736 doxlog(what,fullname,fsize,binary,1,"Skipped");
5739 } else if (filesize < 0) {
5740 if (filesize == (CK_OFF_T)-3) { /* Exists but not readable */
5741 debug(F100,"gnfile -3","",0);
5742 filrej++; /* Count this one as not sent */
5743 tlog(F110,"Read access denied",fullname,0); /* Log this */
5744 xxscreen(SCR_FN,0,0l,fullname);
5745 xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname); /* Display it */
5747 if (tralog && !tlogfmt)
5748 doxlog(what,fullname,fsize,binary,1,"Skipped");
5756 debug(F111,"gnfile sndsmaller",ckfstoa(sndsmaller),sndsmaller);
5757 debug(F111,"gnfile sndlarger",ckfstoa(sndlarger),sndlarger);
5758 debug(F111,"gnfile (CK_OFF_T)-1",ckfstoa((CK_OFF_T)-1),(CK_OFF_T)-1);
5760 xx = fileselect(fullname,
5761 sndafter, sndbefore,
5762 sndnafter,sndnbefore,
5763 sndsmaller,sndlarger,
5765 NSNDEXCEPT,sndexcept);
5766 debug(F111,"gnfile fileselect",fullname,xx);
5768 filesize = (CK_OFF_T)-1;
5770 debug(F101,"gnfile gnferror D","",gnferror);
5773 ckstrncpy(filnam,fullname,CKMAXPATH+1);
5777 /* This can't be right! */
5778 } else { /* sndsrc is 0... */
5779 if (!fileselect(fullname,
5780 sndafter, sndbefore,
5781 sndnafter,sndnbefore,
5782 sndsmaller,sndlarger,
5784 NSNDEXCEPT,sndexcept)) {
5786 debug(F111,"gnfile fileselect",fullname,gnferror);
5787 filesize = (CK_OFF_T)-1;
5790 ckstrncpy(filnam,fullname,CKMAXPATH+1);
5792 #endif /* COMMENT */
5795 debug(F101,"gnfile result","",retcode);
5801 The following bunch of routines feed internally generated data to the server
5802 to send to the client in response to REMOTE commands like DIRECTORY, DELETE,
5803 and so on. We have to write these lines in the format appropriate to our
5804 platform, so they can be converted to generic (CRLF) text format by the
5808 char * endline = "\12";
5811 char * endline = "\12";
5814 char * endline = "\15";
5817 char * endline = "\15";
5819 char * endline = "\15\12";
5822 #endif /* datageneral */
5829 #define FNCBUFL (CKMAXPATH + CKMAXPATH + 64)
5831 #define FNCBUFL (CKMAXPATH + 64)
5832 #endif /* CKSYMLINK */
5835 /* NB: The minimum FNCBUFL is 255 */
5837 static CHAR funcbuf[FNCBUFL];
5838 static int funcnxt = 0;
5839 static int funclen = 0;
5840 static int nxpnd = -1;
5841 static long ndirs = 0;
5842 static long nfiles = 0;
5843 static CK_OFF_T nbytes = 0;
5846 sndstring(p) char * p; {
5848 nfils = 0; /* No files, no lists. */
5849 xflg = 1; /* Flag we must send X packet. */
5850 ckstrncpy(cmdstr,versio,CMDSTRL); /* Data for X packet. */
5851 first = 1; /* Init getchx lookahead */
5852 memstr = 1; /* Just set the flag. */
5853 memptr = p; /* And the pointer. */
5854 binary = XYFT_T; /* Text mode for this. */
5858 #endif /* NOSERVER */
5861 /* S N D H L P -- Routine to send builtin help */
5863 static int srvhlpnum = 0;
5866 static char *nmx[] = { "Disabled", "Disabled", "Enabled", "Enabled" };
5883 #endif /* CK_ANSIC */
5887 en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai,
5888 en_pri, en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who,
5889 /* en_ret, */ en_mkd, en_rmd, en_asg, en_que, en_xit, x_login, x_logged,
5891 extern char * ckxsys;
5893 if (funcnxt < funclen)
5894 return (funcbuf[funcnxt++]);
5896 switch (srvhlpnum++) {
5898 x = ckstrncpy((char *)funcbuf,
5899 "Client Command Status Description\n",
5902 if (x_login && !x_logged) {
5903 x += ckstrncat((char *)funcbuf,
5904 " REMOTE LOGIN required\n",
5908 if (FNCBUFL - x > 74)
5909 sprintf((char *)(funcbuf+x)," GET %-14s%s\n",
5911 "Transfer file(s) from server to client."
5915 /* NOTE: The minimum funcbuf[] size is 255; all of the following are safe. */
5918 sprintf((char *)funcbuf," SEND %-14s%s\n",
5920 "Transfer file(s) from client to server."
5925 sprintf((char *)funcbuf," MAIL %-14s%s\n",
5926 xnm(inserver ? 0 : en_mai),
5927 "Send file(s) as e-mail."
5933 sprintf((char *)funcbuf," REMOTE ASSIGN %-14s%s\n",
5935 "Assign value to server variable or macro."
5938 sprintf((char *)funcbuf," REMOTE ASSIGN not configured\n");
5943 sprintf((char *)funcbuf," REMOTE CD %-14s%s\n",
5945 "Change server's directory."
5951 sprintf((char *)funcbuf," REMOTE COPY %-14s%s\n",
5953 "Copy a file on the server."
5956 sprintf((char *)funcbuf," REMOTE COPY not configured\n");
5961 sprintf((char *)funcbuf," REMOTE DELETE %-14s%s\n",
5963 "Delete a file on the server."
5968 sprintf((char *)funcbuf," REMOTE DIRECTORY %-14s%s\n",
5970 "List files on the server."
5975 sprintf((char *)funcbuf," REMOTE EXIT %-14s%s\n",
5977 "Exit from Kermit server program."
5982 sprintf((char *)funcbuf," REMOTE HOST %-14s%s\n",
5983 xnm(inserver ? 0 : en_hos),
5985 "Execute a CLI command on the server."
5988 "Execute a DCL command on the server."
5990 "Execute a shell command on the server."
5992 #endif /* datageneral */
5997 sprintf((char *)funcbuf," REMOTE PRINT %-14s%s\n",
5998 xnm(inserver ? 0 : en_pri),
5999 "Send a file to the server for printing."
6005 sprintf((char *)funcbuf," REMOTE QUERY %-14s%s\n",
6007 "Get value of server variable or macro."
6011 sprintf((char *)funcbuf," REMOTE QUERY not configured\n");
6016 sprintf((char *)funcbuf," REMOTE MKDIR %-14s%s\n",
6018 "Create a directory on the server."
6023 sprintf((char *)funcbuf," REMOTE RMDIR %-14s%s\n",
6025 "Remove a directory on the server."
6030 sprintf((char *)funcbuf," REMOTE RENAME %-14s%s\n",
6032 "Rename a file on the server."
6037 sprintf((char *)funcbuf," REMOTE SET %-14s%s\n",
6039 "Set a parameter on the server"
6044 sprintf((char *)funcbuf," REMOTE SPACE %-14s%s\n",
6046 "Inquire about disk space on the server."
6051 sprintf((char *)funcbuf," REMOTE TYPE %-14s%s\n",
6053 "Display a server file on your screen."
6058 sprintf((char *)funcbuf," REMOTE WHO %-14s%s\n",
6059 xnm(inserver ? 0 : en_who),
6060 "List who is logged in to the server."
6065 sprintf((char *)funcbuf," FINISH %-14s%s\n",
6068 "Exit from Kermit server program." :
6069 "Return the server to its command prompt."
6074 sprintf((char *)funcbuf," BYE %-14s%s\n\n",
6076 "Log the server out and disconnect."
6084 funclen = strlen((char *)funcbuf);
6085 return(funcbuf[funcnxt++]);
6091 extern char * ckxsys;
6093 first = 1; /* Init getchx lookahead */
6094 nfils = 0; /* No files, no lists. */
6095 xflg = 1; /* Flag we must send X packet. */
6096 ckstrncpy(cmdstr,"REMOTE HELP",CMDSTRL); /* Data for X packet. */
6097 sprintf((char *)funcbuf, "C-Kermit %s,%s\n\n", versio, ckxsys);
6098 funclen = strlen((char *)funcbuf);
6101 sprintf((char *)(funcbuf+funclen),
6102 "Internet Kermit Service (EXPERIMENTAL)\n\n");
6103 funclen = strlen((char *)funcbuf);
6110 binary = XYFT_T; /* Text mode for this. */
6114 #endif /* NOSERVER */
6118 Returns the next available character,
6125 #endif /* CK_ANSIC */
6128 if (zchin(ZIFILE,&c) < 0) {
6132 return((unsigned)c);
6136 /* S N D T Y P -- TYPE a file to remote client */
6139 sndtype(file) char * file; {
6141 char name[CKMAXPATH+1];
6147 ckstrncpy(name, file, CKMAXPATH+1);
6148 /* change / to \. */
6150 while (*p) { /* Change them back to \ */
6151 if (*p == '/') *p = '\\';
6157 ckstrncpy(name, file, CKMAXPATH+1);
6161 funclen = strlen((char *)funcbuf);
6162 if (zchki(name) == -2) {
6163 /* Found a directory */
6166 if (!zopeni(ZIFILE,name))
6169 nfils = 0; /* No files, no lists. */
6170 xflg = 1; /* Flag we must send X packet. */
6171 ckstrncpy(cmdstr,"type",CMDSTRL); /* Data for X packet. */
6172 first = 1; /* Init getchx lookahead */
6173 funcstr = 1; /* Just set the flag. */
6174 funcptr = nxttype; /* And the pointer. */
6175 binary = XYFT_T; /* Text mode for this */
6179 #endif /* NOSERVER */
6183 N X T D I R -- Provide data for senddir()
6185 Returns the next available character or -1 if no more data.
6188 /* Directory listing parameters set by the user interface, if any. */
6189 extern int dir_head, dir_dots, dir_back;
6191 static int sd_hdg, sd_bkp, sd_dot; /* Local listing parameters */
6197 #endif /* CK_ANSIC */
6199 char name[CKMAXPATH+1], dbuf[24], *p = NULL;
6200 char *dstr = NULL, * lnk = "";
6201 CHAR c, * linebuf = funcbuf;
6203 /* Work around bugs in OSK compiler */
6204 char *dirtag = "directories";
6205 char *filetag = "files";
6206 char *bytetag = "bytes";
6209 int x, itsadir = 0, gotone = 0;
6213 debug(F101,"nxtdir funcnxt","",funcnxt);
6214 debug(F101,"nxtdir funclen","",funclen);
6215 debug(F110,"nxtdir funcbuf",funcbuf+funcnxt,0);
6218 if (funcnxt < funclen) { /* Return next character from buffer */
6219 c = funcbuf[funcnxt++];
6220 debug(F000,"nxtdir return 1","",(unsigned)(c & 0xff));
6221 return((unsigned)(c & 0xff));
6223 while (nxpnd > 0) { /* Buffer needs refill */
6225 znext(name); /* Get next filename */
6226 if (!name[0]) { /* None left - done */
6230 if (sd_bkp) { /* Showing backup files? */
6231 gotone = 1; /* Yes, no need to check. */
6234 x = ckmatch( /* No - see if this is one */
6236 "*.~[0-9]*~" /* Not perfect but close enough. */
6238 "*.~*~" /* Less close. */
6239 #endif /* CKREGEX */
6241 debug(F111,"nxtdir ckmatch",name,x);
6243 continue; /* It's a backup file - skip it */
6245 gotone = 1; /* It's not, break from loop. */
6250 len = zgetfs(name); /* Get file size */
6251 debug(F111,"nxtdir zgetfs",name,len);
6253 itsadir = zgfs_dir; /* See if it's a directory */
6255 itsadir = (len == -2 || isdir(name));
6256 #endif /* VMSORUNIX */
6257 dstr = zfcdat(name);
6258 debug(F111,"nxtdir zcfdat",dstr,0);
6260 dstr = "0000-00-00 00:00:00";
6262 dstr = "0000-00-00 00:00:00";
6274 strcpy(dbuf+10,dstr+8);
6279 p = ziperm(name); /* Get permissions */
6282 #endif /* VMSORUNIX */
6285 #endif /* CK_PERMS */
6286 debug(F110,"domydir perms",p,0);
6289 /* Make name relative */
6290 ckstrncpy(name,zrelname(name,zgtdir()),CKMAXPATH+1);
6303 extern char linkname[];
6306 debug(F111,"nxtdir linkname",lnk,zgfs_link);
6307 #endif /* CKSYMLINK */
6311 The following sprintf's are safe; linebuf is a pointer to funcbuf,
6312 which is 64 bytes larger than CKMAXPATH (or double CKMAXPATH when
6313 symlinks are possible). 64 allows for the fixed-field portions of
6314 the file listing line: permissions, size, and date. CKMAXPATH allows
6315 for the longest possible pathname.
6317 if (itsadir && len < 0) { /* Directory */
6319 sprintf((char *)linebuf,
6320 "%-22s%-10s %s %s\n",p,"<DIR>",dstr,name);
6323 sprintf((char *)linebuf,
6324 "%10s%-10s %s %s\n",p,"<DIR>",dstr,name);
6326 sprintf((char *)linebuf,
6327 "%-10s %s %s\n", "<DIR>", dstr, name);
6329 } else { /* Regular file */
6331 sprintf((char *)linebuf,
6332 "%-22s%10s %s %s\n", p, ckfstoa(len), dstr, name);
6335 sprintf((char *)linebuf,
6336 "%10s%10s %s %s%s%s\n",
6337 p, ckfstoa(len), dstr, name,
6342 sprintf((char *)linebuf,
6344 ckfstoa(len), dstr, name,
6351 funclen = strlen((char *)funcbuf);
6352 } else if (sd_hdg && nxpnd == 0) { /* Done, send summary */
6353 char *blankline = ""; /* At beginning of summary */
6355 The idea is to prevent (a) unnecessary multiple blanklines, and (b)
6356 prompt-stomping. Preventing (b) is practically impossible, because it
6357 depends on the client so for now always include that final CRLF.
6359 if (!ndirs || !nbytes || !nfiles)
6360 blankline = endline;
6362 /* Workaround bugs in OS-9 compiler... */
6364 dirtag = "directory";
6367 if (nbytes == (CK_OFF_T)1)
6369 sprintf((char *)funcbuf,
6370 "%sSummary: %ld %s, %ld %s, %s %s%s",
6380 sprintf((char *)funcbuf,
6381 "%sSummary: %ld director%s, %ld file%s, %s byte%s%s",
6384 (ndirs == 1) ? "y" : "ies",
6386 (nfiles == 1) ? "" : "s",
6388 (nbytes == (CK_OFF_T)1) ? "" : "s",
6394 funclen = strlen((char *)funcbuf);
6400 debug(F101,"nxtdir funclen","",funclen);
6402 if (funcnxt < funclen) { /* If we have data to send... */
6403 c = funcbuf[funcnxt++];
6404 debug(F000,"nxtdir return 2","",(unsigned)(c & 0xff));
6405 return((unsigned)(c & 0xff));
6407 return(-1); /* Nothing left, done. */
6410 /* S N D D I R -- send directory listing */
6413 snddir(spec) char * spec; {
6415 char * p = NULL, name[CKMAXPATH+1];
6417 char fnbuf[CKMAXPATH+1];
6419 debug(F111,"snddir matchdot",spec,matchdot);
6422 debug(F111,"snddir dir_dots",spec,dir_dots);
6423 sd_hdg = dir_head > 0; /* Import listing parameters if any */
6424 sd_bkp = dir_back > 0;
6430 sd_hdg = 1; /* Or use hardwired defaults */
6435 if (!spec) spec = "";
6436 debug(F111,"snddir sd_dot",spec,sd_dot);
6439 zfnqfp(spec,CKMAXPATH,name);
6440 debug(F110,"snddir zfnqfp",name,0);
6442 ckstrncpy(name,spec,CKMAXPATH+1);
6443 debug(F110,"snddir name",name,0);
6444 #endif /* COMMENT */
6450 strcpy(name, "./*");
6453 strcpy(name, "*.*");
6458 debug(F101,"snddir quit (no filespec)","",0);
6460 #endif /* datageneral */
6465 debug(F110,"snddir name 1",name,0);
6468 nbytes = (CK_OFF_T)0;
6470 if (zfnqfp(name,CKMAXPATH,fnbuf))
6472 debug(F110,"snddir name 2",name,0);
6473 p = name + strlen(name); /* Move it to end of list */
6475 /* sprintf safe because funcbuf size >= max path len + 64 */
6478 sprintf((char *)funcbuf,"Listing files: %s%s%s",fnbuf,endline,endline);
6480 funclen = strlen((char *)funcbuf);
6485 if (zchki(name) == -2) { /* Found a directory */
6487 if (*p == '\\' || *p == '/')
6488 ckstrncat(name, "*", CKMAXPATH);
6490 ckstrncat(name, ".", CKMAXPATH);
6492 ckstrncat(name, "\\*", CKMAXPATH);
6493 debug(F110,"snddir directory",name,0);
6496 if (!iswild(name) && isdir(name)) {
6500 if (*p == '/') /* So append wildcard to it */
6501 ckstrncat(s, "*", CKMAXPATH);
6503 ckstrncat(s, "/*", CKMAXPATH);
6506 if (*p == ']' || *p == '>' || *p == ':')
6507 ckstrncat(s, "*.*", CKMAXPATH);
6511 ckstrncat(s, "+", CKMAXPATH);
6513 ckstrncat(s, ":+", CKMAXPATH);
6517 ckstrncat(s, "*", CKMAXPATH);
6519 ckstrncat(s, ">*", CKMAXPATH);
6521 #endif /* datageneral */
6523 #endif /* UNIXOROSK */
6524 debug(F110,"snddir directory",name,0);
6531 extern char ** mtchs;
6532 debug(F111,"snddir sd_dot",spec,sd_dot);
6534 nzxopts |= ZX_MATCHDOT;
6536 nzxopts |= ZX_RECURSE;
6537 debug(F111,"snddir nzxopts",spec,nzxopts);
6538 nxpnd = nzxpand(name,nzxopts); /* Get the array of names */
6539 sh_sort(mtchs,NULL,nxpnd,0,0,1); /* Sort the array */
6542 if (recursive) nzxopts |= ZX_RECURSE;
6543 nxpnd = nzxpand(name,nzxopts);
6546 debug(F101,"snddir nzxpand nxpnd","",nxpnd);
6549 nfils = 0; /* No files, no lists. */
6550 xflg = 1; /* Flag we must send X packet. */
6551 if ((int)strlen(name) < CMDSTRL - 11) /* Data for X packet. */
6552 sprintf(cmdstr,"DIRECTORY %s",name); /* safe */
6554 ckstrncpy(cmdstr,"DIRECTORY",CMDSTRL);
6555 first = 1; /* Init getchx lookahead */
6556 funcstr = 1; /* Just set the flag. */
6557 funcptr = nxtdir; /* And the pointer. */
6558 binary = XYFT_T; /* Text mode for this */
6559 rc = sinit(); /* 26 Aug 2005 */
6560 debug(F111,"snddir","sinit()",rc);
6564 #endif /* NOSERVER */
6567 /* N X T D E L -- provide data for delete */
6569 /* Returns the next available character or -1 if no more data */
6575 #endif /* CK_ANSIC */
6577 char name[257], *p = NULL;
6580 if (funcnxt < funclen)
6581 return ((unsigned)funcbuf[funcnxt++]);
6592 /* Find just the name of the file */
6594 for (p = name + strlen(name); p != name && *p != '/' ; p--) ;
6597 /* sprintf's safe because size of funcbuf >= 64 + maxpathlen */
6601 sprintf((char *)funcbuf," %10s: %s%s","skipping",p,endline);
6605 sprintf((char *)funcbuf," %10s: %s%s","deleted",p,endline);
6608 sprintf((char *)funcbuf," directory: %s%s", p, endline);
6610 funclen = strlen((char *)funcbuf);
6613 /* If done processing the expanded entries send a summary statement */
6616 sprintf((char *)funcbuf,
6617 "%s%ld file%s deleted, %s byte%s freed%s",
6620 (nfiles == 1) ? "" : "s",
6622 (nbytes == (CK_OFF_T)1) ? "" : "s",
6627 funclen = strlen((char *)funcbuf);
6634 /* If we have data to send */
6636 if (funcnxt < funclen)
6637 return ((unsigned)funcbuf[funcnxt++]); /* Return a character */
6639 return(-1); /* No more input */
6642 /* S N D D E L -- Send delete message */
6645 snddel(spec) char * spec; {
6647 char name[CKMAXPATH+1];
6650 #endif /* #ifdef OS2 */
6655 ckstrncpy(name, spec, CKMAXPATH+1);
6658 /* change / to \. */
6660 while (*p) { /* Change them back to \ */
6661 if (*p == '/') *p = '\\';
6667 nbytes = (CK_OFF_T)0;
6668 sprintf((char *)funcbuf,"Deleting \"%s\"%s",name,endline);
6670 funclen = strlen((char *)funcbuf);
6672 nzxopts = ZX_FILONLY; /* Files only */
6674 if (matchdot) nzxopts |= ZX_MATCHDOT;
6675 #endif /* UNIXOROSK */
6677 /* Recursive deleting not supported yet */
6678 if (recursive) nzxopts |= ZX_RECURSE;
6679 #endif /* COMMENT */
6680 nxpnd = nzxpand(name,nzxopts);
6683 nfils = 0; /* No files, no lists. */
6684 xflg = 1; /* Flag we must send X packet. */
6685 ckstrncpy(cmdstr,"REMOTE DELETE",CMDSTRL); /* Data for X packet. */
6686 first = 1; /* Init getchx lookahead */
6687 funcstr = 1; /* Just set the flag. */
6688 funcptr = nxtdel; /* And the pointer. */
6689 binary = XYFT_T; /* Use text mode for this, */
6693 #endif /* NOSERVER */
6697 /* S N D S P A C E -- send disk space message */
6699 sndspace(drive) int drive; {
6701 static char spctext[64];
6702 unsigned long space;
6705 space = zdskspace(drive - 'A' + 1);
6706 if (space > 0 && space < 1024)
6708 " Drive %c: unknown%s",
6714 " Drive %c: %ldK free%s",
6720 space = zdskspace(0);
6721 if (space > 0 && space < 1024)
6722 sprintf(spctext, " Free space: unknown%s", endline);
6724 sprintf(spctext, " Free space: %ldK%s", space / 1024L, endline);
6726 nfils = 0; /* No files, no lists. */
6727 xflg = 1; /* Flag we must send X packet. */
6728 ckstrncpy(cmdstr,"free space",CMDSTRL); /* Data for X packet. */
6729 first = 1; /* Init getchx lookahead */
6730 memstr = 1; /* Just set the flag. */
6731 memptr = spctext; /* And the pointer. */
6732 binary = XYFT_T; /* Text mode for this. */
6736 #endif /* NOSERVER */
6739 /* S N D W H O -- send who message */
6741 sndwho(who) char * who; {
6743 nfils = 0; /* No files, no lists. */
6744 xflg = 1; /* Flag we must send X packet. */
6745 ckstrncpy(cmdstr,"who",CMDSTRL); /* Data for X packet. */
6746 first = 1; /* Init getchx lookahead */
6747 memstr = 1; /* Just set the flag. */
6749 memptr = "\15\12K95 SERVER\15\12"; /* And the pointer. */
6751 memptr = "\15\12K/2 SERVER\15\12";
6753 binary = XYFT_T; /* Use text mode */
6757 #endif /* NOSERVER */
6761 /* C W D -- Change server's working directory */
6764 String passed has first byte as length of directory name, rest of string
6767 1 on success after sending short-form response (ACK with name).
6768 2 on success if a CD Message file is to be sent.
6771 cwd(vdir) char *vdir; {
6774 vdir[xunchar(*vdir) + 1] = '\0'; /* Terminate string with a null */
6776 tlog(F110,"Directory requested: ",dirp,0L);
6777 if (zchdir(dirp)) { /* Try to change */
6778 cdd = zgtdir(); /* Get new working directory. */
6779 debug(F110,"cwd",cdd,0);
6780 if (srvcdmsg) { /* Send orientation file? */
6782 for (i = 0; i < 8; i++) {
6783 if (zchki(cdmsgfile[i]) > -1) {
6784 xxscreen(SCR_CD,0,0l,cdd);
6785 tlog(F110,"Changed directory to",cdd,0L);
6790 encstr((CHAR *)cdd); /* Send short-form reply */
6791 ack1(data); /* containing directory name. */
6792 xxscreen(SCR_CD,0,0l,cdd);
6793 tlog(F110,"Changed directory to",cdd,0L);
6796 debug(F110,"cwd failed",dirp,0);
6797 tlog(F110,"Failed to change directory to",dirp,0L);
6803 /* S Y S C M D -- Do a system command */
6805 /* Command string is formed by concatenating the two arguments. */
6808 syscmd(prefix,suffix) char *prefix, *suffix; {
6809 extern int i_isopen;
6818 for (cp = cmdstr; *prefix != '\0'; (*cp++ = *prefix++));
6819 while ((*cp++ = *suffix++))
6821 /* This takes away more than we gain in convenience
6822 if (*(cp-1) == '/') *(cp-1) = '\\' */
6826 debug(F110,"syscmd",cmdstr,0);
6828 if (zxcmd(ZIFILE,cmdstr) > 0) {
6829 debug(F110,"syscmd zxcmd ok",cmdstr,0);
6830 nfils = sndsrc = 0; /* Flag that input is from stdin */
6831 xflg = hcflg = 1; /* And special flags for pipe */
6832 binary = XYFT_T; /* Go to text mode */
6834 return (sinit()); /* Send S packet */
6836 debug(F100,"syscmd zxcmd failed",cmdstr,0);
6841 debug(F100,"syscmd zxcmd NOPUSH",cmdstr,0);
6847 /* R E M S E T -- Remote Set */
6848 /* Called by server to set variables as commanded in REMOTE SET packets. */
6849 /* Returns 1 on success, 0 on failure. */
6852 remset(s) char *s; {
6853 extern int c_save, en_del;
6857 len = xunchar(*s++); /* Length of first field */
6858 p = s + len; /* Pointer to second length field */
6859 *p++ = '\0'; /* Zero out second length field */
6860 x = atoi(s); /* Value of first field */
6861 debug(F111,"remset",s,x);
6862 debug(F110,"remset",p,0);
6863 switch (x) { /* Do the right thing */
6864 case 132: /* Attributes (all, in) */
6867 case 133: /* File length attributes */
6868 case 233: /* IN/OUT combined */
6869 case 148: /* Both kinds of lengths */
6871 atleni = atleno = atoi(p);
6873 case 134: /* File Type (text/binary) */
6875 attypi = attypo = atoi(p);
6877 case 135: /* File creation date */
6879 atdati = atdato = atoi(p);
6881 case 139: /* File Blocksize */
6883 atblki = atblko = atoi(p);
6885 case 141: /* Encoding / Character Set */
6887 atenci = atenco = atoi(p);
6889 case 142: /* Disposition */
6891 atdisi = atdiso = atoi(p);
6893 case 145: /* System ID */
6895 atsidi = atsido = atoi(p);
6897 case 147: /* System-Dependent Info */
6899 atsysi = atsyso = atoi(p);
6901 case 232: /* Attributes (all, out) */
6904 case 300: /* File type (text, binary) */
6911 case 301: /* File name conversion */
6912 fncnv = 1 - atoi(p); /* (oops) */
6918 case 302: /* File name collision */
6921 if (inserver && isguest) /* May not be changed by guest */
6923 #endif /* CK_LOGIN */
6926 if (!ENABLED(en_del) && (x == XYFX_X || x == XYFX_U))
6928 if (x == XYFX_R) ckwarn = 1; /* Rename */
6929 if (x == XYFX_X) ckwarn = 0; /* Replace */
6932 case 310: /* Incomplete File Disposition */
6933 keep = atoi(p); /* Keep, Discard, Auto */
6935 case 311: /* Blocksize */
6938 case 312: /* Record Length */
6941 case 313: /* Record format */
6944 case 314: /* File organization */
6947 case 315: /* File carriage control */
6950 case 330: /* Match dotfiles */
6952 dir_dots = -1; /* This undoes DIR /DOT option */
6956 case 331: /* Match FIFOs */
6957 matchfifo = atoi(p);
6959 case 400: /* Block check */
6961 if (y < 5 && y > 0) {
6965 } else if (*p == 'B') {
6969 } else if (*p == '5') {
6975 case 401: /* Receive packet-length */
6976 rpsiz = urpsiz = atoi(p);
6977 if (urpsiz > MAXRP) urpsiz = MAXRP; /* Max long-packet length */
6978 if (rpsiz > 94) rpsiz = 94; /* Max short-packet length */
6979 urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
6981 case 402: /* Receive timeout */
6982 y = atoi(p); /* Client is telling us */
6983 if (y > -1 && y < 999) { /* the timeout that it wants */
6984 pkttim = chktimo(y,timef); /* us to tell it to use. */
6987 case 403: /* Retry limit */
6989 if (y > -1 && y < 95) {
6993 case 404: /* Server timeout */
6995 if (y < 0) return(0);
7000 case 405: { /* Transfer character set */
7001 extern int s_cset, axcset[];
7003 for (i = 0; i < ntcsets; i++) {
7004 if (!strcmp(tcsinfo[i].designator,p)) break;
7006 debug(F101,"remset tcharset lookup","",i);
7007 if (i == ntcsets) return(0);
7008 tcharset = tcsinfo[i].code; /* If known, use it */
7009 debug(F101,"remset tcharset","",tcharset);
7010 if (s_cset == XMODE_A)
7011 if (axcset[tcharset] > -1 && axcset[tcharset] > MAXFCSETS)
7012 fcharset = axcset[tcharset]; /* Auto-pick file charset */
7013 debug(F101,"remset tcharset fcharset","",fcharset);
7014 setxlatype(tcharset,fcharset); /* Set up charset translations */
7015 debug(F101,"remset xlatype","",xlatype);
7016 debug(F101,"remset tcharset after setxlatype","",tcharset);
7020 case 320: { /* File character set */
7021 extern struct keytab fcstab[];
7022 extern int nfilc, s_cset, r_cset;
7023 x = lookup(fcstab,p,nfilc,&y);
7024 debug(F111,"RSET FILE CHAR name",p,x);
7027 s_cset = XMODE_M; /* No automatic charset switching */
7029 fcharset = x; /* Set file charset */
7030 setxlatype(tcharset,fcharset); /* and translation type */
7034 #endif /* NOCSETS */
7036 case 406: /* Window slots */
7039 if (y < 1 || y > MAXWS) return(0);
7042 urpsiz = adjpkl(urpsiz,wslotr,bigrbsiz);
7045 case 410: /* Transfer mode */
7046 y = atoi(p); /* 0 = automatic, nonzero = manual */
7049 debug(F101,"REMOTE SET xfermode","",xfermode);
7052 case 420: /* SERVER CD-MESSAGE { ON, OFF } */
7053 y = atoi(p); /* 0 = automatic, nonzero = manual */
7057 default: /* Anything else... */
7062 /* Adjust packet length based on number of window slots and buffer size */
7065 adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
7066 if (protocol != PROTO_K) return(pktlen);
7067 debug(F101,"adjpkl len","",pktlen);
7068 debug(F101,"adjpkl slots","",slots);
7069 debug(F101,"adjpkl bufsiz","",bufsiz);
7070 if (((pktlen + 6) * slots) > bufsiz)
7071 pktlen = (bufsiz / slots) - 6;
7072 debug(F101,"adjpkl new len","",pktlen);
7076 /* Set transfer mode and file naming based on comparison of system types */
7082 extern int g_xfermode;
7087 debug(F101,"whoarewe xfermode","",xfermode);
7089 debug(F101,"whoarewe g_xfermode","",g_xfermode);
7091 if (whoareu[0]) { /* If we know partner's system type */
7092 char * p = (char *)whoareu;
7093 debug(F110,"whoarewe remote sysid",whoareu,0);
7094 if (!strcmp(p,cksysid)) /* Other system same as us */
7098 else if (!strcmp(p,"L3")) /* UNIX is sort of like AmigaDOS */
7099 wearealike = 1; /* (same directory separator) */
7100 else if (!strcmp(p,"N3")) /* UNIX like Aegis */
7104 /* Like UNIX, but case distinctions are ignored and can begin with device:. */
7105 else if (!strcmp(p,"U1")) /* Amiga is sort of like UNIX */
7107 else if (!strcmp(p,"N3")) /* Amiga is sort of like Aegis */
7110 #ifdef OS2 /* (Includes Windows 95/NT) */
7112 /* DOS, GEMDOS, Windows 3.x, Windows 95, Windows NT */
7113 /* All "the same" for FAT partitions but all bets off otherwise */
7114 /* so this part needs some refinement ... */
7116 else if (!strcmp(p,"U8")) /* MS-DOS */
7118 else if (!strcmp(p,"UO")) /* OS/2 */
7120 else if (!strcmp(p,"UN")) /* Windows NT or 95 */
7122 else if (!strcmp(p,"K2")) /* GEMDOS */
7126 else if (!strcmp(p,"U8"))
7128 else if (!strcmp(p,"UO"))
7130 else if (!strcmp(p,"UN"))
7132 else if (!strcmp(p,"K2"))
7139 /* Get here with wearealike == 1 if system types match */
7141 debug(F101,"whoarewe wearealike","",wearealike);
7142 if (!wearealike) /* Not alike */
7145 fncnv = XYFN_L; /* Alike, so literal filenames */
7146 debug(F101,"whoarewe setting fncnv","",fncnv);
7148 if (xfermode == XMODE_A) { /* Current xfer mode is auto */
7150 binary = XYFT_L; /* For VMS-to-VMS, use labeled */
7153 /* OS/2 but not Windows */
7154 if (!strcmp(cksysid,"UO") && !strcmp((char *)whoareu,"UO"))
7155 binary = XYFT_L; /* For OS/2-to-OS/2, use labeled */
7157 binary = XYFT_B; /* For all others use binary */
7160 gnf_binary = binary; /* Prevailing type for gnfile() */
7161 debug(F101,"whoarewe setting binary","",binary);