1 char *fnsv = "C-Kermit functions, 8.0.223, 1 May 2003";
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, 2004,
14 Trustees of Columbia University in the City of New York.
15 All rights reserved. See the C-Kermit COPYING.TXT file or the
16 copyright text in the ckcmai.c module for disclaimer and permissions.
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;
52 #endif /* CKSYMLINK */
53 #endif /* VMSORUNIX */
62 extern int apcactive, adl_ask;
69 /* (move these prototypes to the appropriate .h files...) */
74 _PROTOTYP( int getvnum, (char *) );
78 _PROTOTYP( static int bgetpkt, (int) );
80 _PROTOTYP( int lookup, (struct keytab[], char *, int, int *) );
83 _PROTOTYP( int zzstring, (char *, char **, int *) );
86 _PROTOTYP( long zfsize, (char *) );
87 #endif /* OS2ORUNIX */
100 /* Externals from ckcmai.c */
102 extern int srvcdmsg, srvidl, idletmo;
103 extern char * cdmsgfile[];
104 extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
105 rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr, xitsta;
106 extern int pktnum, bctr, bctu, bctl, clfils, sbufnum, protocol,
107 size, osize, spktl, nfils, ckwarn, timef, spsizf, sndtyp, rcvtyp, success;
108 extern int parity, turn, network, whatru, fsecs, justone, slostart,
109 ckdelay, displa, mypadn, moving, recursive, nettype;
110 extern long filcnt, flci, flco, tlci, tlco, tfc, fsize, sendstart, rs_len;
111 extern long filrej, oldcps, cps, peakcps, ccu, ccp, calibrate, filestatus;
112 extern int fblksiz, frecl, frecfm, forg, fcctrl, fdispla, skipbup;
113 extern int spackets, rpackets, timeouts, retrans, crunched, wmax, wcur;
114 extern int hcflg, binary, fncnv, b_save, f_save, server;
115 extern int nakstate, discard, rejection, local, xfermode, interrupted;
116 extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
117 extern int fnspath, fnrpath, eofmethod, diractive, whatru2, wearealike;
118 extern int atcapr, atcapb, atcapu;
119 extern int lpcapr, lpcapb, lpcapu;
120 extern int swcapr, swcapb, swcapu;
121 extern int lscapr, lscapb, lscapu;
122 extern int rscapr, rscapb, rscapu;
123 extern int rptena, rptmin;
124 extern int sseqtbl[];
125 extern int numerrs, nzxopts;
130 extern int carrier, ttprty;
131 extern int g_fnrpath;
134 #endif /* TCPSOCKET */
137 extern int sndxin, sndxhi, sndxlo;
140 extern int g_binary, g_fncnv;
143 extern CKFLOAT fpfsecs;
147 extern struct zattr iattr;
152 #endif /* PIPESEND */
156 extern int streamrq, streaming, streamed, streamok;
157 #endif /* STREAMING */
158 extern int reliable, clearrq, cleared, urclear;
161 atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
162 attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
164 extern int bigsbsiz, bigrbsiz;
166 extern char *filefile;
167 extern char whoareu[], * cksysid;
171 extern char * getpath[];
172 extern int fromgetpath;
173 #endif /* NOSERVER */
177 #endif /* CK_LOGIN */
179 extern int srvcmdlen;
180 extern CHAR *srvcmd, * epktmsg;
181 extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, myrptq;
182 extern CHAR *data, padbuf[], stchr, mystch;
185 extern char *cmarg, *cmarg2, **cmlist, filnam[], ofilnam[];
186 extern char *rfspec, *prfspec, *rrfspec, *prrfspec, *sfspec, *psfspec, *rfspec;
191 extern struct filelist * filehead, * filenext;
195 _PROTOTYP( int lslook, (unsigned int b) ); /* Locking Shift Lookahead */
196 _PROTOTYP( int szeof, (CHAR *s) );
197 _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 long sndsmaller = -1L;
267 long sndlarger = -1L;
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 long 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 == 0L && 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[1-swapping];
993 output.bytes[1] = uc.x_char[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 == 0 && 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 */
1469 if (ffc == 0L) xkanjf();
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 = 0L; /* 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 == 0) {
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 == 0) /* 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 == 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 == 0L) /* 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
2260 xx = (what & W_SEND) ? xut : xuf;
2262 if (haveuc) { /* File is Unicode */
2263 /* See Unicode TR13, "Converting to Other Character Sets" */
2264 if (uc.x_short == 0x2028 || /* Line Separator? */
2265 uc.x_short == 0x2029 || /* Paragraph Separator */
2266 (feol && (uc.x_short == (USHORT)feol))
2268 debug(F001,"xgnbyte uc eol","",uc.x_short);
2270 eolflag = 1; /* Don't translate and handle later */
2272 if (xx && !eolflag) { /* UCS-to-TCS function (UCS->byte) */
2273 rc = (*xx)(uc.x_short); /* These can fail... */
2274 debug(F101,"xgnbyte xx rc","",rc);
2275 if (rc < 0) /* If it can't be translated */
2276 uc.x_short = UNK; /* Put unknown-character symbol */
2278 uc.x_short = (unsigned)((unsigned)rc & 0xffff);
2279 debug(F101,"xgnbyte xx uc","",uc.x_short);
2282 if (tcs == FC_JEUC) { /* Translating to EUC-JP */
2285 debug(F001,"xgnbyte UCS->EUC UCS","",uc.x_short);
2286 if (!havesj) /* If we don't already have it */
2287 sj = un_to_sj(uc.x_short); /* convert to Shift-JIS */
2288 eu.x_short = sj_to_eu(sj);
2289 debug(F001,"xgnbyte UCS->EUC EUC","",eu.x_short);
2293 if (what & W_SEND) {
2294 xlabuf[xlacount++] = LF;
2300 if (eu.x_char[byteorder]) { /* Two bytes */
2301 rc = eu.x_char[byteorder];
2302 xlabuf[xlacount++] = eu.x_char[1-byteorder];
2303 debug(F001,"xgnbyte UCS->EUC xlabuf[0]","",xlabuf[0]);
2304 } else { /* One byte */
2305 rc = eu.x_char[1-byteorder];
2307 debug(F101,"xgnbyte UCS->EUC xlacount","",xlacount);
2308 debug(F001,"xgnbyte UCS->EUC rc","",rc);
2312 if (tcs != FC_UCS2 && tcs != FC_UTF8) {
2313 if (uc.x_short & 0xff00) { /* Decoding error */
2314 debug(F001,"xgnbyte decoding error","",uc.x_short);
2317 return((unsigned int)(uc.x_short & 0xff));
2321 } else { /* File is not Unicode */
2323 /* Translate from single FCS byte to UCS-2 */
2325 This is a bit nonobvious... The blah_u() (Blah-to-Unicode) routines are
2326 called only with pieces of character sets, in the ISO 2022 sense. So,
2327 for example, if ch is a Latin-1 character, we call the translation
2328 routine only if it is in the right half; if it's in the left half, it
2329 isn't translated, and in fact will give the wrong result if sent to the
2330 translation function. That's because those functions were designed for
2331 use with the ISO 2022 G0..G3 sets, not for file transfer. On the other
2332 hand, if it's a 7-bit character set, we *do* call the translation
2333 function. (To put it another way, the left half of any 8-bit character
2334 set is ASCII and therefore doesn't need to be translated but 7-bit sets
2335 such as ISO 646 German do need translation).
2337 ch = (unsigned)(thischar & 0xff);
2338 if (((fcsinfo[fcs].size > 128) && (ch & 0x80)) ||
2339 fcsinfo[fcs].size <= 128) {
2340 if (xfu) { /* FCS-to-UCS function */
2346 /* At this point we have a UCS-2 character in native format */
2347 /* (Big Endian or Little Endian) in xc, which is an unsigned int. */
2349 debug(F001,"xgnbyte xc","",xc);
2351 if (tcs == FC_UTF8) { /* Now convert to UTF-8 */
2352 USHORT c; /* NOTE: this is FC_UTF8 on purpose! */
2361 if (eolflag) { /* We detected EOL in source file */
2362 if (what & W_SEND) { /* Convert to CRLF */
2365 return((unsigned int)CR);
2367 } else { /* Or to local line-end */
2369 return((unsigned int)feol);
2370 #endif /* COMMENT */
2374 if ((x = ucs2_to_utf8(c,&buf)) < 1) {
2375 debug(F101,"xgnbyte ucs2_to_utf8 error","",c);
2378 debug(F101,"xgnbyte UTF8 buf[0]","",buf[0]);
2379 for (i = 1; i < x; i++) {
2380 xlabuf[k+i-1] = buf[i];
2381 debug(F111,"xgnbyte UTF8 xlabuf",ckitoa(i-1),buf[i]);
2385 debug(F101,"xgnbyte UTF8 xlacount","",xlacount);
2386 return((unsigned int)buf[0]);
2387 } else { /* Or keep it as UCS-2 */
2394 debug(F101,"xgnbyte error","",k);
2396 if (eolflag) { /* We detected EOL in source file */
2397 if (what & W_SEND) { /* Convert to CRLF */
2402 debug(F101,"xgnbyte send CRLF","",k);
2403 return(0); /* Return NUL */
2404 } else { /* Or to local line-end */
2406 /* This bypasses byte swapping that we might need */
2407 xlabuf[k++] = (CHAR)feol;
2409 debug(F101,"xgnbyte send feol","",k);
2410 return(0); /* Return NUL */
2413 #endif /* COMMENT */
2416 /* In which order should we return the bytes? */
2418 if ( (what & W_SEND) || (what & W_FTP) || (fileorder == 0)) {
2419 #endif /* COMMENT */
2420 /* ALWAYS RETURN IN BIG ENDIAN ORDER... 7 Sep 2002 */
2421 /* xgnbyte() is almost always used to feed xpnbyte() */
2422 /* which requires bytes in BE order. In cases where */
2423 /* xgnbyte is used in isolation, the caller can swap */
2424 /* bytes itself afterwards. */
2425 xlabuf[k++] = (xc >> 8) & 0xff; /* Big Endian */
2426 xlabuf[k++] = xc & 0xff;
2427 debug(F001,"xgnbyte->UCS2BE",
2428 ckitox((int)xlabuf[0]),xlabuf[1]);
2430 } else { /* Little Endian */
2431 xlabuf[k++] = xc & 0xff;
2432 xlabuf[k++] = (xc >> 8) & 0xff;
2433 debug(F001,"xgnbyte->UCS2LE",
2434 ckitox((int)xlabuf[0]),xlabuf[1]);
2436 #endif /* COMMENT */
2440 debug(F101,"xgnbyte c","",c);
2441 debug(F101,"xgnbyte xlaptr","",xlaptr);
2442 debug(F011,"xgnbyte xlabuf",xlabuf,xlacount);
2443 return((unsigned int)c);
2446 #endif /* UNICODE */
2448 return((fn ? (*fn)() : zminchar()));
2449 case XLA_BYTE: /* Byte-for-Byte translation */
2460 #endif /* UNICODE */
2461 return((unsigned int)rt);
2464 case XLA_JAPAN: /* Come here with Shift-JIS */
2465 if (tcs == FC_JEUC) { /* It better be... */
2469 printf("BAD BAD\n");
2472 if (!haveeu) /* We might already have EUC too */
2473 eu.x_short = sj_to_eu(sj.x_short);
2474 if (eu.x_char[byteorder]) {
2475 xlabuf[xlacount++] = eu.x_char[1-byteorder];
2476 return(eu.x_char[byteorder]);
2478 return(eu.x_char[1-byteorder]);
2485 debug(F101,"xgnbyte bad xlatype","",xlatype);
2490 If there is a return() statement here, some compilers complain
2491 about "statement not reached". If there is no return() statement,
2492 other compilers complain that "Non-void function should return a value".
2493 There is no path through this function that falls through to here.
2495 debug(F100,"xgnbyte switch failure","",0);
2497 #endif /* COMMENT */
2499 #endif /* NOCSETS */
2503 /* G E T P K T -- Fill a packet data field from the indicated source. */
2507 bufmax: Maximum length of entire packet.
2508 xlate: Flag for whether to translate charsets when in text mode.
2509 Returns: Number of characters written to packet data field, 0 or more,
2510 Or -1 on failure (internal error),
2511 or -3 on timeout (e.g. when reading from a pipe).
2513 This is the full version allowing for parity and text-mode conversions;
2514 i.e. it works in all cases. Also see bgetpkt(), a special lean/mean/fast
2515 packet encoder that works only for binary-mode no-parity transfers.
2517 static int uflag = 0;
2520 getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
2521 register CHAR rt = t, rnext = NUL; /* Register shadows of the globals */
2522 register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
2523 register int x; /* Loop index. */
2524 register int a7; /* Low 7 bits of character */
2526 CHAR xxls, xxdl, xxrc, xxss, xxcq; /* Pieces of prefixed sequence */
2528 if (binary) xlate = 0; /* We don't translate if binary */
2531 debug(F100,"SERIOUS ERROR: getpkt data == NULL","",0);
2534 dp = data; /* Point to packet data buffer */
2535 size = 0; /* And initialize its size */
2537 Assume bufmax is the receiver's total receive-packet buffer length.
2538 Our whole packet has to fit into it, so we adjust the data field length.
2539 We also decide optimally whether it is better to use a short-format or
2540 long-format packet when we're near the borderline.
2542 bufmax = maxdata(); /* Get maximum data length */
2544 if (first == 1) { /* If first character of this file.. */
2546 /* Special end-of-line handling for Unicode */
2547 if (tcharset == TC_UCS2 || tcharset == TC_UTF8)
2549 #endif /* UNICODE */
2550 debug(F101,"getpkt first uflag","",uflag);
2551 debug(F101,"getpkt first rt","",rt);
2552 if (!memstr && !funcstr) /* and real file... */
2553 ffc = 0L; /* reset file character counter */
2555 /* Moved to below... */
2556 first = 0; /* Next character won't be first */
2557 #endif /* COMMENT */
2558 *leftover = '\0'; /* Discard any interrupted leftovers */
2561 setxlatype(tcharset,fcharset); /* Set up charset translations */
2562 #endif /* NOCSETS */
2564 /* Get first character of file into rt, watching out for null file */
2567 if (calibrate && !memstr) {
2571 x = rt = cal_a[rand() & 0xff];
2572 #endif /* NORANDOM */
2576 #endif /* CALIBRATE */
2578 if (xlate && tcharset == TC_JEUC) { /* Kanji text */
2580 if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
2584 debug(F100,"getpkt zkanji: input error","",0);
2586 } else debug(F100,"getpkt zkanji: empty string/file","",0);
2593 if (docrc && (what & W_SEND)) /* Accumulate file crc */
2596 } else { /* Not Kanji text */
2598 if (memstr) { /* Reading data from memory string */
2599 /* This will not be Unicode */
2600 if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
2603 debug(F100,"getpkt: empty string","",0);
2607 } else if (funcstr) { /* Reading data from a function */
2608 /* This will not be Unicode */
2609 if ((x = (*funcptr)()) < 0) { /* End of input */
2611 size = 0; /* Empty */
2614 ffc++; /* Count a file character */
2615 rt = (CHAR) x; /* Convert int to char */
2617 debug(F000,"getpkt funcstr","",rt);
2619 } else { /* Reading data from a file */
2621 if (xlate && !binary) { /* Could be Unicode */
2622 if (xlatype == XLA_UNICODE) {
2623 /* Get next translated byte */
2624 x = xgnbyte(cseqtab[tcharset],fcharset,NULL);
2625 debug(F101,"getpkt xgnbyte","",x);
2626 } else { /* Not Unicode */
2627 x = zminchar(); /* Get next byte, translate below */
2628 debug(F101,"getpkt zminchar A","",x);
2630 } else { /* Just get next byte */
2631 #endif /* NOCSETS */
2633 debug(F101,"getpkt zminchar B","",x);
2636 #endif /* NOCSETS */
2637 if (x < 0) { /* End of file or input error */
2638 if (x == -3) { /* Timeout. */
2640 debug(F101,"getpkt timeout size","",size);
2641 return((size == 0) ? x : size);
2645 if (x == -2) { /* Error */
2646 debug(F100,"getpkt: input error","",0);
2647 cxseen = 1; /* Interrupt the file transfer */
2649 debug(F100,"getpkt empty file","",0);
2653 first = 0; /* Next character won't be first */
2654 rt = (CHAR) x; /* Convert int to char */
2656 if (xlatype != XLA_UNICODE || binary) {
2660 if (docrc && (what & W_SEND))
2663 #endif /* NOCSETS */
2666 debug(F101,"getpkt 1st char","",rt);
2668 if (/* !haveuc && */ docrc && (what & W_SEND)) /* File CRC */
2674 /* PWP: handling of feol is done later (in the while loop)... */
2676 } else if ((first == -1) && (nleft == 0)) { /* EOF from last time */
2679 debug(F101,"getpkt eof crc16","",crc16);
2680 debug(F101,"getpkt eof ffc","",ffc);
2686 Here we handle characters that were encoded for the last packet but
2687 did not fit, and so were saved in the "leftover" array.
2689 debug(F101,"getpkt nleft","",nleft);
2691 for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */
2693 *leftover = '\0'; /* Delete leftovers */
2696 if (first == -1) /* Handle EOF */
2697 return(size = (dp - data));
2699 /* Now fill up the rest of the packet. */
2701 rpt = 0; /* Initialize character repeat count */
2703 while (first > -1) { /* Until EOF... */
2705 if (calibrate && !memstr) { /* We generate our own "file" */
2706 if (ffc >= calibrate) { /* EOF */
2709 } else { /* Generate next character */
2710 if (cal_j > CAL_M * ffc)
2711 cal_j = cal_a[ffc & 0xff];
2712 x = (unsigned)cal_a[(cal_j & 0xff)];
2713 if (x == rt) x ^= 2;
2715 cal_j += (unsigned int)(ffc + CAL_O);
2718 #endif /* CALIBRATE */
2720 if (xlate && tcharset == TC_JEUC) {
2721 if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
2723 if (x == -2) cxseen = 1;
2724 } else if (!memstr) ffc++;
2725 rnext = (CHAR) (x & fmask);
2728 if (memstr) { /* Get next char from memory string */
2729 if ((x = *memptr++) == '\0') /* End of string means EOF */
2730 first = -1; /* Flag EOF for next time. */
2731 rnext = (CHAR) (x & fmask); /* Apply file mask */
2732 } else if (funcstr) { /* Get next char from function */
2733 if ((x = (*funcptr)()) < 0) /* End of string means EOF */
2734 first = -1; /* Flag EOF for next time. */
2735 rnext = (CHAR) (x & fmask); /* Apply file mask */
2736 } else { /* From file... */
2738 if (xlate && !binary) { /* Could be Unicode */
2739 if (xlatype == XLA_UNICODE) {
2740 /* Get next translated byte */
2741 x = xgnbyte(cseqtab[tcharset],fcharset,NULL);
2742 } else { /* Not Unicode */
2743 x = zminchar(); /* Get next byte, translate below */
2744 /* debug(F101,"xgnbyte B zminchar","",x); */
2746 } else { /* Just get next byte */
2747 #endif /* NOCSETS */
2749 /* debug(F101,"xgnbyte C zminchar","",x); */
2752 #endif /* NOCSETS */
2753 if (x < 0) { /* Check for EOF */
2754 if (x == -3) { /* Timeout reading from pipe */
2757 debug(F101,"getpkt timeout size","",size);
2758 return((size == 0) ? x : size);
2760 first = -1; /* Flag eof for next time. */
2761 if (x == -2) cxseen = 1; /* If error, cancel this file. */
2763 rnext = (CHAR) (x & fmask); /* Apply file mask */
2765 if (xlatype != XLA_UNICODE) {
2766 #endif /* NOCSETS */
2771 #endif /* NOCSETS */
2772 if (docrc && (what & W_SEND))
2777 #endif /* NOCSETS */
2783 At this point, the character we just read is in rnext,
2784 and the character we are about to encode into the packet is in rt.
2786 odp = dp; /* Remember where we started. */
2787 xxls = xxdl = xxrc = xxss = xxcq = NUL; /* Clear these. */
2789 Now encode the character according to the options that are in effect:
2790 ctlp[]: whether this control character needs prefixing.
2791 binary: text or binary mode.
2792 rptflg: repeat counts enabled.
2793 ebqflg: 8th-bit prefixing enabled.
2794 lscapu: locking shifts enabled.
2796 if (rptflg) { /* Repeat processing is on? */
2799 * If the next char is really CRLF, then we cannot
2800 * be doing a repeat (unless CR,CR,LF which becomes
2801 * "~ <n-1> CR CR LF", which is OK but not most efficient).
2802 * I just plain don't worry about this case. The actual
2803 * conversion from NL to CRLF is done after the rptflg if...
2805 (!feol || binary || (feol && (rnext != feol))) &&
2806 (rt == rnext) && (first == 0)) { /* Got a run... */
2807 if (++rpt < 94) { /* Below max, just count */
2808 continue; /* go back and get another */
2809 } else if (rpt == 94) { /* Reached max, must dump */
2810 xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
2811 rptn += rpt; /* Accumulate it for statistics */
2812 rpt = 0; /* And reset it */
2814 } else if (rpt > 1) { /* More than two */
2815 xxrc = (CHAR) tochar(++rpt); /* and count. */
2817 rpt = 0; /* Reset repeat counter. */
2820 If (rpt == 1) we must encode exactly two characters.
2821 This is done later, after the first character is encoded.
2824 /* If it's the newline character... */
2825 if (!uflag && !binary && feol && (rt == feol)) {
2826 if (lscapu && lsstate) { /* If SHIFT-STATE is SHIFTED */
2827 if (ebqflg) { /* If single shifts enabled, */
2828 *dp++ = (CHAR) ebq; /* insert a single shift. */
2829 } else { /* Otherwise must shift in. */
2830 *dp++ = myctlq; /* Insert shift-out code */
2832 lsstate = 0; /* Change shift state */
2837 *dp++ = myctlq; /* Insert carriage return directly */
2841 *dp++ = CR; /* Perhaps literally */
2844 #else /* !CK_SPEED */
2845 *dp++ = myctlq; /* Insert carriage return directly */
2848 #endif /* CK_SPEED */
2849 rt = LF; /* Now make next char be linefeed. */
2852 Now handle the 8th bit of the file character. If we have an 8-bit
2853 connection, we preserve the 8th bit. If we have a 7-bit connection,
2854 we employ either single or locking shifts (if they are enabled).
2856 a7 = rt & 0177; /* Get low 7 bits of character */
2857 if (rt & 0200) { /* 8-bit character? */
2858 if (lscapu) { /* Locking shifts enabled? */
2859 if (!lsstate) { /* Not currently shifted? */
2860 x = lslook(0200); /* Look ahead */
2861 if (x != 0 || ebqflg == 0) { /* Locking shift decision */
2862 xxls = 'N'; /* Need locking shift-out */
2863 lsstate = 1; /* and change to shifted state */
2864 } else if (ebqflg) { /* Not worth it */
2865 xxss = (CHAR) ebq; /* Use single shift */
2868 rt = (CHAR) a7; /* Replace character by 7-bit value */
2869 } else if (ebqflg) { /* 8th bit prefixing is on? */
2870 xxss = (CHAR) ebq; /* Insert single shift */
2871 rt = (CHAR) a7; /* Replace character by 7-bit value */
2874 In case we have a 7-bit connection and this is an 8-bit character, AND
2875 neither locking shifts nor single shifts are enabled, then the character's
2876 8th bit will be destroyed in transmission, and a block check error will
2879 } else if (lscapu) { /* 7-bit character */
2881 if (lsstate) { /* Comes while shifted out? */
2882 x = lslook(0); /* Yes, look ahead */
2883 if (x || ebqflg == 0) { /* Time to shift in. */
2884 xxls = 'O'; /* Set shift-in code */
2885 lsstate = 0; /* Exit shifted state */
2886 } else if (ebqflg) { /* Not worth it, stay shifted out */
2887 xxss = (CHAR) ebq; /* Insert single shift */
2891 /* If data character is significant to locking shift protocol... */
2892 if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
2893 xxdl = 'P'; /* Insert datalink escape */
2898 Thwart YET ANOTHER unwanted, unneeded, and unloved sign
2899 extension. This one was particularly nasty because it prevented
2900 255 (Telnet IAC) from being prefixed on some platforms -- e.g.
2901 VMS with VAX C -- but not others, thus causing file transfers to
2902 fail on Telnet connections by sending bare IACs. Not to mention
2903 the stray memory reference. Signed chars are a BAD idea.
2905 ctlp[(unsigned)(rt & 0xff)] /* Lop off any "sign" extension */
2907 (a7 < SP) || (a7 == DEL)
2908 #endif /* CK_SPEED */
2909 ) { /* Do control prefixing if necessary */
2910 xxcq = myctlq; /* The prefix */
2911 ccp++; /* Count it */
2912 rt = (CHAR) ctl(rt); /* Uncontrollify the character */
2915 else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
2917 #endif /* CK_SPEED */
2919 if (a7 == myctlq) /* Always prefix the control prefix */
2922 if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */
2923 xxcq = myctlq; /* prefix it if doing repeat counts */
2925 if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th-bit prefix */
2926 xxcq = myctlq; /* if doing 8th-bit prefixes */
2928 /* Now construct the entire sequence */
2930 if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
2931 odp2 = dp; /* (Save this place) */
2932 if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
2933 if (xxrc) { *dp++ = (CHAR) rptq; *dp++ = xxrc; } /* Repeat count */
2934 if (xxss) { *dp++ = (CHAR) ebq; } /* Single shift */
2935 if (xxcq) { *dp++ = myctlq; } /* Control prefix */
2936 *dp++ = rt; /* Finally, the character itself */
2938 if (rpt == 1) { /* Exactly two copies? */
2940 p2 = dp; /* Save place temporarily */
2941 for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
2943 if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
2944 if ((p2-data) < bufmax) odp = p2; /* Check packet bounds */
2946 rt = rnext; /* Next character is now current. */
2948 /* Done encoding the character. Now take care of packet buffer overflow. */
2950 if ((dp-data) >= bufmax) { /* If too big, save some for next. */
2952 debug(F000,"getpkt EOP","",rt);
2954 size = (dp-data); /* Calculate the size. */
2955 *dp = '\0'; /* Mark the end. */
2956 if (memstr) { /* No leftovers for memory strings */
2957 if (rt) /* Char we didn't encode yet */
2958 memptr--; /* (for encstr()) */
2961 if ((dp-data) > bufmax) { /* if packet is overfull */
2962 /* copy the part that doesn't fit into the leftover buffer, */
2963 /* taking care not to split a prefixed sequence. */
2966 for (i = 0, p1 = leftover, p2 = odp; i < nleft; i++) {
2968 if (memstr) memptr--; /* (for encstr) */
2970 debug(F111,"getpkt leftover",leftover,size);
2971 debug(F101,"getpkt osize","",(odp-data));
2972 size = (odp-data); /* Return truncated packet. */
2973 *odp = '\0'; /* Mark the new end */
2975 t = rt; /* Save for next time */
2978 } /* Otherwise, keep filling. */
2979 size = (dp-data); /* End of file */
2980 *dp = '\0'; /* Mark the end of the data. */
2981 debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
2982 return(size); /* return partially filled last packet. */
2985 /* T I N I T -- Initialize a transaction */
2987 int epktrcvd = 0, epktsent = 0;
2990 Call with 1 to reset everything before S/I/Y negotiation, or 0 to
2991 reset only the things that are not set in the S/I/Y negotiation.
2992 Returns -1 on failure (e.g. to create packet buffers), 0 on success.
2995 tinit(flag) int flag; {
2999 #endif /* CK_TIMERS */
3003 debug(F101,"tinit flag","",flag);
3009 diractive = 0; /* DIR / REMOTE DIR not active */
3010 interrupted = 0; /* Not interrupted */
3011 fatalio = 0; /* No fatal i/o error */
3014 pipesend = 0; /* This takes care of multiple GETs sent to a server. */
3016 bestlen = 0; /* For packet length optimization */
3017 maxsend = 0; /* Biggest data field we can send */
3019 streamok = 0; /* Streaming negotiated */
3020 streaming = 0; /* Streaming being done now */
3021 #endif /* STREAMING */
3023 binary = b_save; /* ... */
3024 gnf_binary = binary; /* Per-file transfer mode */
3025 retrans = 0; /* Packet retransmission count */
3026 sndtyp = 0; /* No previous packet */
3027 xflg = 0; /* Reset x-packet flag */
3028 memstr = 0; /* Reset memory-string flag */
3029 memptr = NULL; /* and buffer pointer */
3030 funcstr = 0; /* Reset "read from function" flag */
3031 funcptr = NULL; /* and function pointer */
3032 autopar = 0; /* Automatic parity detection flag */
3034 /* This stuff is only for BEFORE S/I/Y negotiation, not after */
3037 bctu = bctl = 1; /* Reset block check type to 1 */
3038 myinit[0] = '\0'; /* Haven't sent init string yet */
3039 rqf = -1; /* Reset 8th-bit-quote request flag */
3040 ebq = MYEBQ; /* Reset 8th-bit quoting stuff */
3041 ebqflg = 0; /* 8th bit quoting not enabled */
3042 ebqsent = 0; /* No 8th-bit prefix bid sent yet */
3043 sq = 'Y'; /* 8th-bit prefix bid I usually send */
3044 spsiz = spsizr; /* Initial send-packet size */
3045 debug(F101,"tinit spsiz","",spsiz);
3046 wslots = 1; /* One window slot */
3047 wslotn = 1; /* No window negotiated yet */
3048 justone = 0; /* (should this be zero'd here?) */
3049 whoareu[0] = NUL; /* Partner's system type */
3052 what = W_INIT; /* Doing nothing so far... */
3054 fncnv = f_save; /* Back to what user last said */
3055 pktnum = 0; /* Initial packet number to send */
3056 cxseen = czseen = discard = 0; /* Reset interrupt flags */
3057 *filnam = '\0'; /* Clear file name */
3058 spktl = 0; /* And its length */
3059 nakstate = 0; /* Assume we're not in a NAK state */
3060 numerrs = 0; /* Transmission error counter */
3061 idletmo = 0; /* No idle timeout yet */
3062 if (server) { /* If acting as server, */
3063 if (srvidl > 0) /* If an idle timeout is given */
3066 timint = srvtim; /* use server timeout interval. */
3067 } else { /* Otherwise */
3068 timint = chktimo(rtimo,timef); /* and use local timeout value */
3070 debug(F101,"tinit timint","",timint);
3073 if (rttflg && timint > 0) /* Using round-trip timers? */
3076 #endif /* CK_TIMERS */
3079 winlo = 0; /* Packet 0 is at window-low */
3080 debug(F101,"tinit winlo","",winlo);
3081 x = mksbuf(1); /* Make a 1-slot send-packet buffer */
3082 if (x < 0) return(x);
3083 x = getsbuf(0); /* Allocate first send-buffer. */
3084 debug(F101,"tinit getsbuf","",x);
3085 if (x < 0) return(x);
3087 x = mkrbuf(wslots); /* & a 1-slot receive-packet buffer. */
3088 if (x < 0) return(x);
3089 lsstate = 0; /* Initialize locking shift state */
3090 if (autopath) { /* SET RECEIVE PATHNAMES AUTO fixup */
3091 fnrpath = PATH_AUTO;
3098 pktinit() { /* Initialize packet sequence */
3099 pktnum = 0; /* number & window low. */
3101 debug(F101,"pktinit winlo","",winlo);
3104 /* R I N I T -- Respond to S or I packet */
3110 tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
3111 tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
3112 tlog(F110,"Collision action:", fncnam[fncact],0);
3114 debug(F101,"rinit fncact","",fncact);
3115 filcnt = filrej = 0; /* Init file counters */
3119 if ((local) && (!quiet)) /* Only do this if local & not quiet */
3120 consta_mt(); /* Start the asynch read task */
3121 #endif /* datageneral */
3125 /* R E S E T C -- Reset per-transaction character counters */
3129 rptn = 0; /* Repeat counts */
3130 fsecs = flci = flco = 0L; /* File chars in and out */
3133 #endif /* GFTIMER */
3134 tfc = tlci = tlco = 0L; /* Total file, line chars in & out */
3135 ccu = ccp = 0L; /* Control-char statistics */
3137 fsize = -1L; /* File size */
3139 if (!(what & W_SEND))
3141 debug(F101,"resetc fsize","",fsize);
3142 #endif /* COMMENT */
3143 timeouts = retrans = 0; /* Timeouts, retransmissions */
3144 spackets = rpackets = 0; /* Packet counts out & in */
3145 crunched = 0; /* Crunched packets */
3146 wcur = 0; /* Current window size */
3147 wmax = 0; /* Maximum window size used */
3148 peakcps = 0; /* Peak chars per second */
3151 /* S I N I T -- Get & verify first file name, then send Send-Init packet */
3154 1 if send operation begins successfully
3155 0 if send operation fails
3158 char *cmargbuf = NULL;
3160 char cmargbuf[CKMAXPATH+1];
3161 #endif /* DYNAMIC */
3167 sndsrc = (nfils < 0) ? -1 : nfils; /* Source for filenames */
3169 if (!cmargbuf && !(cmargbuf = malloc(CKMAXPATH+1)))
3170 fatal("fnlist: no memory for cmargbuf");
3171 #endif /* DYNAMIC */
3172 cmargbuf[0] = NUL; /* Initialize name buffer */
3174 debug(F101,"fnlist nfils","",nfils);
3175 debug(F110,"fnlist cmarg",cmarg,0);
3176 debug(F110,"fnlist cmarg2",cmarg2,0);
3177 if (!cmarg2) cmarg2 = "";
3178 if (nfils == 0) { /* Sending from stdin or memory. */
3179 if ((cmarg2 != NULL) && (*cmarg2)) {
3180 cmarg = cmarg2; /* If F packet, "as-name" is used */
3181 cmarg2 = ""; /* if provided */
3183 cmarg = "stdin"; /* otherwise just use "stdin" */
3184 ckstrncpy(cmargbuf,cmarg,CKMAXPATH+1);
3185 cmargp[0] = cmargbuf;
3194 int x; /* Worker int */
3195 char *tp, *xp, *m; /* Worker string pointers */
3197 filcnt = filrej = 0; /* Initialize file counters */
3204 if (usepipes && protocol == PROTO_K && *cmarg == '!') {
3208 #endif /* PIPESEND */
3213 xp = filehead->fl_name;
3215 #endif /* NOMSEND */
3223 debug(F110,"sinit xp",xp,0);
3224 x = gnfile(); /* Get first filename. */
3225 debug(F111,"sinit gnfile",ckitoa(gnferror),x);
3226 if (x == 0) x = gnferror; /* If none, get error reason */
3227 m = NULL; /* Error message pointer */
3228 debug(F101,"sinit gnfil","",x);
3230 case -6: m = "No files meet selection criteria"; break;
3231 case -5: m = "Too many files match wildcard"; break;
3232 case -4: m = "Cancelled"; break;
3233 case -3: m = "Read access denied"; break;
3234 case -2: m = "File is not readable"; break;
3236 case -1: m = iswild(filnam) ? "No files match" : "File not found";
3238 case 0: m = "No filespec given!"; break;
3241 case -1: m = iswild(filnam) ? "No files match" : "File not found";
3243 #endif /* COMMENT */
3247 debug(F101,"sinit nfils","",nfils);
3248 debug(F110,"sinit filnam",filnam,0);
3249 if (x < 1) { /* Didn't get a file. */
3250 debug(F111,"sinit msg",m,x);
3251 if (server) { /* Doing GET command */
3252 errpkt((CHAR *)m); /* so send Error packet. */
3253 } else if (!local) { /* Doing SEND command */
3254 interrupted = 1; /* (To suppress hint) */
3255 printf("?%s\r\n",m);
3257 xxscreen(SCR_EM,0,0l,m); /* so print message. */
3259 tlog(F110,xp,m,0L); /* Make transaction log entry. */
3260 freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */
3261 return(0); /* Return failure code */
3263 if (!local && !server && ckdelay > 0) /* OS-9 sleep(0) == infinite */
3264 sleep(ckdelay); /* Delay if requested */
3266 if ((local) && (!quiet)) /* Only do this if local & not quiet */
3267 consta_mt(); /* Start the async read task */
3268 #endif /* datageneral */
3269 freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */
3270 sipkt('S'); /* Send the Send-Init packet. */
3271 ztime(&tp); /* Get current date/time */
3272 tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
3273 tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
3275 debug(F111,"sinit ok",filnam,0);
3281 sipkt(char c) /* Send S or I packet. */
3287 extern int sendipkts;
3288 debug(F101,"sipkt pktnum","",pktnum); /* (better be 0...) */
3289 ttflui(); /* Flush pending input. */
3291 If this is an I packet and SET SEND I-PACKETS is OFF, don't send it;
3292 set sstate to 'Y' which makes the next input() call return 'Y' as if we
3293 had received an ACK to the I packet we didn't send. This is to work
3294 around buggy Kermit servers that can't handle I packets.
3296 if ((sendipkts == 0) && (c == 'I')) { /* I packet but don't send I pkts? */
3297 sstate = 'Y'; /* Yikes! */
3298 return(0); /* (see input()..)*/
3300 k = sseqtbl[pktnum]; /* Find slot for this packet */
3301 if (k < 0) { /* No slot? */
3302 k = getsbuf(winlo = pktnum); /* Make one. */
3303 debug(F101,"sipkt getsbuf","",k);
3305 rp = rpar(); /* Get protocol parameters. */
3306 if (!rp) rp = (CHAR *)"";
3307 x = spack(c,pktnum,(int)strlen((char *)rp),rp); /* Send them. */
3311 /* X S I N I T -- Retransmit S-packet */
3313 For use in the GET-SEND sequence, when we start to send, but receive another
3314 copy of the GET command because the receiver didn't get our S packet.
3315 This retransmits the S packet and frees the receive buffer for the ACK.
3316 This special case is necessary because packet number zero is being re-used.
3322 debug(F101,"xsinit k","",k);
3328 /* R C V F I L -- Receive a file */
3331 Incoming filename is in data field of F packet.
3332 This function decodes it into the srvcmd buffer, substituting an
3333 alternate "as-name", if one was given.
3334 Then it does any requested transformations (like converting to
3335 lowercase), and finally if a file of the same name already exists,
3336 takes the desired collision action.
3341 char ofn1[CKMAXPATH+4]; /* Buffer for output file name */
3342 char * ofn2; /* Pointer to backup file name */
3343 int ofn1x; /* Flag output file already exists */
3345 int opnerr; /* Flag for open error */
3347 int /* Returns success ? 1 : 0 */
3348 rcvfil(n) char *n; {
3354 char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */
3355 #endif /* OS2ONLY */
3361 extern char * rcvfilter;
3362 #endif /* PIPESEND */
3366 csave = calibrate; /* So we can decode filename */
3368 #endif /* CALIBRATE */
3370 ofperms = ""; /* Reset old-file permissions */
3371 opnerr = 0; /* No open error (yet) */
3372 ofn2 = NULL; /* No new name (yet) */
3373 lsstate = 0; /* Cancel locking-shift state */
3374 srvptr = srvcmd; /* Decode file name from packet. */
3377 xpnbyte(-1,0,0,NULL); /* Reset UCS-2 byte counter. */
3378 #endif /* UNICODE */
3380 debug(F110,"rcvfil rdatap",rdatap,0);
3381 decode(rdatap,putsrv,0); /* Don't xlate charsets. */
3384 if (dest == DEST_N) {
3386 cmarg2 = "CALIBRATE";
3388 #endif /* CALIBRATE */
3389 if (*srvcmd == '\0') /* Watch out for null F packet. */
3390 ckstrncpy((char *)srvcmd,"NONAME",srvcmdlen);
3391 makestr(&prrfspec,(char *)srvcmd); /* New preliminary filename */
3393 if (*srvcmd == '~') {
3394 dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
3396 ckstrncpy((char *)srvcmd,dirp,srvcmdlen);
3400 if (isalpha(*srvcmd) && srvcmd[1] == ':' && srvcmd[2] == '\0')
3401 ckstrncat((char *)srvcmd,"NONAME",srvcmdlen);
3407 /* File dialog when downloading... */
3410 (apcactive == APC_LOCAL && adl_ask) || /* Autodownload with ASK */
3412 (clcmds && haveurl) /* Or "kermit:" or "iksd:" URL */
3415 char fnbuf[CKMAXPATH+1]; /* Result buffer */
3418 if (clcmds && haveurl)
3419 preface = "\r\nIncoming file from Kermit server...\r\n\
3420 Please confirm output file specification or supply an alternative:";
3422 preface = "\r\nIncoming file from remote Kermit...\r\n\
3423 Please confirm output file specification or supply an alternative:";
3425 x = uq_file(preface, /* Preface */
3426 NULL, /* Prompt (let uq_file() built it) */
3427 3, /* Output file */
3428 NULL, /* Help text */
3429 (char *)srvcmd, /* Default */
3430 fnbuf, /* Result buffer */
3431 CKMAXPATH+1 /* Size of result buffer */
3433 if (x < 1) { /* Refused */
3434 rf_err = "Refused by user";
3437 ckstrncpy((char *)srvcmd,fnbuf,CKMAXPATH+1);
3438 if (isabsolute((char *)srvcmd)) { /* User gave an absolute path */
3439 g_fnrpath = fnrpath; /* Save current RECEIVE PATHNAMES */
3440 fnrpath = PATH_ABS; /* switch to ABSOLUTE */
3446 if (!ENABLED(en_cwd)) { /* CD is disabled */
3447 zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
3448 if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
3449 rf_err = "Access denied";
3454 /* Wrong place for this -- handle cmarg2 first -- see below... */
3456 if (zchko((char *)srvcmd) < 0) { /* Precheck for write access */
3457 debug(F110,"rcvfil access denied",srvcmd,0);
3458 rf_err = "Write access denied";
3459 discard = opnerr = 1;
3462 xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
3463 debug(F110,"rcvfil srvcmd 1",srvcmd,0);
3464 tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
3465 #endif /* COMMENT */
3467 skipthis = 0; /* This file in our exception list? */
3468 for (i = 0; i < NSNDEXCEPT; i++) {
3469 if (!rcvexcept[i]) {
3472 if (ckmatch(rcvexcept[i],(char *)srvcmd,filecase,1)) {
3479 if (deblog && skipthis) {
3480 debug(F111,"rcvfil rcvexcept",rcvexcept[i],i);
3481 debug(F110,"rcvfil skipping",srvcmd,0);
3485 if (skipthis) { /* Skipping this file */
3488 rf_err = "Exception list";
3489 debug(F101,"rcvfil discard","",discard);
3490 tlog(F100," refused: exception list","",0);
3494 /* File is not in exception list */
3496 if (!cmarg2) /* No core dumps please */
3498 debug(F110,"rcvfil cmarg2",cmarg2,0);
3500 if (*cmarg2) { /* Check for alternate name */
3502 int y; char *s; /* Pass it thru the evaluator */
3503 extern int cmd_quoting;
3506 ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* for \v(filename) */
3508 zzstring(cmarg2,&s,&y);
3511 if (!*srvcmd) /* If we got something */
3513 ckstrncpy((char *)srvcmd,cmarg2,srvcmdlen);
3515 debug(F110,"rcvfil srvcmd 2",srvcmd,0);
3518 /* If it starts with "bang", it's a pipe, not a file. */
3519 if (usepipes && protocol == PROTO_K && *srvcmd == '!' && !rcvfilter) {
3521 s = srvcmd+1; /* srvcmd[] is not a pointer. */
3522 while (*s) { /* So we have to slide the contents */
3523 *(s-1) = *s; /* over 1 space to the left. */
3529 #endif /* PIPESEND */
3533 This is commented out because we need to know whether the name we are
3534 using was specified by the local user as an override, or came from the
3535 incoming packet. In the former case, we don't do stuff to it (like
3536 strip the pathname) that we might do to it in the latter.
3538 cmarg2 = ""; /* Done with alternate name */
3539 #endif /* COMMENT */
3541 if ((int)strlen((char *)srvcmd) > CKMAXPATH) /* Watch out for overflow */
3542 *(srvcmd + CKMAXPATH - 1) = NUL;
3544 /* At this point, srvcmd[] contains the incoming filename or as-name. */
3545 /* So NOW we check for write access. */
3547 if (zchko((char *)srvcmd) < 0) { /* Precheck for write access */
3548 debug(F110,"rcvfil access denied",srvcmd,0);
3549 rf_err = "Write access denied";
3550 discard = opnerr = 1;
3553 xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
3554 debug(F110,"rcvfil srvcmd 1",srvcmd,0);
3555 tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
3560 If we have an as-name, this overrides the internal name if we are doing
3561 a labeled-mode transfer.
3565 lf_opts &= ~LBL_NAM;
3568 #endif /* CK_LABELED */
3570 debug(F111,"rcvfil pipesend",srvcmd,pipesend);
3573 /* Skip all the filename manipulation and collision actions */
3577 ckstrncpy(&ofn1[1],(char *)srvcmd,CKMAXPATH+1);
3578 ckstrncpy(n,ofn1,CKMAXPATH+1);
3579 ckstrncpy(fspec,ofn1,CKMAXPATH+1);
3580 makestr(&prfspec,fspec); /* New preliminary filename */
3581 debug(F110,"rcvfil pipesend",ofn1,0);
3584 #endif /* PIPESEND */
3586 This is to avoid passing email subjects through nzrtol().
3587 We haven't yet received the A packet so we don't yet know it's e-mail,
3588 so in fact we go ahead and convert it anyway, but later we get the
3589 original back from ofilnam[].
3592 ckstrncpy(ofilnam,(char *)srvcmd,CKMAXPATH+1);
3596 ckstrncpy((char *)ofn1,(char *)srvcmd,CKMAXPATH+1);
3598 nzrtol((char *)srvcmd, /* Filename from packet */
3599 (char *)ofn1, /* Where to put result */
3600 fncnv, /* Filename conversion */
3601 fnrpath, /* Pathname handling */
3602 CKMAXPATH /* Size of result buffer */
3605 debug(F101,"rcvfil fnrpath","",fnrpath); /* Handle pathnames */
3606 if (fnrpath == PATH_OFF && !*cmarg2) { /* RECEIVE PATHNAMES OFF? */
3608 zstrip((char *)srvcmd,&t); /* If there is a pathname, strip it */
3609 debug(F110,"rcvfil PATH_OFF zstrip",t,0);
3610 if (!t) /* Be sure we didn't strip too much */
3611 sprintf(ofn1,"FILE%02ld",filcnt);
3612 else if (*t == '\0')
3613 sprintf(ofn1,"FILE%02ld",filcnt);
3615 ckstrncpy(ofn1,t,CKMAXPATH+1);
3616 ckstrncpy((char *)srvcmd,ofn1,srvcmdlen); /* Now copy it back. */
3619 SET RECEIVE PATHNAMES RELATIVE...
3620 The following doesn't belong here but doing it right would require
3621 defining and implementing a new file routine for all ck?fio.c modules.
3625 else if (fnrpath == PATH_REL && !*cmarg2) {
3626 if (isabsolute((char *)srvcmd)) {
3628 ckstrncpy(&of1n[1],(char *)srvcmd,CKMAXPATH+1);
3629 ckstrncpy((char *)srvcmd,ofn1,srvcmdlen);
3630 debug(F110,"rcvfil PATH_REL",ofn1,0);
3635 else if (fnrpath == PATH_REL && !*cmarg2) {
3636 if (isabsolute((char *)srvcmd)) {
3637 char *p = (char *)srvcmd;
3638 if (isalpha(*p) && *(p+1) == ':')
3640 if (*p == '\\' || *p == '/')
3642 ckstrncpy(ofn1,p,CKMAXPATH+1);
3643 ckstrncpy((char *)srvcmd,ofn1,srvcmdlen);
3644 debug(F110,"rcvfil OS2 PATH_REL",ofn1,0);
3648 #endif /* UNIXOROSK */
3650 /* Now srvcmd contains incoming filename with path possibly stripped */
3652 if (fncnv) /* FILE NAMES CONVERTED? */
3653 zrtol((char *)srvcmd,(char *)ofn1); /* Yes, convert to local form */
3655 ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* No, copy literally. */
3660 char * p = NULL, * q;
3663 debug(F110,"rcvfil rcvfilter ",rcvfilter,0);
3665 if ((p = (char *) malloc(nn + 1))) {
3668 /* We have already processed srvcmd and placed it into ofn1 */
3669 ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* For \v(filename) */
3670 #endif /* COMMENT */
3671 debug(F110,"rcvfile pipesend filter",rcvfilter,0);
3672 zzstring(rcvfilter,&p,&nn);
3673 debug(F111,"rcvfil pipename",q,nn);
3676 "?Sorry, receive filter + filename too long, %d max.\n",
3679 rf_err = "Name too long";
3683 ckstrncpy((char *)srvcmd,q,MAXRP);
3688 #endif /* PIPESEND */
3690 /* Now the incoming filename, possibly converted, is in ofn1[]. */
3693 /* Don't refuse the file just because the name is illegal. */
3694 if (!IsFileNameValid(ofn1)) { /* Name is OK for OS/2? */
3697 zstrip(ofn1, &zs); /* Not valid, strip unconditionally */
3699 if (iattr.longname.len && /* Free previous longname, if any */
3701 free(iattr.longname.val);
3702 iattr.longname.len = strlen(zs); /* Store in attribute structure */
3703 iattr.longname.val = (char *) malloc(iattr.longname.len + 1);
3704 if (iattr.longname.val) /* Remember this (illegal) name */
3705 strcpy(iattr.longname.val, zs); /* safe */
3707 #endif /* OS2ONLY */
3708 debug(F110,"rcvfil: invalid file name",ofn1,0);
3709 ChangeNameForFAT(ofn1); /* Change to an acceptable name */
3710 debug(F110,"rcvfil: FAT file name",ofn1,0);
3712 } else { /* Name is OK. */
3714 debug(F110,"rcvfil: valid file name",ofn1,0);
3716 if (iattr.longname.len &&
3717 iattr.longname.val) /* Free previous longname, if any */
3718 free(iattr.longname.val);
3719 iattr.longname.len = 0;
3720 iattr.longname.val = NULL; /* This file doesn't need a longname */
3721 #endif /* OS2ONLY */
3724 debug(F110,"rcvfil as",ofn1,0);
3726 /* Filename collision action section. */
3728 dirflg = /* Is it a directory name? */
3733 #endif /* CK_TMPDIR */
3735 debug(F101,"rcvfil dirflg","",dirflg);
3736 ofn1len = zchki(ofn1); /* File already exists? */
3737 debug(F111,"rcvfil ofn1len",ofn1,ofn1len);
3738 ofn1x = (ofn1len != -1);
3742 strcmp(ofn1,"/dev/null") && /* It's not the null device? */
3745 strcmp(ofn1,"/nil") &&
3748 !stdouf ) && /* Not copying to standard output? */
3749 ofn1x || /* File of same name exists? */
3750 dirflg ) { /* Or file is a directory? */
3751 debug(F111,"rcvfil exists",ofn1,fncact);
3753 ofperms = zgperm((char *)ofn1); /* Get old file's permissions */
3754 debug(F110,"rcvfil perms",ofperms,0);
3755 #endif /* CK_PERMS */
3757 debug(F101,"rcvfil fncact","",fncact);
3758 switch (fncact) { /* Yes, do what user said. */
3759 case XYFX_A: /* Append */
3761 debug(F100,"rcvfil append","",0);
3763 rf_err = "Can't append to a directory";
3764 tlog(F100," error - can't append to directory","",0);
3765 discard = opnerr = 1;
3768 tlog(F110," appending to",ofn1,0);
3771 case XYFX_Q: /* Query (Ask) */
3772 break; /* not implemented */
3773 #endif /* COMMENT */
3774 case XYFX_B: /* Backup (rename old file) */
3776 rf_err = "Can't rename existing directory";
3777 tlog(F100," error - can't rename directory","",0);
3778 discard = opnerr = 1;
3781 znewn(ofn1,&ofn2); /* Get new unique name */
3782 tlog(F110," backup:",ofn2,0);
3783 debug(F110,"rcvfil backup ofn1",ofn1,0);
3784 debug(F110,"rcvfil backup ofn2",ofn2,0);
3788 In case this is a FAT file system, we can't change only the FAT name, we
3789 also have to change the longname from the extended attributes block.
3790 Otherwise, we'll have many files with the same longname and if we copy them
3791 to an HPFS volume, only one will survive.
3793 if (os2getlongname(ofn1, &longname) > -1) {
3794 if (strlen(longname)) {
3796 extern int ck_znewn;
3797 sprintf(tmp,".~%d~",ck_znewn);
3799 (char *) malloc(strlen(longname) + strlen(tmp) + 1);
3801 strcpy(newlongname, longname); /* safe (prechecked) */
3802 strcat(newlongname, tmp); /* safe (prechecked) */
3803 os2setlongname(ofn1, newlongname);
3808 } else debug(F100,"rcvfil os2getlongname failed","",0);
3809 #endif /* OS2ONLY */
3810 #endif /* CK_LABELED */
3813 /* Do this later, in opena()... */
3814 if (zrename(ofn1,ofn2) < 0) {
3815 rf_err = "Can't transform filename";
3816 debug(F110,"rcvfil rename fails",ofn1,0);
3817 discard = opnerr = 1;
3820 #endif /* COMMENT */
3823 case XYFX_D: /* Discard (refuse new file) */
3826 rejection = 1; /* Horrible hack: reason = name */
3827 debug(F101,"rcvfil discard","",discard);
3828 tlog(F100," refused: name","",0);
3831 case XYFX_R: /* Rename incoming file */
3832 znewn(ofn1,&ofn2); /* Make new name for it */
3834 if (iattr.longname.len) {
3836 extern int ck_znewn;
3837 sprintf(tmp,".~%d~",ck_znewn);
3839 (char *) malloc(iattr.longname.len + strlen(tmp) + 1);
3841 strcpy(newlongname, iattr.longname.val); /* safe */
3842 strcat(newlongname, tmp); /* safe */
3844 "Rename Incoming: newlongname",newlongname,0);
3845 if (iattr.longname.len &&
3847 free(iattr.longname.val);
3848 iattr.longname.len = strlen(newlongname);
3849 iattr.longname.val = newlongname;
3850 /* free(newlongname) here ? */
3853 #endif /* OS2ONLY */
3855 case XYFX_X: /* Replace old file */
3856 debug(F100,"rcvfil overwrite","",0);
3858 rf_err = "Can't overwrite existing directory";
3859 tlog(F100," error - can't overwrite directory","",0);
3860 discard = opnerr = 1;
3865 #endif /* COMMENT */
3867 tlog(F110,"overwriting",ofn1,0);
3869 case XYFX_U: /* Refuse if older */
3870 debug(F110,"rcvfil update",ofn1,0);
3872 rf_err = "File has same name as existing directory";
3873 tlog(F110," error - directory exists:",ofn1,0);
3874 discard = opnerr = 1;
3876 /* Don't send an error packet, just refuse the file */
3878 #endif /* COMMENT */
3880 break; /* Not here, we don't have */
3881 /* the attribute packet yet. */
3884 debug(F101,"rcvfil bad collision action","",fncact);
3888 debug(F110,"rcvfil ofn1",ofn1,0);
3889 debug(F110,"rcvfil ofn2",ofn2,0);
3890 debug(F110,"rcvfil ofperms",ofperms,0);
3891 if (fncact == XYFX_R && ofn1x && ofn2) { /* Renaming incoming file? */
3892 xxscreen(SCR_AN,0,0l,ofn2); /* Display renamed name */
3893 ckstrncpy(n, ofn2, CKMAXPATH+1); /* Return it */
3895 xxscreen(SCR_AN,0,0l,ofn1); /* Display regular name */
3896 ckstrncpy(n, ofn1, CKMAXPATH+1); /* and return it. */
3900 /* Create directory(s) if necessary. */
3901 if (!discard && fnrpath != PATH_OFF) { /* RECEIVE PATHAMES ON? */
3903 debug(F110,"rcvfil calling zmkdir",ofn1,0); /* Yes */
3904 if ((x = zmkdir(ofn1)) < 0) {
3905 debug(F100,"zmkdir fails","",0);
3906 tlog(F110," error - directory creation failure:",ofn1,0);
3907 rf_err = "Directory creation failure.";
3913 tlog(F110," path created:",ofn1,0);
3917 debug(F110,"rcvfil CK_MKDIR not defined",ofn1,0);
3918 #endif /* CK_MKDIR */
3921 ckstrncpy(fspec,ofn1,CKMAXPATH+1);
3923 zfnqfp(ofn1,fspeclen,fspec);
3924 debug(F110,"rcvfil fspec",fspec,0);
3927 /* See comments with VMS zfnqfp()... */
3929 /* zfnqfp() does not return the version number */
3934 if (ofn1[x-1] == ';') {
3936 ckstrncpy(&ofn1[x],ckitoa(v),CKMAXPATH-x);
3941 #endif /* COMMENT */
3942 fspec[fspeclen] = NUL;
3943 makestr(&prfspec,fspec); /* New preliminary filename */
3947 #endif /* PIPESEND */
3949 debug(F110,"rcvfilx: n",n,0);
3950 debug(F110,"rcvfilx: ofn1",ofn1,0);
3951 ffc = 0L; /* Init per-file counters */
3955 fsecs = gtimer(); /* Time this file started */
3957 fpfsecs = gftimer();
3958 debug(F101,"rcvfil fpfsecs","",fpfsecs);
3959 #endif /* GFTIMER */
3962 return(1); /* Successful return */
3966 /* R E O F -- Receive End Of File packet for incoming file */
3969 Closes the received file.
3972 -1 if file could not be closed.
3973 2 if disposition was mail, mail was sent, but temp file not deleted.
3974 3 if disposition was print, file was printed, but not deleted.
3975 -2 if disposition was mail and mail could not be sent
3976 -3 if disposition was print and file could not be printed
3977 -4 if MOVE-TO: failed
3978 -5 if RENAME-TO: failed
3981 reof(f,yy) char *f; struct zattr *yy; {
3982 extern char * rcv_move, * rcv_rename;
3983 extern int o_isopen;
3984 int rc = 0; /* Return code */
3988 debug(F111,"reof fncact",f,fncact);
3989 debug(F101,"reof discard","",discard);
3990 success = 1; /* Assume status is OK */
3991 lsstate = 0; /* Cancel locking-shift state */
3992 if (discard) { /* Handle attribute refusals, etc. */
3993 debug(F101,"reof discarding","",0);
3994 success = 0; /* Status = failed. */
3995 if (rejection == '#' || /* Unless rejection reason is */
3996 rejection == 1 || /* date or name (SET FILE COLLISION */
3997 rejection == '?') /* UPDATE or DISCARD) */
3999 debug(F101,"reof success","",success);
4000 filrej++; /* Count this rejection. */
4001 discard = 0; /* We never opened the file, */
4002 return(0); /* so we don't close it. */
4006 debug(F101,"reof cxseen","",cxseen);
4007 debug(F101,"reof czseen","",czseen);
4008 debug(F110,"reof rdatap",rdatap,0);
4012 if (cxseen == 0) /* Got cancel directive? */
4013 cxseen = (*rdatap == 'D');
4014 if (cxseen || czseen) /* (for hints) */
4016 success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */
4017 if (!success) /* "Uncount" this file */
4019 debug(F101,"reof o_isopen","",o_isopen);
4021 if (o_isopen) { /* If an output file was open... */
4025 debug(F101,"reof lastchar","",lastchar);
4026 if (!binary && eofmethod == XYEOF_Z && lastchar != 26 &&
4027 (!xflg || (xflg && remfile)))
4028 pnbyte((char)26,putfil);
4030 #endif /* CK_CTRLZ */
4032 rc = clsof(cxseen || czseen); /* Close the file (resets cxseen) */
4033 debug(F101,"reof closf","",rc);
4034 if (rc < 0) { /* If failure to close, FAIL */
4035 if (success) filrej++;
4039 /* Set file modification date and/or permissions */
4044 if (success && yy->longname.len)
4045 os2setlongname(f, yy->longname.val);
4046 #endif /* CK_LABELED */
4047 #endif /* OS2ONLY */
4049 if (success == 0) { /* And program return code */
4051 } else if (success == 1) { /* File rec'd successfully */
4052 makestr(&rrfspec,prrfspec); /* Record it for wheremsg */
4053 makestr(&rfspec,prfspec);
4056 /* Handle dispositions from attribute packet... */
4060 if (!calibrate && yy->disp.len != 0) {
4065 See ckcpro.w. In UNIX we don't use temp files any more -- we pipe the
4066 stuff right into mail or lpr.
4068 if (c == 'M') { /* Mail to user. */
4069 rc = zmail(p,filnam); /* Do the system's mail command */
4070 if (rc < 0) success = 0; /* Remember status */
4071 tlog(F110,"mailed",filnam,0L);
4072 tlog(F110," to",p,0L);
4073 zdelet(filnam); /* Delete the file */
4074 } else if (c == 'P') { /* Print the file. */
4075 rc = zprint(p,filnam); /* Do the system's print command */
4076 if (rc < 0) success = 0; /* Remember status */
4077 tlog(F110,"printed",filnam,0L);
4078 tlog(F110," with options",p,0L);
4081 /* spooler deletes file after print complete in VOS & VMS */
4082 if (zdelet(filnam) && rc == 0) rc = 3; /* Delete the file */
4083 #endif /* STRATUS */
4088 #endif /* NOFRILLS */
4092 !calibrate && c != 'M' && c != 'P') {
4093 if (rcv_move) { /* If /MOVE-TO was given... */
4094 char * p = rcv_move;
4096 /* No need for this - it's a directory name */
4097 char tmpbuf[CKMAXPATH+1];
4098 extern int cmd_quoting; /* for \v(filename) */
4099 if (cmd_quoting) { /* But only if cmd_quoting is on */
4103 debug(F111,"reof /move-to",rcv_move,0);
4104 zzstring(rcv_move,&p,&n);
4107 #endif /* COMMENT */
4109 Here we could create the directory if it didn't exist (and it was relative)
4110 but there would have to be a user-settable option to say whether to do this.
4112 rc = zrename(filnam,p);
4113 debug(F111,"reof MOVE zrename",rcv_move,rc);
4115 tlog(F110," moving received file to",rcv_move,0);
4118 tlog(F110," FAILED to move received file to",rcv_move,0);
4120 } else if (rcv_rename) { /* Or /RENAME-TO: */
4121 char *s = rcv_rename; /* This is the renaming string */
4123 char tmpnam[CKMAXPATH+16];
4124 extern int cmd_quoting; /* for \v(filename) */
4125 if (cmd_quoting) { /* But only if cmd_quoting is on */
4126 int n; /* Pass it thru the evaluator */
4129 zzstring(rcv_rename,&s,&n);
4134 rc = zrename(filnam,s);
4135 debug(F111,"reof RENAME zrename",s,rc);
4137 tlog(F110," renaming received file to",s,0);
4140 tlog(F110," FAILED to rename received file to",s,0);
4146 debug(F101,"reof success","",success);
4147 debug(F101,"reof returns","",rc);
4149 filnam[0] = NUL; /* Erase the filename */
4153 /* R E O T -- Receive End Of Transaction */
4157 cxseen = czseen = discard = 0; /* Reset interruption flags */
4158 tstats(); /* Finalize transfer statistics */
4161 /* S F I L E -- Send File header or teXt header packet */
4164 Call with x nonzero for X packet, zero for F packet.
4165 If X == 0, filename to send is in filnam[], and if cmarg2 is not null
4166 or empty, the file should be sent under this name rather than filnam[].
4167 If sndfilter not NULL, it is the name of a send filter.
4168 Returns 1 on success, 0 on failure.
4177 char pktnam[PKTNL+1]; /* Local copy of name */
4181 extern int filepeek;
4183 extern char * sndfilter;
4187 debug(F110,"sfile send filter ",sndfilter,0);
4189 #endif /* PIPESEND */
4191 notafile = calibrate || sndarray || pipesend || x;
4192 debug(F101,"sfile x","",x);
4193 debug(F101,"sfile notafile","",notafile);
4196 if (tcs_save > -1) { /* Character sets */
4197 tcharset = tcs_save;
4199 debug(F101,"sfile restored tcharset","",tcharset);
4201 if (fcs_save > -1) {
4202 fcharset = fcs_save;
4204 debug(F101,"sfile restored fcharset","",fcharset);
4206 setxlatype(tcharset,fcharset); /* Translation type */
4207 #endif /* NOCSETS */
4209 /* cmarg2 or filnam (with that precedence) have the file's name */
4211 lsstate = 0; /* Cancel locking-shift state */
4213 /* Do this after making sure we can open the file */
4214 if (nxtpkt() < 0) return(0); /* Bump packet number, get buffer */
4215 #endif /* COMMENT */
4216 pktnam[0] = NUL; /* Buffer for name we will send */
4217 if (x == 0) { /* F-Packet setup */
4218 if (!cmarg2) cmarg2 = "";
4221 debug(F111,"sfile cmarg2",cmarg2,cmarg2);
4222 debug(F101,"sfile binary 1","",binary);
4223 debug(F101,"sfile wearealike","",wearealike);
4224 debug(F101,"sfile xfermode","",xfermode);
4225 debug(F101,"sfile filepeek","",filepeek);
4227 debug(F101,"sfile s_cset","",s_cset);
4228 debug(F101,"sfile tcharset","",tcharset);
4229 debug(F101,"sfile xfrxla","",xfrxla);
4230 #endif /* NOCSETS */
4233 if (xfermode == XMODE_A /* TRANSFER MODE AUTOMATIC */
4235 && !addlist /* And not working from a SEND-LIST */
4236 #endif /* NOMSEND */
4238 /* Other Kermit is on a like system and no charset translation */
4241 && (tcharset == TC_TRANSP || xfrxla == 0)
4242 #endif /* NOCSETS */
4245 if (binary != XYFT_I)
4248 if (binary != XYFT_L)
4249 #endif /* CK_LABELED */
4250 binary = XYFT_B; /* Send all files in binary mode */
4253 /* Otherwise select transfer mode based on file info */
4255 else if (!notafile /* but not if sending from pipe */
4257 && binary != XYFT_L /* and not if FILE TYPE LABELED */
4258 #endif /* CK_LABELED */
4260 && binary != XYFT_I /* or FILE TYPE IMAGE */
4264 fileorder = -1; /* File byte order */
4265 #endif /* UNICODE */
4266 if (filepeek && !notafile) { /* Real file, FILE SCAN is ON */
4268 k = scanfile(filnam,&x,nscanfile); /* Scan the file */
4269 debug(F101,"sfile scanfile","",k);
4271 case FT_TEXT: /* Unspecified text */
4272 debug(F100,"sfile scanfile text","",0);
4273 binary = XYFT_T; /* SET FILE TYPE TEXT */
4276 case FT_7BIT: /* 7-bit text */
4277 binary = XYFT_T; /* SET FILE TYPE TEXT */
4278 /* If SEND CHARSET-SELECTION AUTO */
4279 /* and SET TRANSFER TRANSLATION is ON */
4280 debug(F100,"sfile scanfile text7","",0);
4281 if (s_cset == XMODE_A && xfrxla) {
4282 if (fcsinfo[fcharset].size != 128) {
4283 fcs_save = fcharset; /* Current FCS not 7bit */
4284 fcharset = dcset7; /* Use default 7bit set */
4285 debug(F101,"sfile scanfile 7 fcharset",
4288 /* And also switch to appropriate TCS */
4289 if (afcset[fcharset] > -1 &&
4290 afcset[fcharset] <= MAXTCSETS) {
4291 tcs_save = tcharset;
4292 tcharset = afcset[fcharset];
4293 debug(F101,"sfile scanfile 7 tcharset","",
4296 setxlatype(tcharset,fcharset);
4300 case FT_8BIT: /* 8-bit text */
4301 binary = XYFT_T; /* SET FILE TYPE TEXT */
4302 /* If SEND CHARSET-SELEC AUTO */
4303 /* and SET TRANSFER TRANSLATION is ON */
4304 debug(F100,"sfile scanfile text8","",0);
4305 if (s_cset == XMODE_A && xfrxla) {
4306 if (fcsinfo[fcharset].size != 256) {
4307 fcs_save = fcharset; /* Current FCS not 8bit */
4308 fcharset = dcset8; /* Use default 8bit set */
4309 debug(F101,"sfile scanfile 8 fcharset",
4312 /* Switch to corresponding transfer charset */
4313 if (afcset[fcharset] > -1 &&
4314 afcset[fcharset] <= MAXTCSETS) {
4315 tcs_save = tcharset;
4316 tcharset = afcset[fcharset];
4317 debug(F101,"sfile scanfile 8 tcharset","",
4320 setxlatype(tcharset,fcharset);
4324 case FT_UTF8: /* UTF-8 text */
4325 case FT_UCS2: /* UCS-2 text */
4326 debug(F101,"sfile scanfile Unicode","",k);
4328 /* If SEND CHARSET-SELEC AUTO */
4329 /* and SET TRANSFER TRANSLATION is ON */
4330 if (s_cset == XMODE_A && xfrxla) {
4331 fcs_save = fcharset;
4332 tcs_save = tcharset;
4333 fcharset = (k == FT_UCS2) ? FC_UCS2 : FC_UTF8;
4334 if (k == FT_UCS2 && x > -1)
4337 /* Switch to associated transfer charset if any */
4338 if (afcset[fcharset] > -1 &&
4339 afcset[fcharset] <= MAXTCSETS)
4340 tcharset = afcset[fcharset];
4341 if (tcharset == TC_TRANSP) /* If none */
4342 tcharset = TC_UTF8; /* use UTF-8 */
4343 setxlatype(tcharset,fcharset);
4344 debug(F101,"sfile Unicode tcharset","",tcharset);
4346 #endif /* UNICODE */
4347 #endif /* NOCSETS */
4349 debug(F101,"sfile scanfile binary","",k);
4352 /* Default: Don't change anything */
4356 debug(F101,"sfile binary 2","",binary);
4357 debug(F101,"sfile sendmode","",sendmode);
4359 if (*cmarg2) { /* If we have a send-as name... */
4361 #ifndef NOSPL /* and a script programming language */
4362 extern int cmd_quoting;
4363 if (cmd_quoting) { /* and it's not turned off */
4364 y = PKTNL; /* pass as-name thru the evaluator */
4366 zzstring(cmarg2,&s,&y);
4368 /* This ruins macros like BSEND */
4369 if (!pktnam[0]) /* and make sure result is not empty */
4370 sprintf(pktnam,"FILE%02ld",filcnt);
4371 #endif /* COMMENT */
4374 ckstrncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */
4376 debug(F110,"sfile pktnam",pktnam,0);
4378 /* We don't do this any more because now we have filename templates */
4379 cmarg2 = ""; /* and blank it out for next time. */
4380 #endif /* COMMENT */
4382 if (!*pktnam) { /* No as-name... */
4385 debug(F101,"sfile fnspath","",fnspath);
4386 debug(F101,"sfile fncnv","",fncnv);
4389 if (notafile) { /* If not an actual file */
4390 xfncnv = 0; /* Don't convert name */
4391 xpath = PATH_OFF; /* Leave path off */
4392 } else if (xfncnv &&
4393 (!strcmp(whoareu,"U1") || !strcmp(whoareu,"UN"))
4395 /* Less-strict conversion if partner is UNIX or Win32 */
4398 debug(F101,"sfile xpath","",xpath);
4399 debug(F101,"sfile xfncnv","",xfncnv);
4400 nzltor(filnam,pktnam,xfncnv,xpath,PKTNL);
4402 #else /* Not NZLTOR */
4404 debug(F101,"sfile fnspath","",fnspath);
4405 if (fnspath == PATH_OFF /* Stripping path names? */
4406 && (!notafile) /* (of actual files) */
4409 zstrip(filnam,&t); /* Strip off the path. */
4410 debug(F110,"sfile zstrip",t,0);
4411 if (!t) t = "UNKNOWN"; /* Be cautious... */
4412 else if (*t == '\0')
4414 ckstrncpy(pktnam,t,PKTNL); /* Copy stripped name literally. */
4415 } else if (fnspath == PATH_ABS && !notafile) {
4416 /* Converting to absolute form */
4417 zfnqfp(filnam,PKTNL,pktnam);
4419 ckstrncpy(pktnam,filnam,PKTNL);
4421 /* pktnam[] has the packet name, filnam[] has the original name. */
4422 /* But we still need to convert pktnam if FILE NAMES CONVERTED. */
4424 debug(F101,"sfile fncnv","",fncnv);
4425 if (fncnv && !notafile) { /* If converting names of files */
4426 zltor(pktnam,(char *)srvcmd); /* convert it to common form, */
4427 ckstrncpy(pktnam,(char *)srvcmd,PKTNL);
4432 if (!*pktnam) /* Failsafe... */
4433 sprintf(pktnam,"FILE%02ld",filcnt);
4434 debug(F110,"sfile filnam 1",filnam,0);
4435 debug(F110,"sfile pktnam 1",pktnam,0);
4437 /* If we have a send filter, substitute the current filename into it */
4440 char * p = NULL, * q;
4443 if ((p = (char *) malloc(n + 1))) {
4445 debug(F110,"sfile pipesend filter",sndfilter,0);
4446 zzstring(sndfilter,&p,&n);
4447 debug(F111,"sfile pipename",q,n);
4450 "?Sorry, send filter + filename too long, %d max.\n",
4456 ckstrncpy(filnam,q,CKMAXPATH+1);
4461 #endif /* PIPESEND */
4463 debug(F110,"sfile filnam 2",filnam,0); /* Log debugging info */
4464 debug(F110,"sfile pktnam 2",pktnam,0);
4465 if (openi(filnam) == 0) /* Try to open the input file */
4470 The following check is done after openi() is called, since openi() itself
4471 can change the transfer mode (as in VMS).
4473 if ((binary == XYFT_T
4477 ) && sendmode == SM_RESEND) {
4478 /* Trying to RESEND/REGET a file first sent in TEXT mode. */
4479 debug(F111,"sfile error - Recover vs Text",filnam,binary);
4480 /* Set appropriate error messages and make log entries here */
4482 if (binary == XYFT_L)
4483 ckmakmsg((char *)epktmsg,
4485 "Recovery attempted in LABELED mode: ",
4492 ckmakmsg((char *)epktmsg,
4494 "Recovery attempted in TEXT mode: ",
4501 if (sendmode == SM_PSEND) /* PSENDing? */
4502 if (sendstart > 0L) /* Starting position */
4503 if (zfseek(sendstart) < 0) /* seek to it... */
4505 #endif /* CK_RESEND */
4506 s = pktnam; /* Name for packet data field */
4508 /* Never send a disk letter. */
4509 if (isalpha(*s) && (*(s+1) == ':'))
4513 } else { /* X-packet setup, not F-packet. */
4514 binary = XYFT_T; /* Text always */
4515 debug(F110,"sfile X packet",cmdstr,0); /* Log debugging info */
4516 s = cmdstr; /* Name for data field */
4519 /* Now s points to the string that goes in the packet data field. */
4521 debug(F101,"sfile binary","",binary); /* Log debugging info */
4522 encstr((CHAR *)s); /* Encode the name. */
4523 /* Send the F or X packet */
4524 /* If the encoded string did not fit into the packet, it was truncated. */
4526 if (nxtpkt() < 0) return(0); /* Bump packet number, get buffer */
4528 rc = spack((char) (x ? 'X' : 'F'), pktnum, size, data);
4533 setxlatype(tcharset,fcharset); /* Set up charset translations */
4534 #endif /* NOCSETS */
4536 if (x == 0) { /* Display for F packet */
4537 if (displa) { /* Screen */
4538 xxscreen(SCR_FN,'F',(long)pktnum,filnam);
4539 xxscreen(SCR_AN,0,0L,pktnam);
4540 xxscreen(SCR_FS,0,calibrate ? calibrate : fsize,"");
4543 tlog(F110,"Sending",filnam,0L); /* Transaction log entry */
4544 makestr(&psfspec,filnam); /* New filename */
4547 tlog(F110,"Sending",filnam,0L);
4548 makestr(&psfspec,filnam); /* New filename */
4550 if (notafile) { /* If not a file log simple name */
4551 tlog(F110,"Sending", filnam, 0L);
4552 } else { /* Log fully qualified filename */
4554 /* This section generates bad code in SCO 3.2v5.0.5's cc */
4555 char *p = NULL, *q = filnam;
4556 debug(F101,"sfile CKMAXPATH","",CKMAXPATH);
4557 if ((p = malloc(CKMAXPATH+1))) {
4558 debug(F111,"sfile calling zfnqfp",filnam,strlen(filnam));
4559 if (zfnqfp(filnam, CKMAXPATH, p)) {
4560 debug(F111,"sfile zfnqfp ok",p,strlen(p));
4565 char tmpbuf[CKMAXPATH+1];
4566 char *p = tmpbuf, *q = filnam;
4567 if (zfnqfp(filnam, CKMAXPATH, p))
4569 #endif /* COMMENT */
4570 debug(F111,"sfile q",q,strlen(q));
4571 tlog(F110,"Sending",q,0L);
4572 makestr(&psfspec,q); /* New preliminary filename */
4575 #endif /* COMMENT */
4579 tlog(F110," as",pktnam,0L);
4580 if (binary) { /* Log file mode in transaction log */
4581 tlog(F101," mode: binary","",(long) binary);
4582 } else { /* If text mode, check character set */
4583 tlog(F100," mode: text","",0L);
4585 if (tcharset == TC_TRANSP || xfrxla == 0) {
4586 tlog(F110," character set","transparent",0L);
4588 tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
4589 tlog(F110," file character set",fcsinfo[fcharset].name,0L);
4591 #endif /* NOCSETS */
4593 } else { /* Display for X-packet */
4595 xxscreen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */
4596 tlog(F110,"Sending from:",cmdstr,0L); /* Transaction log */
4598 intmsg(++filcnt); /* Count file, give interrupt msg */
4599 first = 1; /* Init file character lookahead. */
4600 ffc = 0L; /* Init file character counter. */
4601 cps = oldcps = 0L; /* Init cps statistics */
4603 fsecs = gtimer(); /* Time this file started */
4605 fpfsecs = gftimer();
4606 debug(F101,"SFILE fpfsecs","",fpfsecs);
4607 #endif /* GFTIMER */
4608 debug(F101,"SFILE fsecs","",fsecs);
4612 /* S D A T A -- Send a data packet */
4615 Returns -1 if no data to send (end of file), -2 if connection is broken.
4616 If there is data, a data packet is sent, and sdata() returns 1.
4618 In the streaming case, the window is regarded as infinite and we keep
4619 sending data packets until EOF or there appears to be a Kermit packet on the
4620 reverse channel. When not streaming and the window size is greater than 1,
4621 we keep sending data packets until window is full or characters start to
4622 appear from the other Kermit.
4624 In the windowing or streaming case, when there is no more data left to send
4625 (or when sending has been interrupted), sdata() does nothing and returns 0
4626 each time it is called until the acknowledgement sequence number catches up
4627 to the last data packet that was sent.
4634 debug(F101,"sdata entry, first","",first);
4635 debug(F101,"sdata drain","",drain);
4637 The "drain" flag is used with window size > 1. It means we have sent
4638 our last data packet. If called and drain is not zero, then we return
4639 0 as if we had sent an empty data packet, until all data packets have
4640 been ACK'd, then then we can finally return -1 indicating EOF, so that
4641 the protocol can switch to seof state. This is a kludge, but at least
4644 if (first == 1) drain = 0; /* Start of file, init drain flag. */
4646 if (drain) { /* If draining... */
4647 debug(F101,"sdata draining, winlo","",winlo);
4648 if (winlo == pktnum) /* If all data packets are ACK'd */
4649 return(-1); /* return EOF indication */
4650 else /* otherwise */
4651 return(0); /* pretend we sent a data packet. */
4653 debug(F101,"sdata sbufnum","",sbufnum);
4658 #endif /* STREAMING */
4663 debug(F101,"sdata countdown","",i);
4666 pktnum = (pktnum + 1) % 64;
4668 debug(F101,"sdata streaming pktnum","",pktnum);
4670 #endif /* STREAMING */
4671 x = nxtpkt(); /* Get next pkt number and buffer */
4672 debug(F101,"sdata nxtpkt pktnum","",pktnum);
4673 if (x < 0) return(0);
4676 #endif /* STREAMING */
4677 debug(F101,"sdata packet","",pktnum);
4678 if (chkint() < 0) /* Especially important if streaming */
4680 if (cxseen || czseen) { /* If interrupted, done. */
4683 debug(F100,"sdata cx/zseen windowing","",0);
4686 debug(F100,"sdata cx/zseen nonwindowing","",0);
4692 debug(F101,"sdata spsiz","",spsiz);
4693 debug(F101,"sdata binary","",binary);
4694 debug(F101,"sdata parity","",parity);
4698 if (binary && !parity && !memstr && !funcstr)
4699 len = bgetpkt(spsiz);
4701 len = getpkt(spsiz,1);
4703 len = getpkt(spsiz,1);
4704 #endif /* CKTUNING */
4706 if (len == -3) { /* Timed out (e.g.reading from pipe) */
4707 s = ""; /* Send an empty data packet. */
4709 } else if (len == 0) { /* Done if no data. */
4710 if (pktnum == winlo)
4712 drain = 1; /* But can't return -1 until all */
4713 debug(F101,"sdata eof, drain","",drain);
4714 return(0); /* ACKs are drained. */
4716 debug(F101,"sdata pktnum","",pktnum);
4717 debug(F101,"sdata len","",len);
4718 debug(F011,"sdata data",data,52);
4720 x = spack('D',pktnum,len,(CHAR *)s); /* Send the data packet. */
4721 debug(F101,"sdata spack","",x);
4722 if (x < 0) { /* Error */
4723 ttchk(); /* See if connection is still there */
4727 if (streaming) /* What an ACK would do. */
4729 #endif /* STREAMING */
4730 x = ttchk(); /* Peek at input buffer. */
4731 debug(F101,"sdata ttchk","",x); /* ACKs waiting, maybe? */
4732 if (x < 0) /* Or connection broken? */
4735 Here we check to see if any ACKs or NAKs have arrived, in which case we
4736 break out of the D-packet-sending loop and return to the state switcher
4737 to process them. This is what makes our windows slide instead of lurch.
4742 In the Atari ST version, ttchk() can only return 0 or 1. But note: x will
4743 probably always be > 0, since the as-yet-unread packet terminator from the
4744 last packet is probably still in the buffer, so sliding windows will
4745 probably never happen when the Atari ST is the file sender. The alternative
4746 is to say "if (0)", in which case the ST will always send a window full of
4747 packets before reading any ACKs or NAKs.
4753 In most other versions, ttchk() returns the actual count.
4754 It can't be a Kermit packet if it's less than five bytes long.
4760 return(1); /* Yes, stop sending data packets */
4761 } /* and go try to read the ACKs. */
4766 /* S E O F -- Send an End-Of-File packet */
4768 /* Call with a string pointer to character to put in the data field, */
4769 /* or else a null pointer or "" for no data. */
4772 There are two "send-eof" functions. seof() is used to send the normal eof
4773 packet at the end of a file's data (even if the file has no data), or when
4774 a file transfer is interrupted. sxeof() is used to send an EOF packet that
4775 occurs because of attribute refusal or interruption prior to entering data
4776 state. The difference is purely a matter of buffer allocation and packet
4777 sequence number management. Both functions act as "front ends" to the
4778 common send-eof function, szeof().
4781 /* Code common to both seof() and sxeof() */
4786 lsstate = 0; /* Cancel locking-shift state */
4787 if (!s) s = (CHAR *)"";
4788 debug(F111,"szeof",s,pktnum);
4790 x = spack('Z',pktnum,1,s);
4793 tlog(F100," *** interrupted, sending discard request","",0L);
4794 #endif /* COMMENT */
4797 x = spack('Z',pktnum,0,(CHAR *)"");
4804 discard = 0; /* Turn off per-file discard flag */
4805 #endif /* COMMENT */
4807 /* If we were sending from a pipe, we're not any more... */
4816 ckcpro.w, before calling seof(), sets window size back to 1 and then calls
4817 window(), which clears out the old buffers. This is OK because the final
4818 data packet for the file has been ACK'd. However, sdata() has already
4819 called nxtpkt(), which set the new value of pktnum which seof() will use.
4820 So all we need to do here is is allocate a new send-buffer.
4823 debug(F111,"seof",s,pktnum);
4824 if (getsbuf(pktnum) < 0) { /* Get a buffer for packet n */
4825 debug(F101,"seof can't get s-buffer","",pktnum);
4828 return(szeof((CHAR *)s));
4832 Version of seof() to be called when sdata() has not been called before. The
4833 difference is that this version calls nxtpkt() to allocate a send-buffer and
4834 get the next packet number.
4840 if (nxtpkt() < 0) /* Get next pkt number and buffer */
4841 debug(F101,"sxeof nxtpkt fails","",pktnum);
4843 debug(F101,"sxeof packet","",pktnum);
4844 return(szeof((CHAR *)s));
4847 /* S E O T -- Send an End-Of-Transaction packet */
4853 debug(F101,"seot nxtpkt","",x);
4854 if (x < 0) return(-1); /* Bump packet number, get buffer */
4855 x = spack('B',pktnum,0,(CHAR *)""); /* Send the EOT packet */
4858 cxseen = czseen = discard = 0; /* Reset interruption flags */
4859 tstats(); /* Log timing info */
4864 /* R P A R -- Fill the data array with my send-init parameters */
4868 CHAR dada[32]; /* Use this instead of data[]. */
4869 /* To avoid some kind of wierd */
4870 /* addressing foulup in spack()... */
4871 /* (which might be fixed now...) */
4879 max = maxdata(); /* Biggest data field I can send */
4880 debug(F101, "rpar max 1","",max);
4881 debug(F101, "rpar sprmlen","",sprmlen);
4882 if (sprmlen > 1 && sprmlen < max) /* User override */
4884 debug(F101, "rpar max 2","",max);
4886 if (rpsiz > MAXPACK) /* Biggest normal packet I want. */
4887 dada[0] = (char) tochar(MAXPACK); /* If > 94, use 94, but specify */
4888 else /* extended packet length below... */
4889 dada[0] = (char) tochar(rpsiz); /* else use what the user said. */
4890 dada[1] = (char) tochar(chktimo(pkttim,0)); /* When to time me out */
4891 dada[2] = (char) tochar(mypadn); /* How much padding I need (none) */
4892 dada[3] = (char) ctl(mypadc); /* Padding character I want */
4893 dada[4] = (char) tochar(eol); /* End-Of-Line character I want */
4894 dada[5] = myctlq; /* Control-Quote character I send */
4896 if (max < 6) { dada[6] = NUL; rqf = 0; ebq = sq = NUL; return(dada); }
4898 switch (rqf) { /* 8th-bit prefix (single-shift) */
4899 case -1: /* I'm opening the bids */
4900 case 1: /* Other Kermit already bid 'Y' */
4901 if (parity) ebq = sq = MYEBQ; /* So I reply with '&' if parity */
4902 break; /* otherwise with 'Y'. */
4903 case 2: /* Other Kermit sent a valid prefix */
4905 sq = ebq; /* Fall through on purpose */
4906 case 0: /* Other Kermit bid nothing */
4907 break; /* So I reply with 'Y'. */
4909 debug(F000,"rpar 8bq sq","",sq);
4910 debug(F000,"rpar 8bq ebq","",ebq);
4911 if (lscapu == 2) /* LOCKING-SHIFT FORCED */
4912 dada[6] = 'N'; /* requires no single-shift */
4913 else /* otherwise send prefix or 'Y' */
4914 dada[6] = (char) sq;
4915 ebqsent = dada[6]; /* And remember what I really sent */
4917 if (max < 7) { dada[7] = NUL; bctr = 1; return(dada); }
4919 dada[7] = (char) (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */
4921 if (max < 8) { dada[8] = NUL; rptflg = 0; return(dada); }
4924 if (rptflg) /* Run length encoding */
4925 dada[8] = (char) rptq; /* If receiving, agree */
4926 else /* by replying with same character. */
4927 dada[8] = (char) (rptq = myrptq); /* When sending use this. */
4928 } else dada[8] = SP; /* Not enabled, put a space here. */
4940 dada[9] = (char) tochar((lscapr ? lscapb : 0) | /* Locking shifts */
4941 (atcapr ? atcapb : 0) | /* Attribute packets */
4942 (lpcapr ? lpcapb : 0) | /* Long packets */
4943 (swcapr ? swcapb : 0) | /* Sliding windows */
4944 (rscapr ? rscapb : 0)); /* RESEND */
4945 if (max < 10) { wslotr = 1; return(dada); }
4946 dada[10] = (char) tochar(swcapr ? wslotr : 1); /* CAPAS+1 = Window size */
4948 if (max < 12) { rpsiz = 80; return(dada); }
4950 rpsiz = urpsiz - 1; /* Long packets ... */
4951 dada[11] = (char) tochar(rpsiz / 95); /* Long packet size, big part */
4952 dada[12] = (char) tochar(rpsiz % 95); /* Long packet size, little part */
4954 if (max < 16) return(dada);
4955 dada[13] = '0'; /* CAPAS+4 = WONT CHKPNT */
4956 dada[14] = '_'; /* CAPAS+5 = CHKINT (reserved) */
4957 dada[15] = '_'; /* CAPAS+6 = CHKINT (reserved) */
4958 dada[16] = '_'; /* CAPAS+7 = CHKINT (reserved) */
4959 if (max < 17) return(dada);
4964 if (server) x |= WMI_SERVE; /* Whether I am a server */
4965 if (binary) x |= WMI_FMODE; /* My file transfer mode is ... */
4966 if (fncnv) x |= WMI_FNAME; /* My filename conversion is ... */
4968 if (streamrq == SET_ON)
4970 else if (streamrq == SET_AUTO && reliable == SET_ON)
4973 Always offer to stream when in remote mode and STREAMING is AUTO
4974 and RELIABLE is not OFF (i.e. is ON or AUTO).
4976 else if (!local && streamrq == SET_AUTO && reliable != SET_OFF)
4978 #endif /* STREAMING */
4980 if (clearrq == SET_ON)
4982 else if (clearrq == SET_AUTO && /* SET CLEAR-CHANNEL AUTO */
4983 ((network && nettype == NET_TCPB /* TCP/IP */
4985 && ttnproto != NP_RLOGIN/* Rlogin is not clear */
4986 && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN)
4987 #endif /* RLOGCODE */
4990 || (network && nettype == NET_SSH)
4991 #endif /* SSHBUILTIN */
4993 || inserver /* We are IKSD */
4997 #endif /* TCPSOCKET */
4999 dada[17] = (char) tochar(x);
5000 #endif /* WHATAMI */
5001 i = 18; /* Position of next field */
5002 p = cksysid; /* WHOAMI (my system ID) */
5004 if (max - i < x + 1) return(dada);
5006 dada[i++] = (char) tochar(x);
5011 if (max < i+1) return(dada);
5012 #ifndef WHATAMI /* WHATAMI2 */
5015 debug(F101,"rpar xfermode","",xfermode);
5016 x = WMI2_FLAG; /* Is-Valid flag */
5017 if (xfermode != XMODE_A) /* If TRANSFER MODE is MANUAL */
5018 x |= WMI2_XMODE; /* set the XFERMODE bit */
5019 if (recursive > 0) /* If this is a recursive transfer */
5020 x |= WMI2_RECU; /* set the RECURSIVE bit */
5021 dada[i++] = tochar(x);
5022 debug(F101,"rpar whatami2","",x);
5023 #endif /* WHATAMI */
5025 dada[i] = '\0'; /* Terminate the init string */
5029 debug(F110,"rpar",dada,0);
5030 rdebu(dada,(int)strlen((char *)dada));
5033 ckstrncpy((char *)myinit,(char *)dada,MYINITLEN);
5034 return(dada); /* Return pointer to string. */
5038 spar(s) CHAR *s; { /* Set parameters */
5039 int x, y, lpsiz, biggest;
5040 extern int rprmlen, lastspmax;
5041 extern struct sysdata sysidlist[];
5048 #endif /* STREAMING */
5051 debug(F101, "spar biggest 1","",biggest);
5052 debug(F101, "spar rprmlen","",rprmlen);
5053 if (rprmlen > 1 && rprmlen < biggest)
5055 debug(F101, "rpar biggest 2","",biggest);
5056 debug(F110,"spar packet",s,0);
5058 s--; /* Line up with field numbers. */
5060 /* Limit on size of outbound packets */
5061 x = (biggest >= 1) ? xunchar(s[1]) : 80;
5062 lpsiz = spsizr; /* Remember what they SET. */
5063 if (spsizf) { /* SET-command override? */
5064 if (x < spsizr) spsiz = x; /* Ignore LEN unless smaller */
5065 } else { /* otherwise */
5066 spsiz = (x < 10) ? 80 : x; /* believe them if reasonable */
5068 spmax = spsiz; /* Remember maximum size */
5070 /* Timeout on inbound packets */
5072 timint = rtimo; /* SET SEND TIMEOUT value overrides */
5073 } else { /* Otherwise use requested value, */
5074 x = (biggest >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */
5075 timint = (x < 0) ? rtimo : x;
5077 timint = chktimo(timint,timef); /* Adjust if necessary */
5079 /* Outbound Padding */
5080 npad = 0; padch = '\0';
5082 npad = xunchar(s[3]);
5083 if (biggest >= 4) padch = (CHAR) ctl(s[4]); else padch = 0;
5087 for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
5090 /* Outbound Packet Terminator */
5091 seol = (CHAR) (biggest >= 5) ? xunchar(s[5]) : CR;
5092 if ((seol < 1) || (seol > 31)) seol = CR;
5094 /* Control prefix that the other Kermit is sending */
5095 x = (biggest >= 6) ? s[6] : '#';
5096 ctlq = (CHAR) (((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#');
5098 /* 8th-bit prefix */
5100 NOTE: Maybe this could be simplified using rcvtyp.
5101 If rcvtyp == 'Y' then we're reading the ACK,
5102 otherwise we're reading the other Kermit's initial bid.
5103 But his horrendous code has been working OK for years, so...
5105 rq = (biggest >= 7) ? s[7] : 0;
5106 if (rq == 'Y') rqf = 1;
5107 else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
5109 debug(F000,"spar 8bq rq","",rq);
5110 debug(F000,"spar 8bq sq","",sq);
5111 debug(F000,"spar 8bq ebq","",ebq);
5112 debug(F101,"spar 8bq rqf","",rqf);
5114 case 0: /* Field is missing from packet. */
5115 ebqflg = 0; /* So no 8th-bit prefixing. */
5117 case 1: /* Other Kermit sent 'Y' = Will Do. */
5119 When I am the file receiver, ebqsent is 0 because I didn't send a
5120 negotiation yet. If my parity is set to anything other than NONE,
5121 either because my user SET PARITY or because I detected parity bits
5122 on this packet, I reply with '&', otherwise 'Y'.
5124 When I am the file sender, ebqsent is what I just sent in rpar(),
5125 which can be 'Y', 'N', or '&'. If I sent '&', then this 'Y' means
5126 the other Kermit agrees to do 8th-bit prefixing.
5128 If I sent 'Y' or 'N', but then detected parity on the ACK packet
5129 that came back, then it's too late: there is no longer any way for
5130 me to tell the other Kermit that I want to do 8th-bit prefixing, so
5131 I must not do it, and in that case, if there is any 8-bit data in
5132 the file to be transferred, the transfer will fail because of block
5135 The following clause covers all of these situations:
5137 if (parity && (ebqsent == 0 || ebqsent == '&')) {
5142 case 2: /* Other Kermit sent a valid prefix */
5143 ebqflg = (ebq == sq || sq == 'Y');
5146 debug(F101,"spar setting parity to space","",ebq);
5147 if (!parity) parity = ttprty = 's';
5150 if (lscapu == 2) { /* But no single-shifts if LOCKING-SHIFT FORCED */
5158 if (s[8] == 'B') x = 4;
5159 else x = s[8] - '0';
5160 if ((x < 1) || (x > 4)) x = 1;
5166 rptflg = 0; /* Assume no repeat-counts */
5167 if (biggest >= 9) { /* Is there a repeat-count field? */
5169 t = s[9]; /* Get its contents. */
5171 If I'm sending files, then I'm reading these parameters from an ACK, and so
5172 this character must agree with what I sent.
5174 if (rptena) { /* If enabled ... */
5175 if ((char) rcvtyp == 'Y') { /* Sending files, reading ACK. */
5176 if (t == myrptq) rptflg = 1;
5177 } else { /* I'm receiving files */
5178 if ((t > 32 && t < 63) || (t > 95 && t < 127)) {
5188 atcapu = lpcapu = swcapu = rscapu = 0; /* Assume none of these. */
5189 if (lscapu != 2) lscapu = 0; /* Assume no LS unless forced. */
5190 y = 11; /* Position of next field, if any */
5191 if (biggest >= 10) {
5193 debug(F101,"spar capas","",x);
5194 atcapu = (x & atcapb) && atcapr; /* Attributes */
5195 lpcapu = (x & lpcapb) && lpcapr; /* Long packets */
5196 swcapu = (x & swcapb) && swcapr; /* Sliding windows */
5197 rscapu = (x & rscapb) && rscapr; /* RESEND */
5198 debug(F101,"spar lscapu","",lscapu);
5199 debug(F101,"spar lscapr","",lscapr);
5200 debug(F101,"spar ebqflg","",ebqflg);
5201 if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0;
5202 debug(F101,"spar swcapr","",swcapr);
5203 debug(F101,"spar swcapu","",swcapu);
5204 debug(F101,"spar lscapu","",lscapu);
5205 for (y = 10; (xunchar(s[y]) & 1) && (biggest >= y); y++);
5206 debug(F101,"spar y","",y);
5210 debug(F101,"spar lpcapu","",lpcapu);
5212 if (biggest > y+1) {
5213 x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
5214 debug(F101,"spar lp len","",x);
5215 if (spsizf) { /* If overriding negotiations */
5216 spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
5217 } else { /* otherwise */
5218 spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
5220 if (spsiz < 10) spsiz = 80; /* Be defensive... */
5223 /* (PWP) save current send packet size for optimal packet size calcs */
5224 spmax = spsiz; /* Maximum negotiated length */
5225 lastspmax = spsiz; /* For stats */
5226 if (slostart && spsiz > 499) /* Slow start length */
5228 debug(F101,"spar slow-start spsiz","",spsiz);
5229 debug(F101,"spar lp spmax","",spmax);
5230 timint = chktimo(timint,timef); /* Recalculate the packet timeout */
5232 /* Sliding Windows... */
5234 if (swcapr) { /* Only if requested... */
5235 if (biggest > y) { /* See what other Kermit says */
5236 x = xunchar(s[y+1]);
5237 debug(F101,"spar window","",x);
5238 wslotn = (x > MAXWS) ? MAXWS : x;
5240 wslotn = negotiated size (from other Kermit's S or I packet).
5241 wslotr = requested window size (from this Kermit's SET WINDOW command).
5243 if (wslotn > wslotr) /* Use the smaller of the two */
5245 if (wslotn < 1) /* Watch out for bad negotiation */
5248 swcapu = 1; /* We do windows... */
5249 if (wslotn > maxtry) /* Retry limit must be greater */
5250 maxtry = wslotn + 1; /* than window size. */
5252 debug(F101,"spar window after adjustment","",x);
5253 } else { /* No window size specified. */
5254 wslotn = 1; /* We don't do windows... */
5255 debug(F101,"spar window","",x);
5257 debug(F101,"spar no windows","",wslotn);
5261 /* Now recalculate packet length based on number of windows. */
5262 /* The nogotiated number of window slots will be allocated, */
5263 /* and the maximum packet length will be reduced if necessary, */
5264 /* so that a windowful of packets can fit in the big buffer. */
5266 if (wslotn > 1) { /* Shrink to fit... */
5267 x = adjpkl(spmax,wslotn,bigsbsiz);
5271 if (slostart && spsiz > 499) spsiz = 244; /* Slow start again */
5272 debug(F101,"spar sending, redefine spmax","",spmax);
5276 debug(F101,"spar biggest","",biggest);
5277 if (biggest > y+7) { /* Get WHATAMI info if any */
5278 whatru = xunchar(s[y+8]);
5279 debug(F101,"spar whatru","",whatru);
5281 if (whatru & WMI_FLAG) { /* Only valid if this bit is set */
5283 if (whatru & WMI_STREAM) {
5284 if (streamrq == SET_ON ||
5285 (streamrq == SET_AUTO &&
5286 (reliable == SET_ON || (reliable == SET_AUTO && !local)
5289 #endif /* TN_COMPORT */
5294 streamok = 1; /* Streaming negotiated */
5295 slostart = 0; /* Undo slow-start machinations */
5299 streamed = streamok;
5300 debug(F101,"spar streamok","",streamok);
5301 debug(F101,"spar clearrq","",clearrq);
5302 if (clearrq == SET_ON ||
5303 (clearrq == SET_AUTO &&
5304 ((network && nettype == NET_TCPB
5306 && ttnproto != NP_RLOGIN/* Rlogin is not clear */
5307 && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN)
5308 #endif /* RLOGCODE */
5311 #endif /* TN_COMPORT */
5314 || (network && nettype == NET_SSH)
5315 #endif /* SSHBUILTIN */
5320 urclear = (whatru & WMI_CLEAR);
5321 debug(F101,"spar urclear","",urclear);
5325 #endif /* CK_SPEED */
5327 #endif /* STREAMING */
5329 #endif /* WHATAMI */
5331 if (biggest > y+8) { /* Get WHOAREYOU info if any */
5333 x = xunchar(s[y+9]); /* Length of it */
5336 debug(F101,"spar sysindex x","",x);
5337 debug(F101,"spar sysindex y","",y);
5338 debug(F101,"spar sysindex biggest","",biggest);
5340 if (x > 0 && x < 16 && biggest >= y) {
5341 strncpy(whoareu,(char *)s+z+10,x); /* Other Kermit's system ID */
5342 debug(F111,"spar whoareyou",whoareu,whoareu[0]);
5343 if (whoareu[0]) { /* Got one? */
5344 sysindex = getsysix((char *)whoareu);
5345 debug(F101,"spar sysindex",whoareu,sysindex);
5352 y++; /* Advance pointer */
5354 whatru2 = xunchar(s[y]); /* Next field is WHATAMI2 */
5355 debug(F101,"spar whatru2","",whatru2);
5356 if (whatru2 & WMI2_FLAG) { /* Valid only if this bit is set */
5357 if (server) { /* Server obeys client's xfer mode */
5358 xfermode = (whatru2 & WMI2_XMODE) ? XMODE_M : XMODE_A;
5359 debug(F101,"spar whatru2 xfermode","",xfermode);
5361 if (whatru2 & WMI2_RECU) { /* RECURSIVE transfer */
5362 if (fnrpath == PATH_AUTO) { /* If REC PATH AUTO */
5363 fnrpath = PATH_REL; /* Set it to RELATIVE */
5364 autopath = 1; /* and remember we did this */
5369 #endif /* WHATAMI */
5372 if (sysindex > -1) {
5374 p = sysidlist[sysindex].sid_name;
5375 tlog(F110,"Remote system type: ",p,0L);
5376 if (sysindex > 0) { /* If partnet's system type known */
5377 whoarewe(); /* see if we are a match. */
5379 /* Never unprefix XON and XOFF when sending to VMS */
5380 debug(F111,"proto whoareu",whoareu,sysindex);
5381 if (!strcmp((char *)whoareu,"D7")) {
5382 debug(F111,"proto special VMS prefixing","",0);
5383 ctlp[XON] = ctlp[XOFF] = 1;
5384 ctlp[XON+128] = ctlp[XOFF+128] = 1;
5385 ctlp[3] = 1; /* Ctrl-C might be dangerous too */
5386 ctlp[14] = ctlp[15] = 1; /* And SO/SI */
5387 ctlp[24] = ctlp[25] = 1; /* And ^X/^Y */
5388 ctlp[141] = 1; /* And CR+128 */
5390 #endif /* CK_SPEED */
5394 /* Record parameters in debug log */
5396 if (deblog) sdebu(biggest);
5398 numerrs = 0; /* Start counting errors here. */
5402 /* G N F I L E -- Get name of next file to send */
5404 Expects global sndsrc to be:
5405 -9: if we are generating a file internally for calibration.
5406 -1: next filename to be obtained by calling znext().
5407 0: no next file name
5408 1: (or greater) next filename to be obtained from **cmlist,
5409 or if addlist != 0, from the "filehead" linked list,
5410 or if filefile pointer not null from that file (which is already open).
5412 1, with name of next file in filnam.
5413 0, no more files, with filnam set to empty string.
5415 -2, file is not readable (but then we just skip to the next one if any)
5416 -3, read access denied
5418 -5, too many files match wildcard
5419 -6, no files selected
5421 If gnfile() returns 0, then the global variable gnferror should be checked
5422 to find out the most recent gnfile() error, and use that instead of the
5423 return code (for reasons to hard to explain).
5427 int i = 0, x = 0; long y = 0L;
5431 char fullname[CKMAXPATH+1];
5433 dodirstoo = ((what & (W_FTP|W_SEND)) == (W_FTP|W_SEND)) && recursive;
5435 debug(F101,"gnfile sndsrc","",sndsrc);
5436 debug(F101,"gnfile filcnt","",filcnt);
5437 debug(F101,"gnfile what","",what);
5438 debug(F101,"gnfile recursive","",recursive);
5439 debug(F101,"gnfile dodirstoo","",dodirstoo);
5441 fsize = -1L; /* Initialize file size */
5443 if (!(what & W_REMO) && (xfermode == XMODE_A)
5446 #endif /* NOMSEND */
5449 if (!stdinf) /* Not if sending from stdin */
5451 /* We don't do this in server mode because it undoes WHATAMI */
5452 if (!server || (server && ((whatru & WMI_FLAG) == 0)))
5453 #endif /* WHATAMI */
5454 binary = gnf_binary; /* Restore prevailing transfer mode */
5455 debug(F101,"gnfile binary = gnf_binary","",gnf_binary);
5458 debug(F101,"gnfile pipesend","",pipesend);
5459 if (pipesend) { /* First one */
5461 ckstrncpy(filnam,cmarg,CKMAXPATH+1);
5463 } else { /* There's only one... */
5469 #endif /* PIPESEND */
5473 debug(F100,"gnfile calibrate","",0);
5474 ckstrncpy(filnam,"CALIBRATION",CKMAXPATH);
5478 sndsrc = 0; /* For next time */
5482 #endif /* CALIBRATE */
5485 if (sndarray) { /* Sending from an array */
5486 extern char sndxnam[]; /* Pseudo filename */
5487 debug(F100,"gnfile array","",0);
5489 fsize = -1L; /* Size unknown */
5491 ckstrncpy(filnam,sndxnam,CKMAXPATH);
5496 if (sndsrc == 0) { /* It's not really a file */
5497 if (nfils > 0) { /* It's a pipe, or stdin */
5498 ckstrncpy(filnam,*cmlist,CKMAXPATH+1); /* Copy its "name" */
5499 nfils = 0; /* There is no next file */
5500 return(1); /* OK this time */
5501 } else return(0); /* but not next time */
5504 /* If file group interruption (C-Z) occurred, fail. */
5507 tlog(F100,"Transaction cancelled","",0L);
5508 debug(F100,"gnfile czseen","",0);
5512 /* Loop through file list till we find a readable, sendable file */
5514 y = -1L; /* Loop exit (file size) variable */
5515 while (y < 0L) { /* Keep trying till we get one... */
5517 if (sndsrc > 0) { /* File list in cmlist or file */
5518 if (filefile) { /* Reading list from file... */
5519 if (zsinl(ZMFILE,filnam,CKMAXPATH) < 0) { /* Read a line */
5520 zclose(ZMFILE); /* Failed */
5521 debug(F110,"gnfile filefile EOF",filefile,0);
5522 makestr(&filefile,NULL);
5525 debug(F110,"gnfile filefile filnam",filnam,0);
5527 debug(F101,"gnfile nfils","",nfils);
5528 if (nfils-- > 0 || filefile) { /* Still some left? */
5531 if (filenext && filenext->fl_name) {
5532 ckstrncpy(filnam,filenext->fl_name,CKMAXPATH+1);
5534 filenext->fl_alias ?
5535 filenext->fl_alias :
5537 binary = filenext->fl_mode;
5539 printf("?Internal error expanding ADD list\n");
5542 filenext = filenext->fl_next;
5543 debug(F111,"gnfile addlist filnam",filnam,nfils);
5544 } else if (sndsrc > 0 && !filefile) {
5545 #endif /* NOMSEND */
5546 ckstrncpy(filnam,*cmlist++,CKMAXPATH+1);
5547 debug(F111,"gnfile cmlist filnam",filnam,nfils);
5550 #endif /* NOMSEND */
5553 debug(F101,"gnfile ngetpath","",ngetpath);
5554 #endif /* NOSERVER */
5558 if (server && !isabsolute(filnam) && (ngetpath > i)) {
5559 ckstrncpy(fullname,getpath[i],CKMAXPATH+1);
5560 strncat(fullname,filnam,CKMAXPATH);
5561 debug(F111,"gnfile getpath",fullname,i);
5568 #endif /* NOSERVER */
5569 ckstrncpy(fullname,filnam,CKMAXPATH+1);
5570 debug(F110,"gnfile absolute",fullname,0);
5573 #endif /* NOSERVER */
5574 if (iswild(fullname)
5576 || recursive > 0 || !strcmp(fullname,".")
5577 #endif /* RECURSIVE */
5578 ) { /* It looks wild... */
5579 /* First check if a file with this name exists */
5580 debug(F110,"gnfile wild",fullname,0);
5581 if (zchki(fullname) > -1) {
5583 Here we have a file whose name actually
5584 contains wildcard characters.
5589 nzxopts = ZX_FILONLY; /* (was 0: 25 Jul 2001 fdc) */
5591 nzxopts = recursive ? 0 : ZX_FILONLY; /* 30 Jul 2001 */
5592 #endif /* COMMENT */
5593 if (nolinks) nzxopts |= ZX_NOLINKS; /* (26 Jul 2001 fdc) */
5595 if (matchdot) nzxopts |= ZX_MATCHDOT;
5596 #endif /* UNIXOROSK */
5597 if (recursive) nzxopts |= ZX_RECURSE;
5598 x = nzxpand(fullname,nzxopts); /* Expand wildcards */
5599 debug(F101,"gnfile nzxpand","",x);
5602 xx = znext(fullname);
5603 debug(F111,"gnfile znext A",fullname,xx);
5606 if (x == 0) { /* None match */
5608 if (server && ngetpath > i)
5610 #endif /* NOSERVER */
5612 debug(F101,"gnfile gnferror A","",gnferror);
5616 if (x < 0) { /* Too many to expand */
5617 debug(F101,"gnfile gnferror B","",gnferror);
5621 sndsrc = -1; /* Change send-source to znext() */
5623 } else { /* We're out of files. */
5624 debug(F111,"gnfile done",ckitoa(gnferror),nfils);
5630 /* Otherwise, step to next element of internal wildcard expansion list. */
5635 debug(F111,"gnfile znext X",filnam,xx);
5637 debug(F111,"gnfile znext B",filnam,xx);
5641 debug(F111,"gnfile FTP MPUT /RECURSIVE",filnam,xx);
5647 debug(F111,"gnfile znext C",filnam,x);
5648 if (!filnam[0]) { /* If no more, */
5649 sndsrc = 1; /* go back to previous list */
5650 debug(F101,"gnfile setting sndsrc back","",sndsrc);
5653 ckstrncpy(fullname,filnam,CKMAXPATH+1);
5656 /* Get here with a filename. */
5659 debug(F110,"gnfile fullname",fullname,0);
5663 if (fullname[0] == '~') {
5664 dirp = tilde_expand((char *)fullname);
5665 if (*dirp) ckstrncpy(fullname,dirp,CKMAXPATH+1);
5668 y = zchki(fullname); /* Check if file readable */
5669 debug(F111,"gnfile zchki",fullname,y);
5670 retcode = (int) y; /* Possible return code */
5671 if (y == -2L && dodirstoo) {
5676 debug(F101,"gnfile gnferror C","",gnferror);
5678 if (y == -1L) { /* If not found */
5679 debug(F100,"gnfile -1","",0);
5681 if (server && ngetpath > i)
5683 #endif /* NOSERVER */
5684 debug(F110,"gnfile skipping:",fullname,0);
5685 tlog(F110,fullname,": open failure - skipped",0);
5686 xxscreen(SCR_FN,0,0l,fullname);
5687 xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname);
5689 if (tralog && !tlogfmt)
5690 doxlog(what,fullname,fsize,binary,1,"Skipped");
5694 if (y == -3) { /* Exists but not readable */
5695 debug(F100,"gnfile -3","",0);
5696 filrej++; /* Count this one as not sent */
5697 tlog(F110,"Read access denied",fullname,0); /* Log this */
5698 xxscreen(SCR_FN,0,0l,fullname);
5699 xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname); /* Display it */
5701 if (tralog && !tlogfmt)
5702 doxlog(what,fullname,fsize,binary,1,"Skipped");
5709 xx = fileselect(fullname,
5710 sndafter, sndbefore,
5711 sndnafter,sndnbefore,
5712 sndsmaller,sndlarger,
5714 NSNDEXCEPT,sndexcept);
5715 debug(F111,"gnfile fileselect",fullname,xx);
5719 debug(F101,"gnfile gnferror D","",gnferror);
5722 ckstrncpy(filnam,fullname,CKMAXPATH+1);
5726 /* This can't be right! */
5727 } else { /* sndsrc is 0... */
5728 if (!fileselect(fullname,
5729 sndafter, sndbefore,
5730 sndnafter,sndnbefore,
5731 sndsmaller,sndlarger,
5733 NSNDEXCEPT,sndexcept)) {
5735 debug(F111,"gnfile fileselect",fullname,gnferror);
5739 ckstrncpy(filnam,fullname,CKMAXPATH+1);
5741 #endif /* COMMENT */
5744 debug(F101,"gnfile result","",retcode);
5750 The following bunch of routines feed internally generated data to the server
5751 to send to the client in response to REMOTE commands like DIRECTORY, DELETE,
5752 and so on. We have to write these lines in the format appropriate to our
5753 platform, so they can be converted to generic (CRLF) text format by the
5757 char * endline = "\12";
5760 char * endline = "\12";
5763 char * endline = "\15";
5766 char * endline = "\15";
5768 char * endline = "\15\12";
5771 #endif /* datageneral */
5778 #define FNCBUFL (CKMAXPATH + CKMAXPATH + 64)
5780 #define FNCBUFL (CKMAXPATH + 64)
5781 #endif /* CKSYMLINK */
5784 /* NB: The minimum FNCBUFL is 255 */
5786 static CHAR funcbuf[FNCBUFL];
5787 static int funcnxt = 0;
5788 static int funclen = 0;
5789 static int nxpnd = -1;
5790 static long ndirs = 0;
5791 static long nfiles = 0;
5792 static long nbytes = 0;
5795 sndstring(p) char * p; {
5797 nfils = 0; /* No files, no lists. */
5798 xflg = 1; /* Flag we must send X packet. */
5799 ckstrncpy(cmdstr,versio,CMDSTRL); /* Data for X packet. */
5800 first = 1; /* Init getchx lookahead */
5801 memstr = 1; /* Just set the flag. */
5802 memptr = p; /* And the pointer. */
5803 binary = XYFT_T; /* Text mode for this. */
5807 #endif /* NOSERVER */
5810 /* S N D H L P -- Routine to send builtin help */
5812 static int srvhlpnum = 0;
5815 static char *nmx[] = { "Disabled", "Disabled", "Enabled", "Enabled" };
5832 #endif /* CK_ANSIC */
5836 en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai,
5837 en_pri, en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who,
5838 /* en_ret, */ en_mkd, en_rmd, en_asg, en_que, en_xit, x_login, x_logged,
5840 extern char * ckxsys;
5842 if (funcnxt < funclen)
5843 return (funcbuf[funcnxt++]);
5845 switch (srvhlpnum++) {
5847 x = ckstrncpy((char *)funcbuf,
5848 "Client Command Status Description\n",
5851 if (x_login && !x_logged) {
5852 x += ckstrncat((char *)funcbuf,
5853 " REMOTE LOGIN required\n",
5857 if (FNCBUFL - x > 74)
5858 sprintf((char *)(funcbuf+x)," GET %-14s%s\n",
5860 "Transfer file(s) from server to client."
5864 /* NOTE: The minimum funcbuf[] size is 255; all of the following are safe. */
5867 sprintf((char *)funcbuf," SEND %-14s%s\n",
5869 "Transfer file(s) from client to server."
5874 sprintf((char *)funcbuf," MAIL %-14s%s\n",
5875 xnm(inserver ? 0 : en_mai),
5876 "Send file(s) as e-mail."
5882 sprintf((char *)funcbuf," REMOTE ASSIGN %-14s%s\n",
5884 "Assign value to server variable or macro."
5887 sprintf((char *)funcbuf," REMOTE ASSIGN not configured\n");
5892 sprintf((char *)funcbuf," REMOTE CD %-14s%s\n",
5894 "Change server's directory."
5900 sprintf((char *)funcbuf," REMOTE COPY %-14s%s\n",
5902 "Copy a file on the server."
5905 sprintf((char *)funcbuf," REMOTE COPY not configured\n");
5910 sprintf((char *)funcbuf," REMOTE DELETE %-14s%s\n",
5912 "Delete a file on the server."
5917 sprintf((char *)funcbuf," REMOTE DIRECTORY %-14s%s\n",
5919 "List files on the server."
5924 sprintf((char *)funcbuf," REMOTE EXIT %-14s%s\n",
5926 "Exit from Kermit server program."
5931 sprintf((char *)funcbuf," REMOTE HOST %-14s%s\n",
5932 xnm(inserver ? 0 : en_hos),
5934 "Execute a CLI command on the server."
5937 "Execute a DCL command on the server."
5939 "Execute a shell command on the server."
5941 #endif /* datageneral */
5946 sprintf((char *)funcbuf," REMOTE PRINT %-14s%s\n",
5947 xnm(inserver ? 0 : en_pri),
5948 "Send a file to the server for printing."
5954 sprintf((char *)funcbuf," REMOTE QUERY %-14s%s\n",
5956 "Get value of server variable or macro."
5960 sprintf((char *)funcbuf," REMOTE QUERY not configured\n");
5965 sprintf((char *)funcbuf," REMOTE MKDIR %-14s%s\n",
5967 "Create a directory on the server."
5972 sprintf((char *)funcbuf," REMOTE RMDIR %-14s%s\n",
5974 "Remove a directory on the server."
5979 sprintf((char *)funcbuf," REMOTE RENAME %-14s%s\n",
5981 "Rename a file on the server."
5986 sprintf((char *)funcbuf," REMOTE SET %-14s%s\n",
5988 "Set a parameter on the server"
5993 sprintf((char *)funcbuf," REMOTE SPACE %-14s%s\n",
5995 "Inquire about disk space on the server."
6000 sprintf((char *)funcbuf," REMOTE TYPE %-14s%s\n",
6002 "Display a server file on your screen."
6007 sprintf((char *)funcbuf," REMOTE WHO %-14s%s\n",
6008 xnm(inserver ? 0 : en_who),
6009 "List who is logged in to the server."
6014 sprintf((char *)funcbuf," FINISH %-14s%s\n",
6017 "Exit from Kermit server program." :
6018 "Return the server to its command prompt."
6023 sprintf((char *)funcbuf," BYE %-14s%s\n\n",
6025 "Log the server out and disconnect."
6033 funclen = strlen((char *)funcbuf);
6034 return(funcbuf[funcnxt++]);
6040 extern char * ckxsys;
6042 first = 1; /* Init getchx lookahead */
6043 nfils = 0; /* No files, no lists. */
6044 xflg = 1; /* Flag we must send X packet. */
6045 ckstrncpy(cmdstr,"REMOTE HELP",CMDSTRL); /* Data for X packet. */
6046 sprintf((char *)funcbuf, "C-Kermit %s,%s\n\n", versio, ckxsys);
6047 funclen = strlen((char *)funcbuf);
6050 sprintf((char *)(funcbuf+funclen),
6051 "Internet Kermit Service (EXPERIMENTAL)\n\n");
6052 funclen = strlen((char *)funcbuf);
6059 binary = XYFT_T; /* Text mode for this. */
6063 #endif /* NOSERVER */
6067 Returns the next available character,
6074 #endif /* CK_ANSIC */
6077 if (zchin(ZIFILE,&c) < 0) {
6081 return((unsigned)c);
6085 /* S N D T Y P -- TYPE a file to remote client */
6088 sndtype(file) char * file; {
6090 char name[CKMAXPATH+1];
6096 ckstrncpy(name, file, CKMAXPATH+1);
6097 /* change / to \. */
6099 while (*p) { /* Change them back to \ */
6100 if (*p == '/') *p = '\\';
6106 ckstrncpy(name, file, CKMAXPATH+1);
6110 funclen = strlen((char *)funcbuf);
6111 if (zchki(name) == -2) {
6112 /* Found a directory */
6115 if (!zopeni(ZIFILE,name))
6118 nfils = 0; /* No files, no lists. */
6119 xflg = 1; /* Flag we must send X packet. */
6120 ckstrncpy(cmdstr,"type",CMDSTRL); /* Data for X packet. */
6121 first = 1; /* Init getchx lookahead */
6122 funcstr = 1; /* Just set the flag. */
6123 funcptr = nxttype; /* And the pointer. */
6124 binary = XYFT_T; /* Text mode for this */
6128 #endif /* NOSERVER */
6132 N X T D I R -- Provide data for senddir()
6134 Returns the next available character or -1 if no more data.
6137 /* Directory listing parameters set by the user interface, if any. */
6138 extern int dir_head, dir_dots, dir_back;
6140 static int sd_hdg, sd_bkp, sd_dot; /* Local listing parameters */
6146 #endif /* CK_ANSIC */
6148 char name[CKMAXPATH+1], dbuf[24], *p = NULL;
6149 char *dstr = NULL, * lnk = "";
6150 CHAR c, * linebuf = funcbuf;
6152 /* Work around bugs in OSK compiler */
6153 char *dirtag = "directories";
6154 char *filetag = "files";
6155 char *bytetag = "bytes";
6158 int x, itsadir = 0, gotone = 0;
6162 debug(F101,"nxtdir funcnxt","",funcnxt);
6163 debug(F101,"nxtdir funclen","",funclen);
6164 debug(F110,"nxtdir funcbuf",funcbuf+funcnxt,0);
6167 if (funcnxt < funclen) { /* Return next character from buffer */
6168 c = funcbuf[funcnxt++];
6169 debug(F000,"nxtdir return 1","",(unsigned)(c & 0xff));
6170 return((unsigned)(c & 0xff));
6172 while (nxpnd > 0) { /* Buffer needs refill */
6174 znext(name); /* Get next filename */
6175 if (!name[0]) { /* None left - done */
6179 if (sd_bkp) { /* Showing backup files? */
6180 gotone = 1; /* Yes, no need to check. */
6183 x = ckmatch( /* No - see if this is one */
6185 "*.~[0-9]*~" /* Not perfect but close enough. */
6187 "*.~*~" /* Less close. */
6188 #endif /* CKREGEX */
6190 debug(F111,"nxtdir ckmatch",name,x);
6192 continue; /* It's a backup file - skip it */
6194 gotone = 1; /* It's not, break from loop. */
6199 len = zgetfs(name); /* Get file size */
6200 debug(F111,"nxtdir zgetfs",name,len);
6202 itsadir = zgfs_dir; /* See if it's a directory */
6204 itsadir = (len == -2 || isdir(name));
6205 #endif /* VMSORUNIX */
6206 dstr = zfcdat(name);
6207 debug(F111,"nxtdir zcfdat",dstr,0);
6209 dstr = "0000-00-00 00:00:00";
6211 dstr = "0000-00-00 00:00:00";
6223 strcpy(dbuf+10,dstr+8);
6228 p = ziperm(name); /* Get permissions */
6231 #endif /* VMSORUNIX */
6234 #endif /* CK_PERMS */
6235 debug(F110,"domydir perms",p,0);
6238 /* Make name relative */
6239 ckstrncpy(name,zrelname(name,zgtdir()),CKMAXPATH+1);
6252 extern char linkname[];
6255 debug(F111,"nxtdir linkname",lnk,zgfs_link);
6256 #endif /* CKSYMLINK */
6260 The following sprintf's are safe; linebuf is a pointer to funcbuf,
6261 which is 64 bytes larger than CKMAXPATH (or double CKMAXPATH when
6262 symlinks are possible). 64 allows for the fixed-field portions of
6263 the file listing line: permissions, size, and date. CKMAXPATH allows
6264 for the longest possible pathname.
6266 if (itsadir && len < 0) { /* Directory */
6268 sprintf((char *)linebuf,
6269 "%-22s%-10s %s %s\n",p,"<DIR>",dstr,name);
6272 sprintf((char *)linebuf,
6273 "%10s%-10s %s %s\n",p,"<DIR>",dstr,name);
6275 sprintf((char *)linebuf,
6276 "%-10s %s %s\n", "<DIR>", dstr, name);
6278 } else { /* Regular file */
6280 sprintf((char *)linebuf,
6281 "%-22s%10ld %s %s\n", p, len, dstr, name);
6284 sprintf((char *)linebuf,
6285 "%10s%10ld %s %s%s%s\n",
6291 sprintf((char *)linebuf,
6292 "%10ld %s %s%s%s\n",
6300 funclen = strlen((char *)funcbuf);
6301 } else if (sd_hdg && nxpnd == 0) { /* Done, send summary */
6302 char *blankline = ""; /* At beginning of summary */
6304 The idea is to prevent (a) unnecessary multiple blanklines, and (b)
6305 prompt-stomping. Preventing (b) is practically impossible, because it
6306 depends on the client so for now always include that final CRLF.
6308 if (!ndirs || !nbytes || !nfiles)
6309 blankline = endline;
6311 /* Workaround bugs in OS-9 compiler... */
6313 dirtag = "directory";
6318 sprintf((char *)funcbuf,
6319 "%sSummary: %ld %s, %ld %s, %ld %s%s",
6329 sprintf((char *)funcbuf,
6330 "%sSummary: %ld director%s, %ld file%s, %ld byte%s%s",
6333 (ndirs == 1) ? "y" : "ies",
6335 (nfiles == 1) ? "" : "s",
6337 (nbytes == 1) ? "" : "s",
6343 funclen = strlen((char *)funcbuf);
6349 debug(F101,"nxtdir funclen","",funclen);
6351 if (funcnxt < funclen) { /* If we have data to send... */
6352 c = funcbuf[funcnxt++];
6353 debug(F000,"nxtdir return 2","",(unsigned)(c & 0xff));
6354 return((unsigned)(c & 0xff));
6356 return(-1); /* Nothing left, done. */
6359 /* S N D D I R -- send directory listing */
6362 snddir(spec) char * spec; {
6364 char * p = NULL, name[CKMAXPATH+1];
6366 char fnbuf[CKMAXPATH+1];
6368 debug(F111,"snddir matchdot",spec,matchdot);
6371 debug(F111,"snddir dir_dots",spec,dir_dots);
6372 sd_hdg = dir_head > 0; /* Import listing parameters if any */
6373 sd_bkp = dir_back > 0;
6379 sd_hdg = 1; /* Or use hardwired defaults */
6384 if (!spec) spec = "";
6385 debug(F111,"snddir sd_dot",spec,sd_dot);
6388 zfnqfp(spec,CKMAXPATH,name);
6389 debug(F110,"snddir zfnqfp",name,0);
6391 ckstrncpy(name,spec,CKMAXPATH+1);
6392 debug(F110,"snddir name",name,0);
6393 #endif /* COMMENT */
6399 strcpy(name, "./*");
6402 strcpy(name, "*.*");
6407 debug(F101,"snddir quit (no filespec)","",0);
6409 #endif /* datageneral */
6414 debug(F110,"snddir name 1",name,0);
6419 if (zfnqfp(name,CKMAXPATH,fnbuf))
6421 debug(F110,"snddir name 2",name,0);
6422 p = name + strlen(name); /* Move it to end of list */
6424 /* sprintf safe because funcbuf size >= max path len + 64 */
6427 sprintf((char *)funcbuf,"Listing files: %s%s%s",fnbuf,endline,endline);
6429 funclen = strlen((char *)funcbuf);
6434 if (zchki(name) == -2) { /* Found a directory */
6436 if (*p == '\\' || *p == '/')
6437 ckstrncat(name, "*", CKMAXPATH);
6439 ckstrncat(name, ".", CKMAXPATH);
6441 ckstrncat(name, "\\*", CKMAXPATH);
6442 debug(F110,"snddir directory",name,0);
6445 if (!iswild(name) && isdir(name)) {
6449 if (*p == '/') /* So append wildcard to it */
6450 ckstrncat(s, "*", CKMAXPATH);
6452 ckstrncat(s, "/*", CKMAXPATH);
6455 if (*p == ']' || *p == '>' || *p == ':')
6456 ckstrncat(s, "*.*", CKMAXPATH);
6460 ckstrncat(s, "+", CKMAXPATH);
6462 ckstrncat(s, ":+", CKMAXPATH);
6466 ckstrncat(s, "*", CKMAXPATH);
6468 ckstrncat(s, ">*", CKMAXPATH);
6470 #endif /* datageneral */
6472 #endif /* UNIXOROSK */
6473 debug(F110,"snddir directory",name,0);
6480 extern char ** mtchs;
6481 debug(F111,"snddir sd_dot",spec,sd_dot);
6483 nzxopts |= ZX_MATCHDOT;
6485 nzxopts |= ZX_RECURSE;
6486 debug(F111,"snddir nzxopts",spec,nzxopts);
6487 nxpnd = nzxpand(name,nzxopts); /* Get the array of names */
6488 sh_sort(mtchs,NULL,nxpnd,0,0,1); /* Sort the array */
6491 if (recursive) nzxopts |= ZX_RECURSE;
6492 nxpnd = nzxpand(name,nzxopts);
6495 debug(F101,"snddir nzxpand nxpnd","",nxpnd);
6498 nfils = 0; /* No files, no lists. */
6499 xflg = 1; /* Flag we must send X packet. */
6500 if ((int)strlen(name) < CMDSTRL - 11) /* Data for X packet. */
6501 sprintf(cmdstr,"DIRECTORY %s",name); /* safe */
6503 ckstrncpy(cmdstr,"DIRECTORY",CMDSTRL);
6504 first = 1; /* Init getchx lookahead */
6505 funcstr = 1; /* Just set the flag. */
6506 funcptr = nxtdir; /* And the pointer. */
6508 debug(F111,"snddir","sinit()",rc);
6512 #endif /* NOSERVER */
6515 /* N X T D E L -- provide data for delete */
6517 /* Returns the next available character or -1 if no more data */
6523 #endif /* CK_ANSIC */
6525 char name[257], *p = NULL;
6528 if (funcnxt < funclen)
6529 return ((unsigned)funcbuf[funcnxt++]);
6540 /* Find just the name of the file */
6542 for (p = name + strlen(name); p != name && *p != '/' ; p--) ;
6545 /* sprintf's safe because size of funcbuf >= 64 + maxpathlen */
6549 sprintf((char *)funcbuf," %10s: %s%s","skipping",p,endline);
6553 sprintf((char *)funcbuf," %10s: %s%s","deleted",p,endline);
6556 sprintf((char *)funcbuf," directory: %s%s", p, endline);
6558 funclen = strlen((char *)funcbuf);
6561 /* If done processing the expanded entries send a summary statement */
6564 sprintf((char *)funcbuf,
6565 "%s%ld file%s deleted, %ld byte%s freed%s",
6568 (nfiles == 1) ? "" : "s",
6570 (nbytes == 1) ? "" : "s",
6575 funclen = strlen((char *)funcbuf);
6582 /* If we have data to send */
6584 if (funcnxt < funclen)
6585 return ((unsigned)funcbuf[funcnxt++]); /* Return a character */
6587 return(-1); /* No more input */
6590 /* S N D D E L -- Send delete message */
6593 snddel(spec) char * spec; {
6595 char name[CKMAXPATH+1];
6598 #endif /* #ifdef OS2 */
6603 ckstrncpy(name, spec, CKMAXPATH+1);
6606 /* change / to \. */
6608 while (*p) { /* Change them back to \ */
6609 if (*p == '/') *p = '\\';
6614 nfiles = nbytes = 0L;
6615 sprintf((char *)funcbuf,"Deleting \"%s\"%s",name,endline);
6617 funclen = strlen((char *)funcbuf);
6619 nzxopts = ZX_FILONLY; /* Files only */
6621 if (matchdot) nzxopts |= ZX_MATCHDOT;
6622 #endif /* UNIXOROSK */
6624 /* Recursive deleting not supported yet */
6625 if (recursive) nzxopts |= ZX_RECURSE;
6626 #endif /* COMMENT */
6627 nxpnd = nzxpand(name,nzxopts);
6630 nfils = 0; /* No files, no lists. */
6631 xflg = 1; /* Flag we must send X packet. */
6632 ckstrncpy(cmdstr,"REMOTE DELETE",CMDSTRL); /* Data for X packet. */
6633 first = 1; /* Init getchx lookahead */
6634 funcstr = 1; /* Just set the flag. */
6635 funcptr = nxtdel; /* And the pointer. */
6636 binary = XYFT_T; /* Use text mode for this, */
6640 #endif /* NOSERVER */
6644 /* S N D S P A C E -- send disk space message */
6646 sndspace(drive) int drive; {
6648 static char spctext[64];
6649 unsigned long space;
6652 space = zdskspace(drive - 'A' + 1);
6653 if (space > 0 && space < 1024)
6655 " Drive %c: unknown%s",
6661 " Drive %c: %ldK free%s",
6667 space = zdskspace(0);
6668 if (space > 0 && space < 1024)
6669 sprintf(spctext, " Free space: unknown%s", endline);
6671 sprintf(spctext, " Free space: %ldK%s", space / 1024L, endline);
6673 nfils = 0; /* No files, no lists. */
6674 xflg = 1; /* Flag we must send X packet. */
6675 ckstrncpy(cmdstr,"free space",CMDSTRL); /* Data for X packet. */
6676 first = 1; /* Init getchx lookahead */
6677 memstr = 1; /* Just set the flag. */
6678 memptr = spctext; /* And the pointer. */
6679 binary = XYFT_T; /* Text mode for this. */
6683 #endif /* NOSERVER */
6686 /* S N D W H O -- send who message */
6688 sndwho(who) char * who; {
6690 nfils = 0; /* No files, no lists. */
6691 xflg = 1; /* Flag we must send X packet. */
6692 ckstrncpy(cmdstr,"who",CMDSTRL); /* Data for X packet. */
6693 first = 1; /* Init getchx lookahead */
6694 memstr = 1; /* Just set the flag. */
6696 memptr = "\15\12K95 SERVER\15\12"; /* And the pointer. */
6698 memptr = "\15\12K/2 SERVER\15\12";
6700 binary = XYFT_T; /* Use text mode */
6704 #endif /* NOSERVER */
6708 /* C W D -- Change server's working directory */
6711 String passed has first byte as length of directory name, rest of string
6714 1 on success after sending short-form response (ACK with name).
6715 2 on success if a CD Message file is to be sent.
6718 cwd(vdir) char *vdir; {
6721 vdir[xunchar(*vdir) + 1] = '\0'; /* Terminate string with a null */
6723 tlog(F110,"Directory requested: ",dirp,0L);
6724 if (zchdir(dirp)) { /* Try to change */
6725 cdd = zgtdir(); /* Get new working directory. */
6726 debug(F110,"cwd",cdd,0);
6727 if (srvcdmsg) { /* Send orientation file? */
6729 for (i = 0; i < 8; i++) {
6730 if (zchki(cdmsgfile[i]) > -1) {
6731 xxscreen(SCR_CD,0,0l,cdd);
6732 tlog(F110,"Changed directory to",cdd,0L);
6737 encstr((CHAR *)cdd); /* Send short-form reply */
6738 ack1(data); /* containing directory name. */
6739 xxscreen(SCR_CD,0,0l,cdd);
6740 tlog(F110,"Changed directory to",cdd,0L);
6743 debug(F110,"cwd failed",dirp,0);
6744 tlog(F110,"Failed to change directory to",dirp,0L);
6750 /* S Y S C M D -- Do a system command */
6752 /* Command string is formed by concatenating the two arguments. */
6755 syscmd(prefix,suffix) char *prefix, *suffix; {
6756 extern int i_isopen;
6765 for (cp = cmdstr; *prefix != '\0'; (*cp++ = *prefix++));
6766 while ((*cp++ = *suffix++))
6768 /* This takes away more than we gain in convenience
6769 if (*(cp-1) == '/') *(cp-1) = '\\' */
6773 debug(F110,"syscmd",cmdstr,0);
6775 if (zxcmd(ZIFILE,cmdstr) > 0) {
6776 debug(F110,"syscmd zxcmd ok",cmdstr,0);
6777 nfils = sndsrc = 0; /* Flag that input is from stdin */
6778 xflg = hcflg = 1; /* And special flags for pipe */
6779 binary = XYFT_T; /* Go to text mode */
6781 return (sinit()); /* Send S packet */
6783 debug(F100,"syscmd zxcmd failed",cmdstr,0);
6788 debug(F100,"syscmd zxcmd NOPUSH",cmdstr,0);
6794 /* R E M S E T -- Remote Set */
6795 /* Called by server to set variables as commanded in REMOTE SET packets. */
6796 /* Returns 1 on success, 0 on failure. */
6799 remset(s) char *s; {
6800 extern int c_save, en_del;
6804 len = xunchar(*s++); /* Length of first field */
6805 p = s + len; /* Pointer to second length field */
6806 *p++ = '\0'; /* Zero out second length field */
6807 x = atoi(s); /* Value of first field */
6808 debug(F111,"remset",s,x);
6809 debug(F110,"remset",p,0);
6810 switch (x) { /* Do the right thing */
6811 case 132: /* Attributes (all, in) */
6814 case 133: /* File length attributes */
6815 case 233: /* IN/OUT combined */
6816 case 148: /* Both kinds of lengths */
6818 atleni = atleno = atoi(p);
6820 case 134: /* File Type (text/binary) */
6822 attypi = attypo = atoi(p);
6824 case 135: /* File creation date */
6826 atdati = atdato = atoi(p);
6828 case 139: /* File Blocksize */
6830 atblki = atblko = atoi(p);
6832 case 141: /* Encoding / Character Set */
6834 atenci = atenco = atoi(p);
6836 case 142: /* Disposition */
6838 atdisi = atdiso = atoi(p);
6840 case 145: /* System ID */
6842 atsidi = atsido = atoi(p);
6844 case 147: /* System-Dependent Info */
6846 atsysi = atsyso = atoi(p);
6848 case 232: /* Attributes (all, out) */
6851 case 300: /* File type (text, binary) */
6858 case 301: /* File name conversion */
6859 fncnv = 1 - atoi(p); /* (oops) */
6865 case 302: /* File name collision */
6868 if (inserver && isguest) /* May not be changed by guest */
6870 #endif /* CK_LOGIN */
6873 if (!ENABLED(en_del) && (x == XYFX_X || x == XYFX_U))
6875 if (x == XYFX_R) ckwarn = 1; /* Rename */
6876 if (x == XYFX_X) ckwarn = 0; /* Replace */
6879 case 310: /* Incomplete File Disposition */
6880 keep = atoi(p); /* Keep, Discard, Auto */
6882 case 311: /* Blocksize */
6885 case 312: /* Record Length */
6888 case 313: /* Record format */
6891 case 314: /* File organization */
6894 case 315: /* File carriage control */
6897 case 330: /* Match dotfiles */
6899 dir_dots = -1; /* This undoes DIR /DOT option */
6903 case 331: /* Match FIFOs */
6904 matchfifo = atoi(p);
6906 case 400: /* Block check */
6908 if (y < 5 && y > 0) {
6912 } else if (*p == 'B') {
6918 case 401: /* Receive packet-length */
6919 rpsiz = urpsiz = atoi(p);
6920 if (urpsiz > MAXRP) urpsiz = MAXRP; /* Max long-packet length */
6921 if (rpsiz > 94) rpsiz = 94; /* Max short-packet length */
6922 urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
6924 case 402: /* Receive timeout */
6925 y = atoi(p); /* Client is telling us */
6926 if (y > -1 && y < 999) { /* the timeout that it wants */
6927 pkttim = chktimo(y,timef); /* us to tell it to use. */
6930 case 403: /* Retry limit */
6932 if (y > -1 && y < 95) {
6936 case 404: /* Server timeout */
6938 if (y < 0) return(0);
6943 case 405: { /* Transfer character set */
6944 extern int s_cset, axcset[];
6946 for (i = 0; i < ntcsets; i++) {
6947 if (!strcmp(tcsinfo[i].designator,p)) break;
6949 debug(F101,"remset tcharset lookup","",i);
6950 if (i == ntcsets) return(0);
6951 tcharset = tcsinfo[i].code; /* If known, use it */
6952 debug(F101,"remset tcharset","",tcharset);
6953 if (s_cset == XMODE_A)
6954 if (axcset[tcharset] > -1 && axcset[tcharset] > MAXFCSETS)
6955 fcharset = axcset[tcharset]; /* Auto-pick file charset */
6956 debug(F101,"remset tcharset fcharset","",fcharset);
6957 setxlatype(tcharset,fcharset); /* Set up charset translations */
6958 debug(F101,"remset xlatype","",xlatype);
6959 debug(F101,"remset tcharset after setxlatype","",tcharset);
6963 case 320: { /* File character set */
6964 extern struct keytab fcstab[];
6965 extern int nfilc, s_cset, r_cset;
6966 x = lookup(fcstab,p,nfilc,&y);
6967 debug(F111,"RSET FILE CHAR name",p,x);
6970 s_cset = XMODE_M; /* No automatic charset switching */
6972 fcharset = x; /* Set file charset */
6973 setxlatype(tcharset,fcharset); /* and translation type */
6977 #endif /* NOCSETS */
6979 case 406: /* Window slots */
6982 if (y < 1 || y > MAXWS) return(0);
6985 urpsiz = adjpkl(urpsiz,wslotr,bigrbsiz);
6988 case 410: /* Transfer mode */
6989 y = atoi(p); /* 0 = automatic, nonzero = manual */
6992 debug(F101,"REMOTE SET xfermode","",xfermode);
6995 case 420: /* SERVER CD-MESSAGE { ON, OFF } */
6996 y = atoi(p); /* 0 = automatic, nonzero = manual */
7000 default: /* Anything else... */
7005 /* Adjust packet length based on number of window slots and buffer size */
7008 adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
7009 if (protocol != PROTO_K) return(pktlen);
7010 debug(F101,"adjpkl len","",pktlen);
7011 debug(F101,"adjpkl slots","",slots);
7012 debug(F101,"adjpkl bufsiz","",bufsiz);
7013 if (((pktlen + 6) * slots) > bufsiz)
7014 pktlen = (bufsiz / slots) - 6;
7015 debug(F101,"adjpkl new len","",pktlen);
7019 /* Set transfer mode and file naming based on comparison of system types */
7025 extern int g_xfermode;
7030 debug(F101,"whoarewe xfermode","",xfermode);
7032 debug(F101,"whoarewe g_xfermode","",g_xfermode);
7034 if (whoareu[0]) { /* If we know partner's system type */
7035 char * p = (char *)whoareu;
7036 debug(F110,"whoarewe remote sysid",whoareu,0);
7037 if (!strcmp(p,cksysid)) /* Other system same as us */
7041 else if (!strcmp(p,"L3")) /* UNIX is sort of like AmigaDOS */
7042 wearealike = 1; /* (same directory separator) */
7043 else if (!strcmp(p,"N3")) /* UNIX like Aegis */
7047 /* Like UNIX, but case distinctions are ignored and can begin with device:. */
7048 else if (!strcmp(p,"U1")) /* Amiga is sort of like UNIX */
7050 else if (!strcmp(p,"N3")) /* Amiga is sort of like Aegis */
7053 #ifdef OS2 /* (Includes Windows 95/NT) */
7055 /* DOS, GEMDOS, Windows 3.x, Windows 95, Windows NT */
7056 /* All "the same" for FAT partitions but all bets off otherwise */
7057 /* so this part needs some refinement ... */
7059 else if (!strcmp(p,"U8")) /* MS-DOS */
7061 else if (!strcmp(p,"UO")) /* OS/2 */
7063 else if (!strcmp(p,"UN")) /* Windows NT or 95 */
7065 else if (!strcmp(p,"K2")) /* GEMDOS */
7069 else if (!strcmp(p,"U8"))
7071 else if (!strcmp(p,"UO"))
7073 else if (!strcmp(p,"UN"))
7075 else if (!strcmp(p,"K2"))
7082 /* Get here with wearealike == 1 if system types match */
7084 debug(F101,"whoarewe wearealike","",wearealike);
7085 if (!wearealike) /* Not alike */
7088 fncnv = XYFN_L; /* Alike, so literal filenames */
7089 debug(F101,"whoarewe setting fncnv","",fncnv);
7091 if (xfermode == XMODE_A) { /* Current xfer mode is auto */
7093 binary = XYFT_L; /* For VMS-to-VMS, use labeled */
7096 /* OS/2 but not Windows */
7097 if (!strcmp(cksysid,"UO") && !strcmp((char *)whoareu,"UO"))
7098 binary = XYFT_L; /* For OS/2-to-OS/2, use labeled */
7100 binary = XYFT_B; /* For all others use binary */
7103 gnf_binary = binary; /* Prevailing type for gnfile() */
7104 debug(F101,"whoarewe setting binary","",binary);