1 char *fnsv = "C-Kermit functions, 9.0.235, 8 October 2020";
2 
3 char *nm[] =  { "Disabled", "Local only", "Remote only", "Enabled" };
4 
5 /*  C K C F N S  --  System-independent Kermit protocol support functions.  */
6 
7 /*  ...Part 1 (others moved to ckcfn2,3 to make this module smaller) */
8 
9 /*
10   Author: Frank da Cruz <fdc@columbia.edu>,
11   Columbia University Academic Information Systems, New York City (1974-2011)
12   The Kermit Project, Bronx NY (2011-????)
13 
14   Copyright (C) 1985, 2020,
15     Trustees of Columbia University in the City of New York.
16     All rights reserved.  See the C-Kermit COPYING.TXT file or the
17     copyright text in the ckcmai.c module for disclaimer and permissions.
18 */
19 /*
20  System-dependent primitives defined in:
21 
22    ck?tio.c -- terminal (communications) i/o
23    cx?fio.c -- file i/o, directory structure
24 */
25 #include "ckcsym.h"			/* Needed for Stratus VOS */
26 #include "ckcasc.h"			/* ASCII symbols */
27 #include "ckcdeb.h"			/* Debug formats, typedefs, etc. */
28 #include "ckcker.h"			/* Symbol definitions for Kermit */
29 #include "ckcxla.h"			/* Character set symbols */
30 #include "ckcnet.h"                     /* VMS definition of TCPSOCKET */
31 #ifdef OS2
32 #ifdef OS2ONLY
33 #include <os2.h>
34 #endif /* OS2ONLY */
35 #include "ckocon.h"
36 #endif /* OS2 */
37 
38 int docrc  = 0;				/* Accumulate CRC for \v(crc16) */
39 long crc16 = 0L;			/* File CRC = \v(crc16) */
40 int gnferror = 0;			/* gnfile() failure reason */
41 
42 extern CHAR feol;
43 extern int byteorder, xflg, what, fmask, cxseen, czseen, nscanfile, sysindex;
44 extern int xcmdsrc, dispos, matchfifo;
45 extern int inserver;
46 
47 extern int nolinks;
48 #ifdef VMSORUNIX
49 extern int zgfs_dir;
50 #ifdef CKSYMLINK
51 extern int zgfs_link;
52 #endif /* CKSYMLINK */
53 #endif /* VMSORUNIX */
54 
55 #ifndef NOXFER
56 
57 #ifndef NOICP
58 #ifndef NOSPL
59 extern char * clcmds;
60 extern int haveurl;
61 #ifdef CK_APC
62 extern int apcactive, adl_ask;
63 #endif /* CK_APC */
64 #endif /* NOSPL */
65 #endif /* NOICP */
66 
67 extern int remfile;
68 
69 /* (move these prototypes to the appropriate .h files...) */
70 
71 #ifdef COMMENT
72 /* Not used */
73 #ifdef VMS
74 _PROTOTYP( int getvnum, (char *) );
75 #endif /* VMS */
76 #endif /* COMMENT */
77 
78 _PROTOTYP( static int bgetpkt, (int) );
79 #ifndef NOCSETS
80 _PROTOTYP( int lookup, (struct keytab[], char *, int, int *) );
81 #endif /* NOCSETS */
82 #ifndef NOSPL
83 _PROTOTYP( int zzstring, (char *, char **, int *) );
84 #endif /* NOSPL */
85 
86 #ifdef OS2
87 #include <io.h>
88 #ifdef OS2ONLY
89 #include <os2.h>
90 #endif /* OS2ONLY */
91 #endif /* OS2 */
92 
93 /* Externals from ckcmai.c */
94 
95 extern int srvcdmsg, srvidl, idletmo;
96 extern char * cdmsgfile[];
97 extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
98  rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr, xitsta;
99 extern int pktnum, bctr, bctu, bctf, bctl, clfils, sbufnum, protocol,
100  size, osize, spktl, nfils, ckwarn, timef, spsizf, sndtyp, rcvtyp, success;
101 extern int parity, turn, network, whatru, fsecs, justone, slostart,
102  ckdelay, displa, mypadn, moving, recursive, nettype;
103 extern long filcnt;
104 extern CK_OFF_T
105  tfc, fsize, sendstart, rs_len, flci, flco, tlci, tlco, calibrate;
106 extern long filrej, oldcps, cps, peakcps, ccu, ccp, filestatus;
107 extern int fblksiz, frecl, frecfm, forg, fcctrl, fdispla, skipbup;
108 extern int spackets, rpackets, timeouts, retrans, crunched, wmax, wcur;
109 extern int hcflg, binary, fncnv, b_save, f_save, server;
110 extern int nakstate, discard, rejection, local, xfermode, interrupted;
111 extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
112 extern int fnspath, fnrpath, eofmethod, diractive, whatru2, wearealike;
113 extern int atcapr, atcapb, atcapu;
114 extern int lpcapr, lpcapb, lpcapu;
115 extern int swcapr, swcapb, swcapu;
116 extern int lscapr, lscapb, lscapu;
117 extern int rscapr, rscapb, rscapu;
118 extern int rptena, rptmin;
119 extern int sseqtbl[];
120 extern int numerrs, nzxopts;
121 extern long rptn;
122 extern int maxtry;
123 extern int stdouf;
124 extern int sendmode;
125 extern int carrier, ttprty;
126 extern int g_fnrpath;
127 #ifdef TCPSOCKET
128 extern int ttnproto;
129 #endif /* TCPSOCKET */
130 
131 #ifndef NOSPL
132 extern int sndxin, sndxhi, sndxlo;
133 #endif /* NOSPL */
134 
135 extern int g_binary, g_fncnv;
136 
137 #ifdef GFTIMER
138 extern CKFLOAT fpfsecs;
139 #endif /* GFTIMER */
140 
141 #ifdef OS2
142 extern struct zattr iattr;
143 #endif /* OS2 */
144 
145 #ifdef PIPESEND
146 extern int usepipes;
147 #endif /* PIPESEND */
148 extern int pipesend;
149 
150 #ifdef STREAMING
151 extern int streamrq, streaming, streamed, streamok;
152 #endif /* STREAMING */
153 extern int reliable, clearrq, cleared, urclear;
154 
155 extern int
156   atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
157   attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
158 
159 extern int bigsbsiz, bigrbsiz;
160 extern char *versio;
161 extern char *filefile;
162 extern char whoareu[], * cksysid;
163 
164 #ifndef NOSERVER
165 extern int ngetpath;
166 extern char * getpath[];
167 extern int fromgetpath;
168 #endif /* NOSERVER */
169 
170 #ifdef CK_LOGIN
171 extern int isguest;
172 #endif /* CK_LOGIN */
173 
174 extern int srvcmdlen;
175 extern CHAR *srvcmd, * epktmsg;
176 extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, myrptq;
177 extern CHAR *data, padbuf[], stchr, mystch;
178 extern CHAR *srvptr;
179 extern CHAR *rdatap;
180 extern char *cmarg, *cmarg2, **cmlist, filnam[], ofilnam[];
181 extern char *rfspec, *prfspec, *rrfspec, *prrfspec, *sfspec, *psfspec, *rfspec;
182 extern char fspec[];
183 extern int fspeclen;
184 
185 #ifndef NOMSEND
186 extern struct filelist * filehead, * filenext;
187 extern int addlist;
188 #endif /* NOMSEND */
189 
190 _PROTOTYP( int lslook, (unsigned int b) ); /* Locking Shift Lookahead */
191 _PROTOTYP( int szeof, (CHAR *s) );
192 _PROTOTYP( VOID fnlist, (void) );
193 #endif /* NOXFER */
194 
195 extern CK_OFF_T ffc;
196 
197 /* Character set Translation */
198 
199 #ifndef NOCSETS
200 extern int tcharset, fcharset, dcset7, dcset8;
201 extern int fcs_save, tcs_save;
202 extern int ntcsets, xlatype, cseqtab[];
203 extern struct csinfo tcsinfo[], fcsinfo[];
204 extern int r_cset, s_cset, afcset[];
205 #ifdef UNICODE
206 extern int ucsorder, fileorder;
207 #endif /* UNICODE */
208 
209 _PROTOTYP( CHAR ident, (CHAR) );	/* Identity translation function */
210 
211 /* Arrays of and pointers to character translation functions */
212 
213 #ifdef CK_ANSIC
214 extern CHAR (*rx)(CHAR); /* Pointer to input character translation function */
215 extern CHAR (*sx)(CHAR); /* Pointer to output character translation function */
216 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Byte-to-Byte Send */
217 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Byte-to-Byte Recv */
218 #ifdef UNICODE
219 extern int (*xut)(USHORT);	/* Translation function UCS to TCS */
220 extern int (*xuf)(USHORT);	/* Translation function UCS to FCS */
221 extern USHORT (*xtu)(CHAR);	/* Translation function TCS to UCS */
222 extern USHORT (*xfu)(CHAR);	/* Translation function FCS to UCS */
223 #endif /* UNICODE */
224 
225 #else /* The same declarations again for non-ANSI comilers... */
226 
227 extern CHAR (*rx)();
228 extern CHAR (*sx)();
229 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();
230 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();
231 #ifdef UNICODE
232 extern int (*xut)();
233 extern int (*xuf)();
234 extern USHORT (*xtu)();
235 extern USHORT (*xfu)();
236 #endif /* UNICODE */
237 #endif /* CK_ANSIC */
238 #endif /* NOCSETS */
239 
240 /* (PWP) external def. of things used in buffered file input and output */
241 
242 #ifdef DYNAMIC
243 extern char *zinbuffer, *zoutbuffer;
244 #else
245 extern char zinbuffer[], zoutbuffer[];
246 #endif /* DYNAMIC */
247 extern char *zinptr, *zoutptr;
248 extern int zincnt, zoutcnt, zobufsize, xfrxla;
249 
250 extern long crcta[], crctb[];		/* CRC-16 generation tables */
251 extern int rseqtbl[];			/* Rec'd-packet sequence # table */
252 
253 #ifndef NOXFER
254 
255 /* Criteria used by gnfile()... */
256 
257 char sndafter[19]   = { NUL, NUL };
258 char sndbefore[19]  = { NUL, NUL };
259 char sndnafter[19]  = { NUL, NUL };
260 char sndnbefore[19] = { NUL, NUL };
261 char *sndexcept[NSNDEXCEPT]  = { NULL, NULL };
262 char *rcvexcept[NSNDEXCEPT]  = { NULL, NULL };
263 CK_OFF_T sndsmaller = (CK_OFF_T)-1;
264 CK_OFF_T sndlarger  = (CK_OFF_T)-1;
265 
266 /* Variables defined in this module but shared by other modules. */
267 
268 int xfrbel = 1;
269 char * ofperms = "";			/* Output file permissions */
270 int autopath = 0;			/* SET RECEIVE PATHNAMES AUTO flag */
271 
272 #ifdef CALIBRATE
273 #define CAL_O 3
274 #define CAL_M 253
275 
276 int cal_j = 0;
277 
278 CHAR
279 cal_a[] = {
280  16, 45, 98,  3, 52, 41, 14,  7, 76,165,122, 11,104, 77,166, 15,
281 160, 93, 18, 19,112, 85, 54, 23,232,213, 90, 27, 12, 81,126, 31,
282   4,205, 34, 35,144, 73,110, 39, 28,133,218, 43,156, 65,102, 47,
283  84, 61, 50, 51,208,117, 86, 55,  8,245, 74, 59, 44,125,222, 63,
284  80,  1,162, 67,116,105,206, 71,120,  9,250, 75, 88, 97,  6, 79,
285 100,221, 82, 83, 36, 89, 94, 87, 40, 21,106, 91,236,145,150, 95,
286 228, 33,130, 99,148,137,198,103,108,169, 42,107,184,129, 78,111,
287   0, 49,114,115, 32,121,254,119,172, 57,138,123,152,177, 22,127,
288 240,193,  2,131,176,  5, 38,135,204,229, 10,139,200,161,174,143,
289 128, 17,146,147, 68,153, 30,151, 72,217,170,155, 24,209, 62,159,
290  64,225,194,163,244,201, 70,167,216,197,234,171,188,109,230,175,
291 212,113,178,179,132,185,190,183,136,249,202,187, 92,241,118,191,
292  48,237, 66,195, 96,233,142,199,248, 37, 58,203, 60, 13,134,207,
293  20, 29,210,211,164,149,182,215,220, 25, 26,219,124,157,246,223,
294 180,141,226,227,192,101,238,231, 56, 69,154,235,252,173, 46,239,
295 224,253,242,243,196, 53,214,247,168,181,186,251,140,189,158,255
296 };
297 #endif /* CALIBRATE */
298 
299 char * rf_err = "Error receiving file";	/* rcvfil() error message */
300 
301 #ifdef CK_SPEED
302 short ctlp[256] = {		/* Control-Prefix table */
303   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  */
304   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  */
305   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,
306   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 */
307   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  */
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, /* G1  */
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,0,
310   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 */
311 };
312 #endif /* CK_SPEED */
313 
314 int sndsrc;		/* Flag for where to get names of files to send: */
315 					/* -1: znext() function */
316 					/*  0: stdin */
317 					/* >0: list in cmlist or other list */
318 					/* -9: calibrate */
319 
320 int  memstr;				/* Flag for input from memory string */
321 int  funcstr;				/* Flag for input from function */
322 int  bestlen = 0;
323 int  maxsend = 0;
324 
325 int gnf_binary = 0;			/* Prevailing xfer mode for gnfile */
326 
327 #ifdef pdp11
328 #define MYINITLEN 32
329 #else
330 #define MYINITLEN 100
331 #endif /* pdp11 */
332 CHAR myinit[MYINITLEN];			/* Copy of my Send-Init data */
333 
334 /* Variables local to this module */
335 
336 #ifdef TLOG
337 #ifndef XYZ_INTERNAL
338 static
339 #endif /* XYZ_INTERNAL */
340 char *fncnam[] = {
341   "rename", "replace", "backup", "append", "discard", "ask",
342   "update", "dates-differ", ""
343 };
344 #endif /* TLOG */
345 
346 static char *memptr;			/* Pointer for memory strings */
347 
348 #ifdef VMS
349 extern int batch;
350 #else
351 extern int backgrd;
352 #endif /* VMS */
353 
354 #ifdef CK_CTRLZ
355 static int lastchar = 0;
356 #endif /* CK_CTRLZ */
357 
358 #ifdef CK_ANSIC
359 static int (*funcptr)(void);		/* Pointer for function strings */
360 #else
361 static int (*funcptr)();
362 #endif /* CK_ANSIC */
363 
364 #ifdef pdp11
365 #define CMDSTRL 50
366 static char cmdstr[50];			/* System command string. */
367 #else
368 #ifdef BIGBUFOK
369 #define CMDSTRL 6144
370 #else
371 #define CMDSTRL 1024
372 #endif /* BIGBUFOK */
373 static char cmdstr[CMDSTRL+1];
374 #endif /* pdp11 */
375 
376 static int drain;			/* For draining stacked-up ACKs. */
377 
378 static int first;			/* Flag for first char from input */
379 static CHAR t;				/* Current character */
380 #ifdef COMMENT
381 static CHAR next;			/* Next character */
382 #endif /* COMMENT */
383 
384 static int ebqsent = 0;			/* 8th-bit prefix bid that I sent */
385 static int lsstate = 0;			/* Locking shift state */
386 static int lsquote = 0;			/* Locking shift quote */
387 
388 extern int quiet;
389 
390 /*  E N C S T R  --  Encode a string from memory. */
391 
392 /*
393   Call this instead of getpkt() if source is a string, rather than a file.
394   Note: Character set translation is never done in this case.
395 */
396 
397 #ifdef COMMENT
398 #define ENCBUFL 200
399 #ifndef pdp11
400 CHAR encbuf[ENCBUFL];
401 #else
402 /* This is gross, but the pdp11 root segment is out of space */
403 /* Will allocate it in ckuusr.c. */
404 extern CHAR encbuf[];
405 #endif /* pdp11 */
406 #endif /* COMMENT */
407 
408 /*
409   Encode packet data from a string in memory rather than from a file.
410   Returns the length of the encoded string on success, -1 if the string
411   could not be completely encoded into the currently negotiated data
412   field length.
413 */
414 int
415 #ifdef CK_ANSIC
encstr(CHAR * s)416 encstr(CHAR *s)
417 #else /* CK_ANSIC */
418 encstr(s) CHAR* s;
419 #endif /* CK_ANSIC */
420 {
421 /*
422   Recoded 30 Jul 94 to use the regular data buffer and the negotiated
423   maximum packet size.  Previously we were limited to the length of encbuf[].
424   Also, to return a failure code if the entire encoded string would not fit.
425   Modified 14 Jul 98 to return length of encoded string.
426 */
427     int m, rc, slen; char *p;
428     if (!data) {			/* Watch out for null pointers. */
429 	debug(F100,"SERIOUS ERROR: encstr data == NULL","",0);
430 	return(-1);
431     }
432     if (!s) s = (CHAR *)"";		/* Ditto. */
433     slen = strlen((char *)s);		/* Length of source string. */
434     debug(F111,"encstr",s,slen);
435     rc = 0;				/* Return code. */
436     m = memstr; p = memptr;		/* Save these. */
437     memptr = (char *)s;			/* Point to the string. */
438     /* debug(F101,"encstr memptr 1","",memptr); */
439     memstr = 1;				/* Flag memory string as source. */
440     first = 1;				/* Initialize character lookahead. */
441     *data = NUL;			/* In case s is empty */
442     debug(F101,"encstr spsiz","",spsiz);
443     rc = getpkt(spsiz,0);		/* Fill a packet from the string. */
444     debug(F101,"encstr getpkt rc","",rc);
445     if (rc > -1 && memptr < (char *)(s + slen)) { /* Means we didn't encode */
446 	rc = -1;			/* the whole string. */
447 	debug(F101,"encstr string too big","",size);
448     }
449     debug(F101,"encstr getpkt rc","",rc);
450     memstr = m;				/* Restore memory string flag */
451     memptr = p;				/* and pointer */
452     first = 1;				/* Put this back as we found it. */
453     return(rc);
454 }
455 
456 /*  Output functions passed to 'decode':  */
457 
458 int			       /*  Put character in server command buffer  */
459 #ifdef CK_ANSIC
putsrv(char c)460 putsrv(char c)
461 #else
462 putsrv(c) register char c;
463 #endif /* CK_ANSIC */
464 /* putsrv */ {
465     *srvptr++ = c;
466     *srvptr = '\0';		/* Make sure buffer is null-terminated */
467     return(0);
468 }
469 
470 int					/*  Output character to console.  */
471 #ifdef CK_ANSIC
puttrm(char c)472 puttrm(char c)
473 #else
474 puttrm(c) register char c;
475 #endif /* CK_ANSIC */
476 /* puttrm */ {
477     extern int rcdactive;
478 #ifndef NOSPL
479     extern char * qbufp;		/* If REMOTE QUERY active, */
480     extern int query, qbufn;		/* also store response in */
481     if (query && qbufn++ < 1024) {	/* query buffer. */
482 	*qbufp++ = c;
483 	*qbufp = NUL;
484     }
485     if (!query || !xcmdsrc)
486 #endif /* NOSPL */
487 /*
488   This routine is used (among other things) for printing the server's answer
489   to a REMOTE command.  But REMOTE CD is special because it isn't really
490   asking for an answer from the server.  Thus some people want to suppress
491   the confirmation message (e.g. when the server sends back the actual path
492   of the directory CD'd to), and expect to be able to do this with SET QUIET
493   ON.  But they would not want SET QUIET ON to suppress the other server
494   replies, which are pointless without their answers.  Thus the "rcdactive"
495   flag (REMOTE CD command is active).  Thu Oct 10 16:38:21 2002
496 */
497       if (!(quiet && rcdactive))	/* gross, yuk */
498 	conoc(c);
499     return(0);
500 }
501 #endif /* NOXFER */
502 
503 int					/*  Output char to file. */
504 #ifdef CK_ANSIC
putmfil(char c)505 putmfil(char c)				/* Just like putfil but to ZMFILE */
506 #else					/* rather than ZOFILE... */
507 putmfil(c) register char c;
508 #endif /* CK_ANSIC */
509 /* putmfil */ {
510     debug(F000,"putfil","",c);
511     if (zchout(ZMFILE, (char) (c & fmask)) < 0) {
512 	czseen = 1;
513 	debug(F101,"putfil zchout write error, setting czseen","",1);
514 	return(-1);
515     }
516     return(0);
517 }
518 
519 int					/*  Output char to nowhere. */
520 #ifdef CK_ANSIC
putnowhere(char c)521 putnowhere(char c)
522 #else
523 putnowhere(c) register char c;
524 #endif /* CK_ANSIC */
525 /* putnowhere */ {
526     return(0);
527 }
528 
529 
530 int					/*  Output char to file. */
531 #ifdef CK_ANSIC
putfil(char c)532 putfil(char c)
533 #else
534 putfil(c) register char c;
535 #endif /* CK_ANSIC */
536 /* putfil */ {
537     debug(F000,"putfil","",c);
538     if (zchout(ZOFILE, (char) (c & fmask)) < 0) {
539 	czseen = 1;   			/* If write error... */
540 	debug(F101,"putfil zchout write error, setting czseen","",1);
541 	return(-1);
542     }
543     return(0);
544 }
545 
546 /*
547   The following function is a wrapper for putfil().  The only reason for its
548   existence is to be passed as a function pointer to decode(), which treats
549   putfil() itself specially -- bypassing it and using an internal macro
550   instead to speed things up.  Use zputfil() instead of putfil() in cases where
551   we do not want this to happen, e.g. when we need to send output to the file
552   with a mixture of zchout() and zsout()/zsoutl() calls (as is the case with
553   incoming short-form REMOTE command replies redirected to a file), which would
554   otherwise result in data written to the file out of order.
555 */
556 int
557 #ifdef CK_ANSIC
zputfil(char c)558 zputfil(char c)
559 #else
560 zputfil(c) register char c;
561 #endif /* CK_ANSIC */
562 /* zputfil */ {
563     return(putfil(c));
564 }
565 
566 #ifndef NOXFER
567 
568 /* D E C O D E  --  Kermit packet decoding procedure */
569 
570 /*
571  Call with string to be decoded and an output function.
572  Returns 0 on success, -1 on failure (e.g. disk full).
573 
574  This is the "inner loop" when receiving files, and must be coded as
575  efficiently as possible.  Note some potential problems:  if a packet
576  is badly formed, having a prefixed sequence ending prematurely, this
577  function, as coded, could read past the end of the packet.  This has
578  never happened, thus the additional (time-consuming) tests have not
579  been added.
580 */
581 
582 static CHAR *xdbuf;	/* Global version of decode()'s buffer pointer */
583                         /* for use by translation functions. */
584 
585 /* Function for pushing a character onto decode()'s input stream. */
586 
587 VOID
588 #ifdef CK_ANSIC
zdstuff(CHAR c)589 zdstuff(CHAR c)
590 #else
591 zdstuff(c) CHAR c;
592 #endif /* CK_ANSIC */
593 /* zdstuff */ {
594     xdbuf--;				/* Back up the pointer. */
595     *xdbuf = c;				/* Stuff the character. */
596 }
597 
598 #ifdef CKTUNING
599 /*
600   Trimmed-down packet decoder for binary-mode no-parity transfers.
601   decode() is the full version.
602 */
603 int
604 #ifdef CK_ANSIC
bdecode(CHAR * buf,int (* fn)(char))605 bdecode(CHAR *buf, int (*fn)(char))
606 #else
607 bdecode(buf,fn) register CHAR *buf; register int (*fn)();
608 #endif /* CK_ANSIC */
609 /* bdecode */ {
610     register unsigned int a, a7;	/* Various copies of current char */
611     int ccpflg;				/* For Ctrl-unprefixing stats */
612     int t;				/* Int version of character */
613     int len;
614     long z;				/* For CRC calculation */
615     CHAR c;				/* Current character */
616 
617     if (!binary || parity || fn != putfil) /* JUST IN CASE */
618       return(decode(buf,fn,1));
619     debug(F100,"BDECODE","",0);
620 
621     xdbuf = buf;			/* Global copy of source pointer. */
622 
623     len = rln;				/* Number of bytes in data field */
624     while (len > 0) {
625         a = *xdbuf++ & 0xff;		/* Get next character */
626 	len--;
627 	rpt = 0;			/* Initialize repeat count. */
628 	if (a == rptq && rptflg) {	/* Got a repeat prefix? */
629 	    rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
630 	    rptn += rpt;
631 	    a = *xdbuf++ & 0xFF;	/* and get the prefixed character. */
632 	    len -= 2;
633 	}
634 	ccpflg = 0;			/* Control prefix flag. */
635 	if (a == ctlq) {		/* If control prefix, */
636 	    a  = *xdbuf++ & 0xFF;	/* get its operand */
637 	    len--;
638 	    a7 = a & 0x7F;		/* and its low 7 bits. */
639 	    if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */
640 		a = ctl(a);		/* if in control range. */
641 		a7 = a & 0x7F;
642 		ccpflg = 1;		/* Note that we did this */
643 		ccp++;			/* Count for stats */
644 	    }
645 	} else a7 = a & 0x7f;		/* Not control quote */
646 	if (a7 < 32 || a7 == 127)	/* A bare control character? */
647 	  if (!ccpflg) ccu++;		/* Count it */
648 	if (!rpt) rpt = 1;
649 	for (; rpt > 0; rpt--) {	/* Output the char RPT times */
650 #ifdef CALIBRATE
651 	    if (calibrate) {
652 		ffc++;
653 		continue;
654 	    }
655 #endif /* CALIBRATE */
656 #ifdef OS2
657             if (xflg && !remfile) {		/* Write to virtual screen */
658                 char _a;
659                 _a = a & fmask;
660                 t = conoc(_a);
661                 if (t < 1)
662                     t = -1;
663             } else
664 #endif /* OS2 */
665 	      t = zmchout(a & fmask);	/* zmchout is a macro */
666 	    if (t < 0) {
667 		debug(F101,"bdecode write error - errno","",errno);
668 		return(-1);
669 	    }
670 	    ffc++;			/* Count the character */
671 	    if (docrc && !remfile) {	/* Update file CRC */
672 		c = a;			/* Force conversion to unsigned char */
673 		z = crc16 ^ (long)c;
674 		crc16 = (crc16 >> 8) ^
675 		  (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
676 	    }
677 	}
678 #ifdef CK_CTRLZ
679 	lastchar = a;
680 #endif /* CK_CTRLZ */
681     }
682     return(0);
683 }
684 #endif /* CKTUNING */
685 #endif /* NOXFER */
686 
687 /*  P N B Y T E  --  Output next byte to file or other destination  */
688 
689 static CK_OFF_T offc = 0L;
690 
691 static int
692 #ifdef CK_ANSIC
pnbyte(CHAR c,int (* fn)(char))693 pnbyte(CHAR c, int (*fn)(char))
694 #else
695 pnbyte(c,fn) CHAR c; int (*fn)();
696 #endif /* CK_ANSIC */
697 /* pnbyte */ {
698     int rc;
699     long z;
700 
701 #ifdef OS2
702 #ifndef NOXFER
703     if (xflg && !remfile) {		/* Write to virtual screen */
704 	char _a;
705 	_a = c & fmask;
706 	rc = conoc(_a);
707 	if (rc < 1)
708 	  return(-1);
709     } else
710 #endif /* NOXFER */
711 #endif /* OS2 */
712     {
713 	if (fn == putfil) {		/* Execute output function */
714 	    rc = zmchout(c);		/* to-file macro (fast) */
715 	} else if (!fn) {
716 	    rc = putchar(c);		/* to-screen macro (fast) */
717         } else {
718 	    rc = (*fn)(c);		/* function call (not as fast) */
719 	}
720 	if (rc < 0)
721 	  return(rc);
722     }
723 /*
724   Both xgnbyte() and xpnbyte() increment ffc (the file byte counter).
725   During file transfer, only one of these functions is called.  However,
726   the TRANSLATE command is likely to call them both.  offc, therefore,
727   contains the output byte count, necessary for handling the UCS-2 BOM.
728   NOTE: It might be safe to just test for W_SEND, FTP or not.
729 */
730     if ((what & (W_FTP|W_SEND)) != (W_FTP|W_SEND)) {
731 	offc++;				/* Count the byte */
732 	ffc++;				/* Count the byte */
733     }
734 #ifndef NOXFER
735     if (docrc && !xflg && !remfile) {	/* Update file CRC */
736 	z = crc16 ^ (long)c;
737 	crc16 = (crc16 >> 8) ^
738 	  (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
739     }
740 #endif /* NOXFER */
741     return(1);
742 }
743 
744 /*
745   X P N B Y T E  --  Translate and put next byte to file.
746 
747   Only for Unicode.  Call with next untranslated byte from incoming
748   byte stream, which can be in any Transfer Character Set: UCS-2, UTF-8,
749   Latin-1, Latin-Hebrew, etc.  Translates to the file character set and
750   writes bytes to the output file.  Call with character to translate
751   as an int, plus the transfer character set (to translate from) and the
752   file character set (to translate to), or -1,0,0 to reset the UCS-2 byte
753   number (which should be done at the beginning of a file).  If the transfer
754   (source) character-set is UCS-2, bytes MUST arrive in Big-Endian order.
755   Returns:
756    -1: On error
757     0: Nothing to write (mid-sequence)
758    >0: Number of bytes written.
759 */
760 #ifdef KANJI
761 static int jstate = 0, jx = 0;		/* For outputting JIS-7 */
762 static char jbuf[16] = { NUL, NUL };
763 #endif /* KANJI */
764 
765 int
766 #ifdef CK_ANSIC
xpnbyte(int a,int tcs,int fcs,int (* fn)(char))767 xpnbyte(int a, int tcs, int fcs, int (*fn)(char))
768 #else
769 xpnbyte(a,tcs,fcs,fn) int a, tcs, fcs; int (*fn)();
770 #endif /* CK_ANSIC */
771 /* xpnbyte */ {
772 #ifdef UNICODE
773     extern int ucsbom;			/* Byte order */
774 #endif /* UNICODE */
775     /* CHAR c; */			/* Unsigned char worker */
776     static union ck_short uc, eu, sj;	/* UCS-2, EUC, and Shift-JIS workers */
777     USHORT ch;				/* ditto... */
778     USHORT * us = NULL;			/* ditto... */
779     int c7, rc, haveuc = 0;		/* Return code and UCS-2 flag */
780     int utferror = 0;			/* UTF-8 error */
781     static int bn = 0;			/* UCS-2 byte number */
782     int swapping = 0;			/* Swapping UCS bytes to output? */
783 					/* swapping must be 0 or 1 */
784     if (a == -1 && (tcs | fcs) == 0) {	/* Reset in case previous run */
785 	bn = 0;				/* left bn at 1... */
786 	offc = (CK_OFF_T)0;
787 	debug(F101,"xpnbyte RESET","",bn);
788 	return(0);
789     }
790     debug(F001,"xpnbyte a","",a);
791 
792 #ifdef UNICODE
793 
794 /*
795   byteorder = hardware byte order of this machine.
796   ucsorder  = override by SET FILE UCS BYTE-ORDER command.
797   fileorder = byte order of UCS-2 input file detected from BOM.
798   swapping applies only when output charset is UCS-2.
799 */
800     if (ucsorder != 1 && ucsorder != 0)	/* Also just in case... */
801       ucsorder = byteorder;
802     if ((byteorder && !ucsorder) || (!byteorder && fileorder))
803       swapping = 1;			/* Swapping bytes to output */
804 
805 #ifdef COMMENT
806     debug(F101,"xpnbyte ucsorder","",ucsorder);
807     debug(F101,"xpnbyte swapping","",swapping);
808 #endif /* COMMENT */
809 
810     if (tcs == TC_UTF8) {		/* 'a' is from a UTF-8 stream */
811 	ch = a;
812 	if (fcs == TC_UTF8)		/* Output is UTF-8 too */
813 	  return(pnbyte(ch,fn));	/* so just copy. */
814 	rc = utf8_to_ucs2(ch,&us);	/* Otherwise convert to UCS-2 */
815 	if (rc == 0) {			/* Done with this sequence */
816 	    uc.x_short = *us;		/* We have a Unicode */
817 	    haveuc = 1;
818 	} else if (rc < 0) {		/* Error */
819 	    debug(F101,"xpnbyte UTF-8 conversion error","",rc);
820 	    haveuc = 1;			/* Replace by U+FFFD */
821 	    uc.x_short = *us;
822 	    utferror = 1;
823 	} else				/* Sequence incomplete */
824 	  return(0);
825     } else if (tcs == TC_UCS2) {	/* 'a' is UCS-2 */
826 	/* Here we have incoming UCS-2 in guaranteed Big Endian order */
827 	/* so we must exchange bytes if local machine is Little Endian. */
828 	switch (bn) {			/* Which byte? */
829 	  case 0:			/* High... */
830 	    uc.x_char[byteorder] = (unsigned)a & 0xff;
831 	    bn++;
832 	    return(0);			/* Wait for next */
833 	  case 1:			/* Low... */
834 	    uc.x_char[1-byteorder] = (unsigned)a & 0xff;
835 	    bn = 0;			/* Done with sequence */
836 	    haveuc = 1;			/* Have a Unicode */
837 	}
838     } else
839 #endif /* UNICODE */
840 
841 #ifdef KANJI				/* Whether UNICODE is defined or not */
842       if (tcs == TC_JEUC) {		/* Incoming Japanese EUC */
843 	int bad = 0;
844 	static int kanji = 0;		/* Flags set in case 0 for case 1 */
845 	static int kana = 0;
846 	switch (bn) {			/* Byte number */
847 	  case 0:			/* Byte 0 */
848 	    eu.x_short = 0;
849 	    if ((a & 0x80) == 0) {
850 		sj.x_short = (unsigned)a & 0xff; /* Single byte */
851 		kanji = kana = 0;
852 	    } else {			/* Double byte */
853 		c7 = a & 0x7f;
854 		if (c7 > 0x20 && c7 < 0x7f) { /* Kanji */
855 		    eu.x_char[byteorder] = (CHAR) a;  /* Store first byte */
856 		    bn++;		      /* Set up for second byte */
857 		    kanji = 1;
858 		    kana = 0;
859 		    return(0);
860 		} else if (a == 0x8e) {	/* SS2 -- Katakana prefix */
861 		    eu.x_char[byteorder] = (CHAR) a; /* Save it */
862 		    bn++;
863 		    kana = 1;
864 		    kanji = 0;
865 		    return(0);
866 		} else {
867 		    bad++;
868 		}
869 	    }
870 	    break;
871 	  case 1:			/* Byte 1 */
872 	    bn = 0;
873 	    if (kanji) {
874 		eu.x_char[1-byteorder] = (CHAR) a;
875 		sj.x_short = eu_to_sj(eu.x_short);
876 		break;
877 	    } else if (kana) {
878 		sj.x_short = (CHAR) (a | 0x80);
879 		break;
880 	    } else {			/* (shouldn't happen) */
881 		bad++;
882 	    }
883 	}
884 	/* Come here with one Shift-JIS character */
885 
886 #ifdef UNICODE
887 	if (bad) {
888 	    uc.x_short = 0xfffd;
889 	} else {
890 	    uc.x_short = sj_to_un(sj.x_short); /* Convert to Unicode */
891 	}
892 	haveuc = 1;
893 #endif /* UNICODE */
894     } else
895 #endif /* KANJI */
896 
897 #ifdef UNICODE
898 	uc.x_short = (unsigned)a & 0xff; /* Latin-1 or whatever... */
899 
900     /* Come here with uc = the character to be translated. */
901     /* If (haveuc) it's UCS-2 in native order, otherwise it's a byte. */
902 
903     debug(F101,"xpnbyte haveuc","",haveuc);
904 
905     if (haveuc) {			/* If we have a Unicode... */
906 	debug(F001,"xpnbyte uc.x_short","[A]",uc.x_short);
907 	debug(F101,"xpnbyte feol","",feol);
908 	if (what & W_XFER) {		/* If transferring a file */
909 	    if (feol && uc.x_short == CR) { /* handle eol conversion. */
910 		return(0);
911 	    } else if (feol && uc.x_short == LF) {
912 		uc.x_short = feol;
913 	    }
914 	}
915 	debug(F001,"xpnbyte uc.x_short","[B]",uc.x_short);
916 	if (fcs == FC_UCS2) {		/* And FCS is UCS-2 */
917 	    /* Write out the bytes in the appropriate byte order */
918 	    int count = 0;
919 #ifndef IKSDONLY
920 #ifdef OS2
921             extern int k95stdout,wherex[],wherey[];
922 			extern unsigned char colorcmd;
923             union {
924                 USHORT ucs2;
925                 UCHAR  bytes[2];
926             } output;
927 #endif /* OS2 */
928 #endif /* IKSDONLY */
929 	    if (!offc && ucsbom) {	/* Beginning of file? */
930 
931 #ifndef IKSDONLY
932 #ifdef OS2
933                 if (fn == NULL && !k95stdout && !inserver) {
934 		    offc++;
935 #ifdef COMMENT
936 		    /* Don't print the BOM to the display */
937                     output.bytes[0] = (!ucsorder ? 0xff : 0xfe);
938                     output.bytes[1] = (!ucsorder ? 0xfe : 0xff);
939 
940                     VscrnWrtUCS2StrAtt(VCMD,
941                                        &output.ucs2,
942                                        1,
943                                        wherey[VCMD],
944                                        wherex[VCMD],
945                                        &colorcmd
946                                        );
947 #endif /* COMMENT */
948                 } else
949 #endif /* OS2 */
950 #endif /* IKSDONLY */
951                 {
952 		    if ((rc = pnbyte((ucsorder ? 0xff : 0xfe),fn)) < 0)
953 		      return(rc);	/* BOM */
954 		    if ((rc = pnbyte((ucsorder ? 0xfe : 0xff),fn)) < 0)
955 		      return(rc);
956 		}
957 		count += 2;
958 	    }
959 	    if (utferror) {
960 #ifndef IKSDONLY
961 #ifdef OS2
962                 if (fn == NULL && !k95stdout && !inserver) {
963                     offc++;
964                     output.bytes[0] = (!ucsorder ? 0xfd : 0xff);
965                     output.bytes[1] = (!ucsorder ? 0xff : 0xfd);
966 
967                     VscrnWrtUCS2StrAtt(VCMD,
968                                        &output.ucs2,
969                                        1,
970                                        wherey[VCMD],
971                                        wherex[VCMD],
972                                        &colorcmd
973                                        );
974                 } else
975 #endif /* OS2 */
976 #endif /* IKSDONLY */
977 		{
978 		    if ((rc = pnbyte((ucsorder ? 0xfd : 0xff),fn)) < 0)
979 		      return(rc);
980 		    if ((rc = pnbyte((ucsorder ? 0xff : 0xfd),fn)) < 0)
981 		      return(rc);
982 		}
983 		count += 2;
984 	    }
985 #ifndef IKSDONLY
986 #ifdef OS2
987             if (fn == NULL && !k95stdout && !inserver) {
988                 offc++;
989                 output.bytes[0] = uc.x_char[swapping];
990                 output.bytes[1] = uc.x_char[1-swapping];
991 
992                 VscrnWrtUCS2StrAtt(VCMD,
993                                    &output.ucs2,
994                                    1,
995                                    wherey[VCMD],
996                                    wherex[VCMD],
997                                    &colorcmd
998                                    );
999             } else
1000 #endif /* OS2 */
1001 #endif /* IKSDONLY */
1002             {
1003 		if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
1004 		  return(rc);
1005 		if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
1006 		  return(rc);
1007 	    }
1008 	    count += 2;
1009 	    return(count);
1010 	} else if (fcs == FC_UTF8) {	/* Convert to UTF-8 */
1011 	    CHAR * buf = NULL;
1012 	    int i, count;
1013 	    if (utferror) {
1014 		if ((rc = pnbyte((ucsorder ? 0xbd : 0xff),fn)) < 0)
1015 		  return(rc);
1016 		if ((rc = pnbyte((ucsorder ? 0xff : 0xbd),fn)) < 0)
1017 		  return(rc);
1018 	    }
1019 	    if ((count = ucs2_to_utf8(uc.x_short,&buf)) < 1)
1020 	      return(-1);
1021 	    debug(F011,"xpnbyte buf",buf,count);
1022 	    for (i = 0; i < count; i++)
1023 	      if ((rc = pnbyte(buf[i],fn)) < 0)
1024 		return(rc);
1025 	    if (utferror)
1026 	      count += 2;
1027 	    return(count);
1028 	} else {			/* Translate UCS-2 to byte */
1029 	    if (uc.x_short == 0x2028 || uc.x_short == 0x2029) {
1030 		if (utferror)
1031 		  pnbyte(UNK,fn);
1032 		if (feol)
1033 		  return(pnbyte((CHAR)feol,fn));
1034 		if ((rc = pnbyte((CHAR)CR,fn)) < 0)
1035 		  return(rc);
1036 		if ((rc = pnbyte((CHAR)LF,fn)) < 0)
1037 		  return(rc);
1038 		else
1039 		  return(utferror ? 3 : 2);
1040 	    } else if (xuf) {		/* UCS-to-FCS function */
1041 		int x = 0;
1042 		if (utferror)
1043 		  pnbyte(UNK,fn);
1044 		if ((rc = (*xuf)(uc.x_short)) < 0) /* These can fail... */
1045 		  ch = UNK;
1046 		else
1047 		  ch = (unsigned)((unsigned)rc & 0xffff);
1048 		x = pnbyte(ch,fn);
1049 		if (x < 0)
1050 		  return(x);
1051 		else if (utferror)
1052 		  x++;
1053 		return(x);
1054 #ifdef KANJI
1055 
1056 /*  Also see the non-Unicode Kanji section further down in this function. */
1057 
1058 	    } else if (fcsinfo[fcs].alphabet == AL_JAPAN) {
1059 
1060 		/* Translate UCS-2 to Japanese set */
1061 		debug(F001,"xpnbyte uc","",uc.x_short);
1062 		sj.x_short = un_to_sj(uc.x_short); /* First to Shift-JIS */
1063 		debug(F001,"xpnbyte sj","",sj.x_short);
1064 
1065 		switch (fcs) {		/* File character set */
1066 		  case FC_SHJIS:	/* Shift-JIS -- just output it */
1067 		    if (sj.x_char[byteorder]) /* But not high byte if zero */
1068 		      if ((rc = pnbyte((CHAR)sj.x_char[byteorder],fn)) < 0)
1069 			return(rc);
1070 		    if ((rc = pnbyte((CHAR)sj.x_char[1-byteorder],fn)) < 0)
1071 		      return(rc);
1072 		    return(2);
1073 		  case FC_JEUC:		/* EUC-JP */
1074 		    eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
1075 		    debug(F001,"xpnbyte eu","",eu.x_short);
1076 		    if (eu.x_short == 0xffff) { /* Bad */
1077 			if ((rc = pnbyte(UNK,fn)) < 0)
1078 			  return(rc);
1079 			return(1);
1080 		    } else {		/* Good */
1081 			int count = 0;	/* Write high byte if not zero */
1082 			if (eu.x_char[byteorder]) {
1083 			    if ((rc=pnbyte((CHAR)eu.x_char[byteorder],fn)) < 0)
1084 			      return(rc);
1085 			    count++;
1086 			}
1087 			/* Always write low byte */
1088 			if ((rc = pnbyte((CHAR)eu.x_char[1-byteorder],fn)) < 0)
1089 			  return(rc);
1090 			count++;
1091 			return(count);
1092 		    }
1093 		    break;
1094 
1095 		  case FC_JIS7:		/* JIS-7 */
1096 		  case FC_JDEC:		/* DEC Kanji */
1097 		    eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
1098 		    if (eu.x_short == 0xffff) { /* Bad */
1099 			debug(F001,"xpnbyte bad eu","",eu.x_short);
1100 			if ((rc = pnbyte(UNK,fn)) < 0)
1101 			  return(rc);
1102 			return(1);
1103 		    } else {		/* Good */
1104 			int i;
1105 			/* Use another name - 'a' hides parameter */
1106 			/* It's OK as is but causes compiler warnings */
1107 			char a = eu.x_char[1-byteorder]; /* Low byte */
1108 			debug(F001,"xpnbyte eu","",eu.x_short);
1109 			if (eu.x_char[byteorder] == 0) { /* Roman */
1110 			    switch (jstate) {
1111 			      case 1:	/* Current state is Katakana */
1112 				jbuf[0] = 0x0f;	/* SI */
1113 				jbuf[1] = a;
1114 				jx = 2;
1115 				break;
1116 			      case 2:	/* Current state is Kanji */
1117 				jbuf[0] = 0x1b;	/* ESC */
1118 				jbuf[1] = 0x28;	/* ( */
1119 				jbuf[2] = 0x4a;	/* J */
1120 				jbuf[3] = a;
1121 				jx = 4;
1122 				break;
1123 			      default:	/* Current state is Roman */
1124 				jbuf[0] = a;
1125 				jx = 1;
1126 				break;
1127 			    }
1128 			    jstate = 0;	/* New state is Roman */
1129 			} else if (eu.x_char[byteorder] == 0x8e) { /* Kana */
1130 			    jx = 0;
1131 			    switch (jstate) {
1132 			      case 2:		   /* from Kanji */
1133 				jbuf[jx++] = 0x1b; /* ESC */
1134 				jbuf[jx++] = 0x28; /* ( */
1135 				jbuf[jx++] = 0x4a; /* J */
1136 			      case 0:		   /* from Roman */
1137 				jbuf[jx++] = 0x0e; /* SO */
1138 			      default:		   /* State is already Kana*/
1139 				jbuf[jx++] = (a & 0x7f); /* and the char */
1140 				break;
1141 			    }
1142 			    jstate = 1;	/* New state is Katakana */
1143 			} else {	/* Kanji */
1144 			    jx = 0;
1145 			    switch (jstate) {
1146 			      case 1:	/* Current state is Katakana */
1147 				jbuf[jx++] = 0x0f; /* SI  */
1148 			      case 0:	/* Current state is Roman */
1149 				jbuf[jx++] = 0x1b; /* ESC */
1150 				jbuf[jx++] = 0x24; /* $   */
1151 				jbuf[jx++] = 0x42; /* B   */
1152 			      default:	/* Current state is already Kanji */
1153 				jbuf[jx++] = eu.x_char[byteorder] & 0x7f;
1154 				jbuf[jx++] = eu.x_char[1-byteorder] & 0x7f;
1155 				break;
1156 			    }
1157 			    jstate = 2;	/* Set state to Kanji */
1158 			}
1159 			for (i = 0; i < jx; i++) /* Output the result */
1160 			  if ((rc = pnbyte(jbuf[i],fn)) < 0)
1161 			    return(rc);
1162 			return(jx);	/* Return its length */
1163 		    }
1164 		}
1165 #endif /* KANJI */
1166 	    } else {			/* No translation function */
1167 		int count = 0;
1168 		if (utferror) {
1169 		    if ((rc = pnbyte((ucsorder ? 0xfd : 0xff),fn)) < 0)
1170 		      return(rc);
1171 		    if ((rc = pnbyte((ucsorder ? 0xff : 0xfd),fn)) < 0)
1172 		      return(rc);
1173 		    count += 2;
1174 		}
1175 		if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
1176 		  return(rc);
1177 		if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
1178 		  return(rc);
1179 		count += 2;
1180 		return(count);
1181 	    }
1182 	}
1183     } else {				/* Byte to Unicode */
1184 	if (xtu) {			/* TCS-to-UCS function */
1185 	    if (((tcsinfo[tcs].size > 128) && (uc.x_short & 0x80)) ||
1186 		tcsinfo[tcs].size <= 128)
1187 	      uc.x_short = (*xtu)(uc.x_short);
1188 	}
1189 	if (fcs == FC_UCS2) {		/* And FCS is UCS-2 */
1190 	    /* Write out the bytes in the appropriate byte order */
1191 	    if (!offc && ucsbom) {	/* Beginning of file? */
1192 		if ((rc = pnbyte((ucsorder ? 0xff : 0xfe),fn)) < 0) /* BOM */
1193 		  return(rc);
1194 		if ((rc = pnbyte((ucsorder ? 0xfe : 0xff),fn)) < 0)
1195 		  return(rc);
1196 	    }
1197 	    if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
1198 	      return(rc);
1199 	    if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
1200 	      return(rc);
1201 	    return(2);
1202 	} else if (fcs == FC_UTF8) {	/* Convert to UTF-8 */
1203 	    CHAR * buf = NULL;
1204 	    int i, count;
1205 	    if ((count = ucs2_to_utf8(uc.x_short,&buf)) < 1)
1206 	      return(-1);
1207 	    for (i = 0; i < count; i++)
1208 	      if ((rc = pnbyte(buf[i],fn)) < 0)
1209 		return(rc);
1210 	    return(count);
1211 	} else {
1212 	    debug(F100,"xpnbyte impossible combination","",0);
1213 	    return(-1);
1214 	}
1215     }
1216 #else
1217 #ifdef KANJI
1218 /*
1219   This almost, but not quite, duplicates the Kanji section above.
1220   There is no doubt a way to combine the sections more elegantly,
1221   but probably only at the expense of additional execution overhead.
1222   As matters stand, be careful to reflect any changes in this section
1223   to the other Kanji section above.
1224 */
1225     if (tcs == TC_JEUC) {		/* Incoming Japanese EUC */
1226 	int count = 0;
1227 	switch (fcs) {			/* File character set */
1228 	  case FC_SHJIS:		/* Shift-JIS -- just output it */
1229 	    if (sj.x_char[byteorder])	/* But not high byte if zero */
1230 	      if ((rc = pnbyte((CHAR)sj.x_char[byteorder],fn)) < 0)
1231 		return(rc);
1232 	    count++;
1233 	    if ((rc = pnbyte((CHAR)sj.x_char[1-byteorder],fn)) < 0)
1234 	      return(rc);
1235 	    count++;
1236 	    return(count);
1237 	  case FC_JEUC:			/* EUC-JP */
1238 	    eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
1239 	    debug(F001,"xpnbyte FC_JEUC eu","",eu.x_short);
1240 	    if (eu.x_short == 0xffff) { /* Bad */
1241 		if ((rc = pnbyte(UNK,fn)) < 0)
1242 		  return(rc);
1243 		return(1);
1244 	    } else {			/* Good */
1245 		int count = 0;		/* Write high byte if not zero */
1246 		if (eu.x_char[byteorder]) {
1247 		    if ((rc = pnbyte((CHAR)eu.x_char[byteorder],fn)) < 0)
1248 		      return(rc);
1249 		    count++;
1250 		}
1251 		/* Always write low byte */
1252 		if ((rc = pnbyte((CHAR)eu.x_char[1-byteorder],fn)) < 0)
1253 		  return(rc);
1254 		count++;
1255 		return(count);
1256 	    }
1257 	    break;
1258 
1259 	  case FC_JIS7:			/* JIS-7 */
1260 	  case FC_JDEC:			/* DEC Kanji */
1261 	    eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
1262 	    if (eu.x_short == 0xffff) { /* Bad */
1263 		debug(F001,"xpnbyte FC_JIS7 bad eu","",eu.x_short);
1264 		if ((rc = pnbyte(UNK,fn)) < 0)
1265 		  return(rc);
1266 		return(1);
1267 	    } else {			/* Good */
1268 		int i;
1269 		char a = eu.x_char[1-byteorder]; /* Low byte */
1270 		debug(F001,"xpnbyte FC_JIS7 eu","",eu.x_short);
1271 		if (eu.x_char[byteorder] == 0) { /* Roman */
1272 		    switch (jstate) {
1273 		      case 1:		/* Current state is Katakana */
1274 			jbuf[0] = 0x0f;	/* SI */
1275 			jbuf[1] = a;
1276 			jx = 2;
1277 			break;
1278 		      case 2:		/* Current state is Kanji */
1279 			jbuf[0] = 0x1b;	/* ESC */
1280 			jbuf[1] = 0x28;	/* ( */
1281 			jbuf[2] = 0x4a;	/* J */
1282 			jbuf[3] = a;
1283 			jx = 4;
1284 			break;
1285 		      default:		/* Current state is Roman */
1286 			jbuf[0] = a;
1287 			jx = 1;
1288 			break;
1289 		    }
1290 		    jstate = 0;		/* New state is Roman */
1291 		} else if (eu.x_char[byteorder] == 0x8e) { /* Kana */
1292 		    jx = 0;
1293 		    switch (jstate) {
1294 		      case 2:		   /* from Kanji */
1295 			jbuf[jx++] = 0x1b; /* ESC */
1296 			jbuf[jx++] = 0x28; /* ( */
1297 			jbuf[jx++] = 0x4a; /* J */
1298 		      case 0:		   /* from Roman */
1299 			jbuf[jx++] = 0x0e; /* SO */
1300 		      default:		   /* State is already Kana*/
1301 			jbuf[jx++] = (a & 0x7f); /* and the char */
1302 			break;
1303 		    }
1304 		    jstate = 1;		/* New state is Katakana */
1305 		} else {		/* Kanji */
1306 		    jx = 0;
1307 		    switch (jstate) {
1308 		      case 1:		/* Current state is Katakana */
1309 			jbuf[jx++] = 0x0f; /* SI  */
1310 		      case 0:		/* Current state is Roman */
1311 			jbuf[jx++] = 0x1b; /* ESC */
1312 			jbuf[jx++] = 0x24; /* $   */
1313 			jbuf[jx++] = 0x42; /* B   */
1314 		      default:		/* Current state is already Kanji */
1315 			jbuf[jx++] = eu.x_char[byteorder] & 0x7f;
1316 			jbuf[jx++] = eu.x_char[1-byteorder] & 0x7f;
1317 			break;
1318 		    }
1319 		    jstate = 2;		/* Set state to Kanji */
1320 		}
1321 		for (i = 0; i < jx; i++) /* Output the result */
1322 		  if ((rc = pnbyte(jbuf[i],fn)) < 0)
1323 		    return(rc);
1324 		return(jx);		/* Return its length */
1325 	    }
1326 	  default:
1327 	    if (sj.x_short < 0x80)
1328 	      return(sj.x_short);
1329 	    else
1330 	      return('?');
1331 	}
1332     }
1333 #endif /* KANJI */
1334 #endif /* UNICODE */
1335     debug(F100,"xpnbyte BAD FALLTHRU","",0);
1336     return(-1);
1337 }
1338 
1339 #ifndef NOXFER
1340 
1341 /*  D E C O D E  --  Kermit Data-packet decoder  */
1342 
1343 int
1344 #ifdef CK_ANSIC
decode(CHAR * buf,int (* fn)(char),int xlate)1345 decode(CHAR *buf, int (*fn)(char), int xlate)
1346 #else
1347 decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate;
1348 #endif /* CK_ANSIC */
1349 /* decode */ {
1350     register unsigned int a, a7, a8, b8; /* Various copies of current char */
1351     int t;				/* Int version of character */
1352     int ssflg;				/* Character was single-shifted */
1353     int ccpflg;				/* For Ctrl-unprefixing stats */
1354     int len;
1355     long z;
1356     CHAR c;
1357 /*
1358   Catch the case in which we are asked to decode into a file that is not open,
1359   for example, if the user interrupted the transfer, but the other Kermit
1360   keeps sending.
1361 */
1362     if ((cxseen || czseen || discard) && (fn == putfil))
1363       return(0);
1364 
1365 #ifdef COMMENT
1366 #ifdef CKTUNING
1367     if (binary && !parity)
1368       return(bdecode(buf,fn));
1369 #endif /* CKTUNING */
1370 #endif /* COMMENT */
1371     debug(F100,"DECODE","",0);
1372 
1373     xdbuf = buf;			/* Make global copy of pointer. */
1374     rpt = 0;				/* Initialize repeat count. */
1375 
1376     len = rln;				/* Number of bytes in data field */
1377     while (len > 0) {			/* Loop for each byte */
1378         a = *xdbuf++ & 0xff;		/* Get next character */
1379 	len--;
1380 	if (a == rptq && rptflg) {	/* Got a repeat prefix? */
1381 	    rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
1382 	    rptn += rpt;
1383 	    a = *xdbuf++ & 0xFF;	/* and get the prefixed character. */
1384 	    len -= 2;
1385 	}
1386 	b8 = lsstate ? 0200 : 0;	/* 8th-bit value from SHIFT-STATE */
1387 	if (ebqflg && a == ebq) {	/* Have 8th-bit prefix? */
1388 	    b8 ^= 0200;			/* Yes, invert the 8th bit's value, */
1389 	    ssflg = 1;			/* remember we did this, */
1390 	    a = *xdbuf++ & 0xFF;	/* and get the prefixed character. */
1391 	    len--;
1392 	} else ssflg = 0;
1393 	ccpflg = 0;
1394 	if (a == ctlq) {		/* If control prefix, */
1395 	    a  = *xdbuf++ & 0xFF;	/* get its operand */
1396 	    len--;
1397 	    a7 = a & 0x7F;		/* and its low 7 bits. */
1398 	    if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */
1399 		a = ctl(a);		/* if in control range. */
1400 		a7 = a & 0x7F;
1401 		ccpflg = 1;		/* Note that we did this */
1402 		ccp++;			/* Count for stats */
1403 	    }
1404 	} else a7 = a & 0x7f;		/* Not control quote */
1405 	if (a7 < 32 || a7 == 127) {	/* Control character? */
1406 	    if (!ccpflg) ccu++;		/* A bare one, count it */
1407 	    if (lscapu) {		/* If doing locking shifts... */
1408 		if (lsstate)		/* If SHIFTED */
1409 		  a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */
1410 		else			/* otherwise */
1411 		  a8 = a | b8;		/* OR in 8th bit */
1412 		/* If we're not in a quoted sequence */
1413 		if (!lsquote && (!lsstate || !ssflg)) {
1414 		    if (a8 == DLE) {	/* Check for DLE quote */
1415 			lsquote = 1;	/* prefixed by single shift! */
1416 			continue;
1417 		    } else if (a8 == SO) { /* Check for Shift-Out */
1418 			lsstate = 1;	/* SHIFT-STATE = SHIFTED */
1419 			continue;
1420 		    } else if (a8 == SI) { /* or Shift-In */
1421 			lsstate = 0;	/* SHIFT-STATE = UNSHIFTED */
1422 			continue;
1423 		    }
1424 		} else lsquote = 0;
1425 	    }
1426 	}
1427 	a |= b8;			/* OR in the 8th bit */
1428 	if (rpt == 0) rpt = 1;		/* If no repeats, then one */
1429 #ifndef NOCSETS
1430 	if (!binary) {			/* If in text mode, */
1431 	    if (tcharset != TC_UCS2) {
1432 		if (feol && a == CR)	/* Convert CRLF to newline char */
1433 		  continue;
1434 		if (feol && a == LF)
1435 		  a = feol;
1436 	    }
1437 	    if (xlatype == XLA_BYTE)	/* Byte-for-byte - do it now */
1438 	      if (xlate && rx) a = (*rx)((CHAR) a);
1439     	}
1440 #endif /* NOCSETS */
1441 	/* (PWP) Decoding speedup via buffered output and a macro... */
1442 	if (fn == putfil) {
1443 	    for (; rpt > 0; rpt--) {	/* Output the char RPT times */
1444 #ifdef CALIBRATE
1445 		if (calibrate) {
1446 		    ffc++;
1447 		    continue;
1448 		}
1449 #endif /* CALIBRATE */
1450 
1451 /* Note: The Unicode and Kanji sections can probably be combined now; */
1452 /* the Unicode method (xpnbyte()) covers Kanji too. */
1453 
1454 #ifdef UNICODE
1455 		if (!binary && xlatype == XLA_UNICODE)
1456 		  t = xpnbyte((unsigned)((unsigned)a & 0xff),
1457 			      tcharset,
1458 			      fcharset,
1459 			      fn
1460 			      );
1461 		else
1462 #endif /* UNICODE */
1463 #ifdef KANJI
1464 		if (!binary && tcharset == TC_JEUC &&
1465 		    fcharset != FC_JEUC) { /* Translating from J-EUC */
1466 		    if (!ffc) xkanjf();
1467 		    if (xkanji(a,fn) < 0)  /* to something else? */
1468 		      return(-1);
1469 		    else t = 1;
1470 		} else
1471 #endif /* KANJI */
1472 		{
1473 #ifdef OS2
1474 		      if (xflg && !remfile) { /* Write to virtual screen */
1475 			  char _a;
1476 			  _a = a & fmask;
1477 			  t = conoc(_a);
1478 			  if (t < 1)
1479 			    t = -1;
1480 		      } else
1481 #endif /* OS2 */
1482 			t = zmchout(a & fmask); /* zmchout is a macro */
1483 		}
1484 		if (t < 0) {
1485 		    debug(F101,"decode write errno","",errno);
1486 		    return(-1);
1487 		}
1488 #ifdef UNICODE
1489 		if (xlatype != XLA_UNICODE || binary) {
1490 		    ffc++;		/* Count the character */
1491 		    if (docrc && !xflg && !remfile) { /* Update file CRC */
1492 			c = a;		/* Force conversion to unsigned char */
1493 			z = crc16 ^ (long)c;
1494 			crc16 = (crc16 >> 8) ^
1495 			  (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
1496 		    }
1497 		}
1498 #endif /* UNICODE */
1499 	    }
1500 	} else {			/* Output to something else. */
1501 	    a &= fmask;			/* Apply file mask */
1502 	    for (; rpt > 0; rpt--) {	/* Output the char RPT times */
1503 #ifdef CALIBRATE
1504 		if (calibrate) {
1505 		    ffc++;
1506 		    continue;
1507 		}
1508 #endif /* CALIBRATE */
1509 		if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */
1510 	    }
1511 	}
1512 #ifdef CK_CTRLZ
1513 	lastchar = a;
1514 #endif /* CK_CTRLZ */
1515     }
1516     return(0);
1517 }
1518 
1519 /*  G E T P K T -- Fill a packet data field  */
1520 
1521 /*
1522   Gets characters from the current source -- file or memory string.
1523   Encodes the data into the packet, filling the packet optimally.
1524   Set first = 1 when calling for the first time on a given input stream
1525   (string or file).
1526 
1527   Call with:
1528     bufmax -- current send-packet size
1529     xlate  -- flag: 0 to skip character-set translation, 1 to translate
1530 
1531   Uses global variables:
1532     t     -- current character.
1533     first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
1534     next  -- next character (not used any more).
1535     data  -- pointer to the packet data buffer.
1536     size  -- number of characters in the data buffer.
1537     memstr - flag that input is coming from a memory string instead of a file.
1538     memptr - pointer to string in memory.
1539     (*sx)()  character set translation function
1540 
1541   Returns:
1542     The size as value of the function, and also sets global "size",
1543     and fills (and null-terminates) the global data array.
1544     Returns:
1545       0 on EOF.
1546      -1 on fatal (internal) error.
1547      -3 on timeout (e.g. when reading data from a pipe).
1548 
1549   Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
1550   Incorporates old getchx() and encode() inline to reduce function calls,
1551   uses buffered input for much-improved efficiency, and clears up some
1552   confusion with line termination (CRLF vs LF vs CR).
1553 
1554   Rewritten again by Frank da Cruz to incorporate locking shift mechanism,
1555   May 1991.  And again in 1998 for efficiency, etc, with a separate
1556   bgetpkt() split out for binary-mode no-parity transfers.
1557 */
1558 
1559 /*
1560   Note: Separate Kanji support dates from circa 1991 and now (1999) can most
1561   likely be combined with the the Unicode support: the xgnbyte()/xpnbyte()
1562   mechanism works for both Unicode and Kanji.
1563 */
1564 #ifdef KANJI
1565 int
kgetf(VOID)1566 kgetf(
1567 #ifdef CK_ANSIC
1568       VOID
1569 #endif /* CK_ANSIC */
1570       ) {
1571     if (funcstr)
1572       return((*funcptr)());
1573     else
1574       return(zminchar());
1575 }
1576 
1577 int
kgetm(VOID)1578 kgetm(
1579 #ifdef CK_ANSIC
1580       VOID
1581 #endif /* CK_ANSIC */
1582       ) {
1583     int x;
1584     if ((x = *memptr++)) return(x);
1585     else return(-1);
1586 }
1587 #endif /* KANJI */
1588 
1589 /*
1590   Lookahead function to decide whether locking shift is worth it.  Looks at
1591   the next four input characters to see if all of their 8th bits match the
1592   argument.  Call with 0 or 0200.  Returns 1 on match, 0 if they don't match.
1593   If we don't happen to have at least 4 more characters waiting in the input
1594   buffer, returns 1.  Note that zinptr points two characters ahead of the
1595   current character because of repeat-count lookahead.
1596 */
1597 int
lslook(b)1598 lslook(b) unsigned int b; {		/* Locking Shift Lookahead */
1599     int i;
1600     if (zincnt < 3)			/* If not enough chars in buffer, */
1601       return(1);			/* force shift-state switch. */
1602     b &= 0200;				/* Force argument to proper form. */
1603     for (i = -1; i < 3; i++)		/* Look at next 5 characters to */
1604       if (((*(zinptr+i)) & 0200) != b)	/* see if all their 8th bits match.  */
1605 	return(0);			/* They don't. */
1606     return(1);				/* They do. */
1607 }
1608 
1609 /* Routine to compute maximum data length for packet to be filled */
1610 
1611 int
maxdata()1612 maxdata() {				/* Get maximum data length */
1613     int n, len;
1614     debug(F101,"maxdata spsiz 1","",spsiz);
1615     if (spsiz < 0)			/* How could this happen? */
1616       spsiz = DSPSIZ;
1617     debug(F101,"maxdata spsiz 2","",spsiz);
1618     n = spsiz - 5;			/* Space for Data and Checksum */
1619     if (n > 92 && n < 96) n = 92;	/* "Short" Long packets don't pay */
1620     if (n > 92 && lpcapu == 0)		/* If long packets needed, */
1621       n = 92;				/* make sure they've been negotiated */
1622     len = n - bctl;			/* Space for data */
1623     if (n > 92) len -= 3;		/* Long packet needs header chksum */
1624     debug(F101,"maxdata len 1","",len);
1625     if (len < 0) len = 10;
1626     debug(F101,"maxdata len 2","",len);
1627     return(len);
1628 }
1629 
1630 static CHAR leftover[9] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0' };
1631 static int nleft = 0;
1632 
1633 #ifdef CKTUNING
1634 /*
1635   When CKTUNING is defined we use this special trimmed-down version of getpkt
1636   to speed up binary-mode no-parity transfers.  When CKTUNING is not defined,
1637   or for text-mode or parity transfers, we use the regular getpkt() function.
1638   Call just like getpkt() but test first for transfer mode and parity.  NOTE:
1639   This routine is only to be called when sending a real file -- not for
1640   filenames, server responses, etc, because it only reads from the input file.
1641   See getpkt() for more detailed commentary.
1642 */
1643 static int
bgetpkt(bufmax)1644 bgetpkt(bufmax) int bufmax; {
1645     register CHAR rt = t, rnext;
1646     register CHAR *dp, *odp, *p1, *p2;
1647     register int x = 0, a7;
1648 
1649     CHAR xxrc, xxcq;			/* Pieces of prefixed sequence */
1650 
1651     long z;				/* A long worker (for CRC) */
1652 
1653     if (!binary || parity || memstr)	/* JUST IN CASE caller didn't test */
1654       return(getpkt(bufmax,!binary));
1655 
1656     if (!data) {
1657 	debug(F100,"SERIOUS ERROR: bgetpkt data == NULL","",0);
1658 	return(-1);
1659     }
1660     dp = data;				/* Point to packet data buffer */
1661     size = 0;				/* And initialize its size */
1662     bufmax = maxdata();			/* Get maximum data length */
1663 
1664 #ifdef DEBUG
1665     if (deblog)
1666       debug(F101,"bgetpkt bufmax","",bufmax);
1667 #endif /* DEBUG */
1668 
1669     if (first == 1) {			/* If first character of this file.. */
1670 	ffc = (CK_OFF_T)0;		/* reset file character counter */
1671 #ifdef COMMENT
1672 /* Moved to below */
1673 	first = 0;			/* Next character won't be first */
1674 #endif /* COMMENT */
1675 	*leftover = '\0';		/* Discard any interrupted leftovers */
1676 	nleft = 0;
1677 
1678 	/* Get first character of file into rt, watching out for null file */
1679 
1680 #ifdef CALIBRATE
1681 	if (calibrate) {
1682 #ifdef NORANDOM
1683 	    rt = 17;
1684 #else
1685 	    rt = cal_a[rand() & 0xff];
1686 #endif /* NORANDOM */
1687 	    first = 0;
1688 	} else
1689 #endif /* CALIBRATE */
1690 
1691 	if ((x = zminchar()) < 0) {	/* EOF or error */
1692 	    if (x == -3) {		/* Timeout. */
1693 		size = (dp - data);
1694 		debug(F101,"bgetpkt timeout size","",size);
1695 		return((size == 0) ? x : size);
1696 	    }
1697 	    first = -1;
1698 	    size = 0;
1699 	    if (x == -2) {		/* Error */
1700 		debug(F100,"bgetpkt: input error","",0);
1701 		cxseen = 1;		/* Interrupt the file transfer */
1702 	    } else {
1703 		debug(F100,"bgetpkt empty file","",0);
1704 	    }
1705 	    return(0);
1706 	}
1707 	first = 0;			/* Next char will not be the first */
1708 	ffc++;				/* Count a file character */
1709 	rt = (CHAR) x;			/* Convert int to char */
1710 	if (docrc && (what & W_SEND)) {	/* Accumulate file crc */
1711 	    z = crc16 ^ (long)rt;
1712 	    crc16 = (crc16 >> 8) ^
1713 	      (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
1714 	}
1715 	rt &= fmask;			/* Apply SET FILE BYTESIZE mask */
1716 
1717     } else if (first == -1 && nleft == 0) { /* EOF from last time */
1718 
1719         return(size = 0);
1720     }
1721 /*
1722   Here we handle characters that were encoded for the last packet but
1723   did not fit, and so were saved in the "leftover" array.
1724 */
1725     if (nleft) {
1726 	for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */
1727 	  *dp++ = *p1++;
1728 	*leftover = '\0';		/* Delete leftovers */
1729 	nleft = 0;
1730     }
1731     if (first == -1)			/* Handle EOF */
1732       return(size = (dp - data));
1733 
1734 /* Now fill up the rest of the packet. */
1735 
1736     rpt = 0;				/* Initialize character repeat count */
1737 
1738     while (first > -1) {		/* Until EOF... */
1739 #ifdef CALIBRATE
1740 	if (calibrate) {		/* We generate our own "file" */
1741 	    if (ffc >= calibrate) {	/* EOF */
1742 		first = -1;
1743 		ffc--;
1744 	    } else {			/* Generate next character */
1745 		if (cal_j > CAL_M * ffc)
1746 		  cal_j = cal_a[ffc & 0xff];
1747 		x = (unsigned)cal_a[(cal_j & 0xff)];
1748 		if (x == rt) x ^= 2;
1749 	    }
1750 	    ffc++;
1751 	    cal_j += (unsigned int)(ffc + CAL_O);
1752 	} else
1753 #endif /* CALIBRATE */
1754 	if ((x = zminchar()) < 0) {	/* Check for EOF */
1755 	    if (x == -3) {		/* Timeout. */
1756 		t = rt;
1757 		size = (dp-data);
1758 		debug(F101,"bgetpkt timeout size","",size);
1759 		return((size == 0) ? x : size);
1760 	    }
1761 	    first = -1;			/* Flag eof for next time. */
1762 	    if (x == -2) cxseen = 1;	/* If error, cancel this file. */
1763 	} else {
1764 	    ffc++;			/* Count the character */
1765 	    if (docrc && (what & W_SEND)) { /* Accumulate file crc */
1766 		z = crc16 ^ (long)((CHAR)x & 0xff);
1767 		crc16 = (crc16 >> 8) ^
1768 		  (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
1769 	    }
1770 	}
1771 	rnext = (CHAR) (x & fmask);	/* Apply file mask */
1772 /*
1773   At this point, the character we just read is in rnext,
1774   and the character we are about to encode into the packet is in rt.
1775 */
1776 	odp = dp;			/* Remember where we started. */
1777 	xxrc = xxcq = NUL;		/* Clear these. */
1778 /*
1779   Now encode the character according to the options that are in effect:
1780     ctlp[]: whether this control character needs prefixing.
1781     rptflg: repeat counts enabled.
1782     Other options don't apply in this routine.
1783 */
1784 	if (rptflg && (rt == rnext) && (first == 0)) { /* Got a run... */
1785 	    if (++rpt < 94) {		/* Below max, just count */
1786 		continue;		/* go back and get another */
1787 	    } else if (rpt == 94) {	/* Reached max, must dump */
1788 		xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
1789 		rptn += rpt;		/* Accumulate it for statistics */
1790 		rpt = 0;		/* And reset it */
1791 	    }
1792 	} else if (rpt > 0) {		/* End of run */
1793 	    xxrc = (CHAR)tochar(++rpt); /* The count */
1794 	    rptn += rpt;		/* For stats */
1795 	    rpt = 0;			/* Reset repeat count */
1796 	}
1797 	a7 = rt & 0177;			/* Get low 7 bits of character */
1798 	if (
1799 #ifdef CK_SPEED
1800 	    ctlp[(unsigned)(rt & 0xff)]	/* Lop off any "sign" extension */
1801 #else
1802 	    (a7 < SP) || (a7 == DEL)
1803 #endif /* CK_SPEED */
1804 	    ) {				/* Do control prefixing if necessary */
1805 	    xxcq = myctlq;		/* The prefix */
1806 	    ccp++;			/* Count it */
1807 	    rt = (CHAR) ctl(rt);	/* Uncontrollify the character */
1808 	}
1809 #ifdef CK_SPEED
1810 	else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
1811 	  ccu++;
1812 #endif /* CK_SPEED */
1813 
1814 	if (a7 == myctlq)		/* Always prefix the control prefix */
1815 	  xxcq = myctlq;
1816 
1817 	if ((rptflg) && (a7 == rptq))	/* If it's the repeat prefix, */
1818 	  xxcq = myctlq;		/* prefix it if doing repeat counts */
1819 
1820 /* Now construct the prefixed sequence */
1821 
1822 	if (xxrc) {			/* Repeat count */
1823 #ifdef COMMENT
1824 	    if (xxrc == (CHAR) '"' && !xxcq) { /* 2 in a row & not prefixed */
1825 		*dp++ = rt;		/* So just do this */
1826 	    } else {			/* More than two or prefixed */
1827 		*dp++ = (CHAR) rptq; *dp++ = xxrc; /* Emit repeat sequence */
1828 	    }
1829 #else					/* CHECK THIS */
1830 	    if (xxrc == (CHAR) '"' && !xxcq) { /* 2 in a row & not prefixed */
1831                 if (dp == data) {
1832                     *dp++ = rt;		/* So just do this */
1833                 } else if (*(dp-1) == rt) {
1834                     *dp++ = (CHAR) rptq;
1835 		    *dp++ = xxrc;	/* Emit repeat sequence */
1836                 } else {
1837                     *dp++ = rt;		/* So just do this */
1838                 }
1839 	    } else {			/* More than two or prefixed */
1840 		*dp++ = (CHAR) rptq;
1841 		*dp++ = xxrc;		/* Emit repeat sequence */
1842 	    }
1843 #endif /* COMMENT */
1844 	}
1845 	if (xxcq) { *dp++ = myctlq; }	/* Control prefix */
1846 	*dp++ = rt;			/* Finally, the character itself */
1847 	rt = rnext;			/* Next character is now current. */
1848 
1849 /* Done encoding the character.  Now take care of packet buffer overflow. */
1850 
1851 	size = dp - data;		/* How many bytes we put in buffer. */
1852 	if (size >= bufmax) {		/* If too big, save some for next. */
1853 	    *dp = '\0';			/* Mark the end. */
1854 	    if (size > bufmax) {	/* if packet is overfull */
1855 		/* Copy the part that doesn't fit into the leftover buffer, */
1856 		/* taking care not to split a prefixed sequence. */
1857 		int i;
1858 		nleft = dp - odp;
1859 		p1 = leftover;
1860 		p2 = odp;
1861 		for (i = 0; i < nleft; i++)
1862 		  *p1++ = *p2++;
1863 		size = odp - data;	/* Return truncated packet. */
1864 		*odp = '\0';		/* Mark the new end */
1865 	    }
1866 	    t = rt;			/* Save for next time */
1867 	    return(size);
1868 	}
1869     }					/* Otherwise, keep filling. */
1870     size = dp - data;			/* End of file */
1871     *dp = '\0';				/* Mark the end of the data. */
1872     return(size);		     /* Return partially filled last packet. */
1873 }
1874 #endif /* CKTUNING */
1875 
1876 VOID
dofilcrc(c)1877 dofilcrc(c) int c; {			/* Accumulate file crc */
1878     long z;
1879     z = crc16 ^ (long)c;
1880     crc16 = (crc16 >> 8) ^
1881       (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
1882 }
1883 
1884 /* For SENDing from an array... */
1885 
1886 int
agnbyte()1887 agnbyte() {				/* Get next byte from array */
1888 #ifndef NOSPL
1889     char c;
1890     static int save = 0;		/* For CRLF */
1891     static char ** ap = NULL;		/* Array pointer */
1892     static char * p = NULL;		/* Character pointer */
1893     static int i = 0, n = 0;		/* Array index and limit */
1894     extern int a_dim[];			/* Array dimension */
1895 
1896     if (!ap) {				/* First time thru */
1897 	ap = sndarray;			/* Set up array pointers */
1898 	if (!ap || (i = sndxlo) > a_dim[sndxin]) {
1899 	    sndarray = NULL;
1900 	    ap = NULL;
1901 	    return(-1);
1902 	}
1903 	p = ap[i];			/* Point to first element in range */
1904 	n = sndxhi;			/* Index of last element in range */
1905 	if (sndxhi > a_dim[sndxin])	/* Adjust if necessary */
1906 	  n = a_dim[sndxin];
1907     }
1908     if (save) {				/* If anything saved */
1909 	c = save;			/* unsave it */
1910 	save = 0;			/* and return it */
1911 	return(c & 0xff);
1912     }
1913     if (i > n) {			/* No more elements */
1914 	sndarray = NULL;
1915 	ap = NULL;
1916 	return(-1);
1917     }
1918     if (!p)				/* Source pointer is NULL */
1919       c = NUL;				/* this means an empty line */
1920     else				/* Source pointer not NULL */
1921       c = *p++;				/* Next char */
1922     if (!c) {				/* Char is empty? */
1923 	if (!binary) {			/* Text: end of line. */
1924 	    if (feol) {			/* Supply NL */
1925 		c = feol;
1926 	    } else {			/* or CRLF */
1927 		save = LF;
1928 		c = CR;
1929 	    }
1930 	    p = ap[++i];
1931 	    return(c & 0xff);
1932 	}
1933 	while (i++ < n) {		/* Binary - get next element */
1934 	    p = ap[i];
1935 	    if (!p)			/* Empty line? */
1936 	      continue;			/* Ignore it and get another */
1937 	    c = *p++;			/* Get next char */
1938 	    if (!c)			/* Emtpy char? */
1939 	      continue;			/* Ignore it and get another */
1940 	    return(c & 0xff);		/* Not empty - return it */
1941 	}
1942 	sndarray = NULL;
1943 	ap = NULL;
1944 	return(-1);			/* Done */
1945     }
1946     return(c & 0xff);			/* Char is not empty */
1947 #else
1948     sndarray = NULL;
1949     return(-1);
1950 #endif /* NOSPL */
1951 }
1952 #endif /* NOXFER */
1953 
1954 #ifndef NOCSETS
1955 static CHAR xlabuf[32] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1956 static int xlacount = 0;
1957 static int xlaptr = 0;
1958 /* static USHORT lastucs2 = 0; */
1959 
1960 /*
1961   X G N B Y T E --  Get next translated byte from the input file.
1962 
1963   Returns the next byte that is to be put into the packet, already translated.
1964   This isolates getpkt() from having to know anything about translation,
1965   single- vs multibyte character sets, one-to-many vs many-to-one, etc, but it
1966   has rather high overhead, so don't call it unless you know translation is
1967   needed to or from Unicode, Japanese, or other multibyte character set.
1968 
1969   Call with:
1970     fcs:  File character set (source, file we are reading from)
1971     tcs:  Target character set (use an FC_xxx code, not a TC_xxx code)
1972   Returns:
1973     >= 0: A translated byte suitable for writing.
1974     <  0: Fatal error (such as EOF on input source).
1975   As of Sat Sep  7 18:37:41 2002:
1976     When the output character-set is UCS-2, bytes are ALWAYS returned in
1977     big-endian order (previously they could also be returned in LE order
1978     under certain conditions, which was just way too confusing).
1979 */
1980 int
1981 #ifdef CK_ANSIC
xgnbyte(int tcs,int fcs,int (* fn)(void))1982 xgnbyte(int tcs, int fcs, int (*fn)(void))
1983 #else /* CK_ANSIC */
1984 xgnbyte(tcs,fcs,fn) int tcs, fcs, (*fn)();
1985 #endif /* CK_ANSIC */
1986 /* xgnbyte */ {
1987     _PROTOTYP( int (*xx), (USHORT) ) = NULL;
1988     int haveuc = 0;			/* Flag for have Unicode character */
1989 #ifdef KANJI
1990     int havesj = 0;			/* Have Shift-JIS character */
1991     int haveeu = 0;			/* Have EUC-JP character */
1992 #endif /* KANJI */
1993     int rc = -1, x = 0, flag = 0;
1994     int utferror = 0;
1995     int eolflag = 0;
1996     unsigned int xc, thischar;
1997     static int swapping = 0;
1998     CHAR rt;
1999     /* USHORT ch; */
2000 #ifdef UNICODE
2001     union ck_short uc;
2002 #endif /* UNICODE */
2003 #ifdef KANJI
2004     union ck_short sj, eu;		/* Shift-JIS character */
2005 #endif /* KANJI */
2006 
2007 #ifdef KANJI
2008     sj.x_short = 0;
2009 #endif /* KANJI */
2010 
2011 #ifdef DEBUG
2012     if (deblog && !ffc) {
2013 	debug(F101,"xgnbyte initial swap","",swapping);
2014     }
2015 #endif /* DEBUG */
2016 
2017     if (xlacount-- > 0) {		/* We already have some */
2018 	x = xlabuf[xlaptr++];
2019 	debug(F001,"xgnbyte from buf","",x);
2020 	return(x);
2021     }
2022     if (xlatype != XLA_NONE) {		/* Not not translating... */
2023 	haveuc = 0;
2024 #ifdef UNICODE
2025 	if (fcs == FC_UCS2) {		/* UCS-2: Read two bytes */
2026 	    if (!ffc)			/* Beginning of file? */
2027 	      swapping = 0;		/* Reset byte-swapping flag */
2028 	    uc.x_short = 0;
2029 	  bomskip:
2030 	    x = fn ? (*fn)() : zminchar(); /* Get first byte */
2031 	    debug(F001,"zminchar swapping","",swapping);
2032 	    debug(F001,"zminchar C0","",x);
2033 	    flag = 1;			/* Remember we called zminchar() */
2034 	    if (x > -1) {		/* Didn't fail */
2035 		ffc++;			/* Count a file byte */
2036 		uc.x_char[swapping] = x & 0xff;
2037 #ifndef NOXFER
2038 		if (docrc && (what & W_SEND))
2039 		  dofilcrc(x);
2040 #endif /* NOXFER */
2041 		x = fn ? (*fn)() : zminchar(); /* Get second byte */
2042 		if (x > -1) {		/* If didn't fail */
2043 		    debug(F001,"zminchar C1","",x);
2044 		    ffc++;		/* count another file byte */
2045 		    uc.x_char[1-swapping] = x & 0xff;
2046 		    haveuc = 1;		/* And remember we have Unicode */
2047 #ifndef NOXFER
2048 		    if (docrc && (what & W_SEND))
2049 		      dofilcrc(x);
2050 #endif /* NOXFER */
2051 		    if (ffc == (CK_OFF_T)2) { /* Second char of file */
2052 			debug(F001,"xgnbyte 1st UCS2","",uc.x_short);
2053 			debug(F111,"xgnbyte fileorder","A",fileorder);
2054 			if (fileorder < 0) /* Byte order of this file */
2055 			  fileorder = ucsorder;	/* Default is ucsorder */
2056 			if (fileorder > 1)
2057 			  fileorder = 1;
2058 			debug(F111,"xgnbyte fileorder","B",fileorder);
2059 			if (uc.x_short == (USHORT)0xfeff) {
2060 			    swapping = 0;
2061 			    debug(F101,
2062 				  "xgnbyte UCS2 goodbom swap","",swapping);
2063 			    fileorder = byteorder; /* Note: NOT 0 */
2064 			    goto bomskip;
2065 			} else if (uc.x_short == (USHORT)0xfffe) {
2066 			    swapping = 1;
2067 			    debug(F101,
2068 				  "xgnbyte UCS2 badbom swap","",swapping);
2069 			    fileorder = (1 - byteorder); /* Note: NOT 1 */
2070 			    goto bomskip;
2071 			} else if ((byteorder && !fileorder) || /* No BOM */
2072 				   (!byteorder && fileorder > 0)) {
2073 			    /* fileorder might have been set by scanfile() */
2074 			    CHAR c;
2075 			    c = uc.x_char[0];
2076 			    uc.x_char[0] = uc.x_char[1];
2077 			    uc.x_char[1] = c;
2078 			    swapping = 1;
2079 			    debug(F111,"xgnbyte UCS2 noBOM swap","A",swapping);
2080 			} else {
2081 			    swapping = 0;
2082 			    debug(F111,"xgnbyte UCS2 noBOM swap","B",swapping);
2083 			}
2084 			debug(F111,"xgnbyte fileorder","C",fileorder);
2085 		    }
2086 		} else
2087 		  return(x);
2088 	    } else
2089 	      return(x);
2090 	    debug(F001,"xgnbyte UCS2","",uc.x_short);
2091 
2092 	} else if (fcs == FC_UTF8) {	/* File is UTF-8 */
2093 	    CHAR ch = 0;		/* Data types needed for API... */
2094 	    USHORT * us = NULL;
2095 	    uc.x_short = 0;
2096 	    flag = 1;			/* We (will) have called zminchar() */
2097 	    /* Read source bytes */
2098 	    while ((x = fn ? (*fn)() : zminchar()) > -1) {
2099 		ffc++;			/* Got a byte - count it */
2100 #ifndef NOXFER
2101 		if (docrc && (what & W_SEND))
2102 		  dofilcrc(x);
2103 #endif /* NOXFER */
2104 		ch = x;
2105 		rc = utf8_to_ucs2(ch,&us); /* Convert to UCS-2 */
2106 		if (rc == 0) {		/* Done */
2107 		    uc.x_short = *us;
2108 		    haveuc = 1;
2109 		    break;
2110 		} else if (rc < 0) {	/* Error */
2111 		    utferror = 1;
2112 		    debug(F101,"xgnbyte UTF-8 input error","",rc);
2113 		    haveuc = 1;
2114 		    uc.x_short = *us;
2115 		    break;
2116 		}
2117 	    }
2118 	    if (x < 0)
2119 	      return(x);
2120 	    debug(F001,"xgnbyte UTF8->UCS2","",uc.x_short);
2121 	}
2122 #endif /* UNICODE */
2123 
2124 #ifdef KANJI
2125 #ifdef UNICODE
2126 	else
2127 #endif /* UNICODE */
2128 	  if (fcsinfo[fcs].alphabet == AL_JAPAN) { /* Japanese source file */
2129 	    int c7, x, y;
2130 	    if (fcs == FC_JIS7) {	/* If file charset is JIS-7 */
2131 		if (!ffc)		/* If first byte of file */
2132 		  j7init();		/* Initialize JIS-7 parser */
2133 		x = getj7();		/* Get a JIS-7 byte */
2134 	    } else			/* Otherwise */
2135 	      x = fn ? (*fn)() : zminchar(); /* Just get byte */
2136 	    if (x < 0) {		/* Propogate EOF or error */
2137 		debug(F100,"XGNBYTE EOF","",0);
2138 		return(x);
2139 	    }
2140 	    debug(F001,"XGNBYTE x","",x);
2141 	    ffc++;			/* Count */
2142 #ifndef NOXFER
2143 	    if (docrc && (what & W_SEND)) dofilcrc(x); /* Do CRC */
2144 #endif /* NOXFER */
2145 	    switch (fcs) {		/* What next depends on charset */
2146 	      case FC_SHJIS:		/* Shift-JIS */
2147 		if ((x <= 0x80) ||	/* Any 7-bit char... */
2148 		    (x >= 0xa0 && x <= 0xdf)) { /* or halfwidth Katakana */
2149 		    sj.x_short = (USHORT) x;    /* we read one byte. */
2150 		} else {		/* Anything else */
2151 		    if ((y = fn ? (*fn)() : zminchar()) < 0) /* get another */
2152 		      return(y);
2153 #ifndef NOXFER
2154 		    if (docrc && (what & W_SEND)) dofilcrc(y);
2155 #endif /* NOXFER */
2156 		    ffc++;
2157 		    sj.x_char[byteorder] = (CHAR) x;
2158 		    sj.x_char[1-byteorder] = (CHAR) y;
2159 		}
2160 		break;
2161 
2162 	      case FC_JIS7:		/* JIS-7 */
2163 	      case FC_JDEC:		/* DEC Kanji */
2164 	      case FC_JEUC:		/* EUC-JP */
2165 		if ((x & 0x80) == 0) {	/* Convert to Shift-JIS */
2166 		    sj.x_short = (USHORT) x; /* C0 or G0: one byte */
2167 		    eu.x_short = (USHORT) x;
2168 		    haveeu = 1;
2169 		} else {
2170 		    c7 = x & 0x7f;
2171 		    if (c7 > 0x20 && c7 < 0x7f) { /* Kanji: two bytes */
2172 			if ((y = (fcs == FC_JEUC) ?
2173 			     (fn ? (*fn)() : zminchar()) :
2174 			     getj7()	/* ^^^ */
2175 			     ) < 0)
2176 			  return(y);
2177 			ffc++;
2178 #ifndef NOXFER
2179 			if (docrc && (what & W_SEND)) dofilcrc(y);
2180 #endif /* NOXFER */
2181 			eu.x_char[byteorder] = (CHAR) x;
2182 			eu.x_char[1-byteorder] = (CHAR) y;
2183 			sj.x_short = eu_to_sj(eu.x_short);
2184 			haveeu = 1;
2185 		    } else if (x == 0x8e) { /* SS2 Katakana prefix: 2 bytes */
2186 			if ((y = (fcs == FC_JIS7) ?
2187 			     getj7() :	/* ^^^ */
2188 			     (fn ? (*fn)() : zminchar())
2189 			     ) < 0)
2190 			  return(y);
2191 			ffc++;
2192 #ifndef NOXFER
2193 			if (docrc && (what & W_SEND)) dofilcrc(y);
2194 #endif /* NOXFER */
2195 			sj.x_short = y | 0x80;
2196 			debug(F001,"XGNBYTE KANA SJ","",sj.x_short);
2197 		    } else {
2198 			/* Something that translates to U+FFFD */
2199 			sj.x_short = UNKSJIS;
2200 		    }
2201 		}
2202 		break;
2203 	    }
2204 	    havesj = 1;			/* Have Shift-JIS */
2205 #ifdef UNICODE
2206 	    uc.x_short = sj_to_un(sj.x_short); /* Translate to UCS-2 */
2207 	    haveuc = 1;			/* Have Unicode */
2208 #endif /* UNICODE */
2209 	    flag = 1;			/* Have a char */
2210 	}
2211 #endif /* KANJI */
2212     }
2213     if (!flag) {			/* If no character was read yet... */
2214 	if ((x = (fn ? (*fn)() : zminchar())) > -1)	/* read one now */
2215 	  ffc++;
2216 	debug(F101,"xgnbyte zminchar 1","",x);
2217 	if (x < 0)
2218 	  return(x);
2219 	haveuc = 0;
2220     }
2221 #ifdef UNICODE
2222     if (haveuc) {
2223 	thischar = uc.x_short;
2224 	/* lastucs2 = uc.x_short; */
2225     } else
2226 #endif /* UNICODE */
2227       thischar = x;
2228     debug(F001,"xgnbyte thischar",haveuc ? "[UNICODE]" : "[other]",thischar);
2229 
2230 #ifdef CK_CTRLZ				/* SET EOF CTRLZ */
2231     if (eofmethod == XYEOF_Z && !binary && thischar == 26) {
2232 	debug(F100,"xgnbyte EOF on Ctrl-Z 1","",0);
2233 	return(-1);
2234     }
2235 #endif /* CK_CTRLZ */
2236 
2237 #ifdef UNICODE
2238     if (!haveuc)			/* If not Unicode... */
2239 #endif /* UNICODE */
2240       x &= fmask;			/* Apply SET FILE BYTESIZE mask */
2241 
2242     switch (xlatype) {			/* Translation type... */
2243 #ifdef UNICODE
2244       case XLA_UNICODE: {		/* Unicode is involved */
2245 	  xc = 0;
2246 /*
2247   Here we must choose the appropriate translation function.  If we are being
2248   called by getpkt() (i.e. when transferring a file), we are translating from
2249   Unicode to the Transfer Character Set and therefore must use the function
2250   pointed to by xut.  Otherwise, e.g. during TRANSLATE, CONNECT, TRANSMIT, etc,
2251   we are translating from Unicode to the File Character Set and so must call
2252   the function pointed to by xuf.  There might be a cleaner way to set this
2253   up but I don't think so.  For example, setxlatype() might have been called
2254   too soon and so might not have known whether it was a file transfer or a
2255   local operation.
2256 */
2257 /*
2258   (Many years later...) In testing this code I noticed that TRANSLATE'ing
2259   Russian text from UTF-8 to ISO Latin/Cyrillic produced all question marks.
2260   Rereading the previous paragraph it seems to me we are (I am) overloading
2261   this function with responsibilites, satisfying the needs of file transfer
2262   (local file charset -> transfer charset for outbound packet) and local file
2263   conversion.  In the case of TRANSLATE, we call (xgnbyte(), xpnbyte()) in a
2264   loop, expecting the xgnbyte() will feed UCS2 to xpnbyte().  But the
2265   following code does what xpnbyte() is going to do, returning (in this case)
2266   an ISO Latin/Cyrillic byte stream, which xpnbyte() believes to be UCS2, and
2267   comes up with nonsense.  Not wanting to rip the whole thing apart and start
2268   over, I made the following change that should do no harm, upon observing
2269   that if the input character set is UTF-8 or UCS-2, then when we get here it
2270   has already been converted to UCS2, so if we are not transferring a file, we
2271   don't need to do anything else except put the bytes in the right place to be
2272   returned, which is done further along.
2273 */
2274 #ifdef COMMENT
2275 	  /* Previous code */
2276 	  xx = (what & W_SEND) ? xut : xuf;
2277 #else
2278 	  /* New code 2011-06-03 */
2279 	  if (what & W_SEND) {
2280 	      xx = xut;
2281 	  } else {
2282 	      if (fcs == FC_UCS2 || fcs == FC_UTF8)
2283 		xx = NULL;
2284 	      else
2285 		xx = xuf;
2286 	  }
2287 #endif	/* COMMENT */
2288 
2289 	  eolflag = 0;
2290 	  if (haveuc) {			/* File is Unicode */
2291 	      /* See Unicode TR13, "Converting to Other Character Sets" */
2292 	      if (uc.x_short == 0x2028 || /* Line Separator? */
2293 		  uc.x_short == 0x2029 || /* Paragraph Separator */
2294 		  (feol && (uc.x_short == (USHORT)feol))
2295 		  ) {
2296 		  debug(F001,"xgnbyte uc eol","",uc.x_short);
2297 		  rc = 0;
2298 		  eolflag = 1;		/* Don't translate and handle later */
2299 	      }
2300 	      if (xx && !eolflag) {	/* UCS-to-TCS function (UCS->byte) */
2301 		  rc = (*xx)(uc.x_short); /* These can fail... */
2302 		  debug(F101,"xgnbyte xx rc","",rc);
2303 		  if (rc < 0)		/* If it can't be translated */
2304 		    uc.x_short = UNK;	/* Put unknown-character symbol */
2305 		  else
2306 		    uc.x_short = (unsigned)((unsigned)rc & 0xffff);
2307 		  debug(F101,"xgnbyte xx uc","",uc.x_short);
2308 	      }
2309 #ifdef KANJI
2310 	      if (tcs == FC_JEUC) {	/* Translating to EUC-JP */
2311 		  USHORT sj = 0;
2312 		  union ck_short eu;
2313 		  debug(F001,"xgnbyte UCS->EUC UCS","",uc.x_short);
2314 		  if (!havesj)		/* If we don't already have it */
2315 		    sj = un_to_sj(uc.x_short); /* convert to Shift-JIS */
2316 		  eu.x_short = sj_to_eu(sj);
2317 		  debug(F001,"xgnbyte UCS->EUC EUC","",eu.x_short);
2318 		  xlaptr = 0;
2319 		  xlacount = 0;
2320 		  if (eolflag) {
2321 		      if (what & W_SEND) {
2322 			  xlabuf[xlacount++] = LF;
2323 			  return(CR);
2324 		      } else {
2325 			  return(feol);
2326 		      }
2327 		  }
2328 		  if (eu.x_char[byteorder]) {	/* Two bytes */
2329 		      rc = eu.x_char[byteorder];
2330 		      xlabuf[xlacount++] = eu.x_char[1-byteorder];
2331 		      debug(F001,"xgnbyte UCS->EUC xlabuf[0]","",xlabuf[0]);
2332 		  } else {		/* One byte */
2333 		      rc = eu.x_char[1-byteorder];
2334 		  }
2335 		  debug(F101,"xgnbyte UCS->EUC xlacount","",xlacount);
2336 		  debug(F001,"xgnbyte UCS->EUC rc","",rc);
2337 		  return(rc);
2338 	      } else
2339 #endif /* KANJI */
2340 	      if (tcs != FC_UCS2 && tcs != FC_UTF8) {
2341 		  if (uc.x_short & 0xff00) {	/* Decoding error */
2342 		      debug(F001,"xgnbyte decoding error","",uc.x_short);
2343 		      return(-2);
2344 		  } else
2345 		    return((unsigned int)(uc.x_short & 0xff));
2346 	      }
2347 	      xc = uc.x_short;
2348 
2349 	  } else {			/* File is not Unicode */
2350 	      USHORT ch;
2351 	      /* Translate from single FCS byte to UCS-2 */
2352 /*
2353   This is a bit nonobvious...  The blah_u() (Blah-to-Unicode) routines are
2354   called only with pieces of character sets, in the ISO 2022 sense.  So,
2355   for example, if ch is a Latin-1 character, we call the translation
2356   routine only if it is in the right half; if it's in the left half, it
2357   isn't translated, and in fact will give the wrong result if sent to the
2358   translation function.  That's because those functions were designed for
2359   use with the ISO 2022 G0..G3 sets, not for file transfer.  On the other
2360   hand, if it's a 7-bit character set, we *do* call the translation
2361   function.  (To put it another way, the left half of any 8-bit character
2362   set is ASCII and therefore doesn't need to be translated but 7-bit sets
2363   such as ISO 646 German do need translation).
2364 */
2365 	      ch = (unsigned)(thischar & 0xff);
2366 	      if (((fcsinfo[fcs].size > 128) && (ch & 0x80)) ||
2367 		  fcsinfo[fcs].size <= 128) {
2368 		  if (xfu) {		 /* FCS-to-UCS function */
2369 		      ch = (*xfu)(ch);
2370 		  }
2371 	      }
2372 	      xc = ch;
2373 	  }
2374 	  /* At this point we have a UCS-2 character in native format */
2375 	  /* (Big Endian or Little Endian) in xc, which is an unsigned int. */
2376 
2377 	  debug(F001,"xgnbyte xc","",xc);
2378 
2379 	  if (tcs == FC_UTF8) {		/* Now convert to UTF-8 */
2380 	      USHORT c;			/* NOTE: this is FC_UTF8 on purpose! */
2381 	      CHAR * buf = NULL;
2382 	      int i, k = 0, x;
2383 
2384 	      xlaptr = 0;
2385 	      if (utferror) {
2386 		  xlabuf[k++] = 0xff;
2387 		  xlabuf[k++] = 0xbd;
2388 	      }
2389 	      if (eolflag) {		/* We detected EOL in source file */
2390 		  if (what & W_SEND) {	/* Convert to CRLF */
2391 		      xlabuf[k++] = LF;
2392 		      xlacount = k;
2393 		      return((unsigned int)CR);
2394 #ifdef COMMENT
2395 		  } else {		/* Or to local line-end */
2396 		      xlacount = k;
2397 		      return((unsigned int)feol);
2398 #endif /* COMMENT */
2399 		  }
2400 	      }
2401 	      c = xc;
2402 	      if ((x = ucs2_to_utf8(c,&buf)) < 1) {
2403 		  debug(F101,"xgnbyte ucs2_to_utf8 error","",c);
2404 		  return(-2);
2405 	      }
2406 	      debug(F101,"xgnbyte UTF8 buf[0]","",buf[0]);
2407 	      for (i = 1; i < x; i++) {
2408 		  xlabuf[k+i-1] = buf[i];
2409 		  debug(F111,"xgnbyte UTF8 xlabuf",ckitoa(i-1),buf[i]);
2410 	      }
2411 	      xlaptr = 0;
2412 	      xlacount = x - 1;
2413 	      debug(F101,"xgnbyte UTF8 xlacount","",xlacount);
2414 	      return((unsigned int)buf[0]);
2415 	  } else {			/* Or keep it as UCS-2 */
2416 	      int k = 0;
2417 	      CHAR c;
2418 	      xlaptr = 0;
2419 	      if (utferror) {
2420 		  xlabuf[k++] = 0xff;
2421 		  xlabuf[k++] = 0xfd;
2422 		  debug(F101,"xgnbyte error","",k);
2423 	      }
2424 	      if (eolflag) {		/* We detected EOL in source file */
2425 		  if (what & W_SEND) {	/* Convert to CRLF */
2426 		      xlabuf[k++] = CR;
2427 		      xlabuf[k++] = NUL;
2428 		      xlabuf[k++] = LF;
2429 		      xlacount = k;
2430 		      debug(F101,"xgnbyte send CRLF","",k);
2431 		      return(0);	/* Return NUL */
2432 		  } else {		/* Or to local line-end */
2433 #ifdef COMMENT
2434 		      /* This bypasses byte swapping that we might need */
2435 		      xlabuf[k++] = (CHAR)feol;
2436 		      xlacount = k;
2437 		      debug(F101,"xgnbyte send feol","",k);
2438 		      return(0);	/* Return NUL */
2439 #else
2440 		      xc = (CHAR)feol;
2441 #endif /* COMMENT */
2442 		  }
2443 	      }
2444 	      /* In which order should we return the bytes? */
2445 #ifdef COMMENT
2446 	      if ( (what & W_SEND) || (what & W_FTP) || (fileorder == 0)) {
2447 #endif /* COMMENT */
2448 		  /* ALWAYS RETURN IN BIG ENDIAN ORDER... 7 Sep 2002   */
2449 		  /* xgnbyte() is almost always used to feed xpnbyte() */
2450 		  /* which requires bytes in BE order. In cases where  */
2451 		  /* xgnbyte is used in isolation, the caller can swap */
2452 		  /* bytes itself afterwards. */
2453 		  xlabuf[k++] = (xc >> 8) & 0xff; /* Big Endian */
2454 		  xlabuf[k++] = xc & 0xff;
2455 		  debug(F001,"xgnbyte->UCS2BE",
2456 			ckitox((int)xlabuf[0]),xlabuf[1]);
2457 #ifdef COMMENT
2458 	      } else {			/* Little Endian */
2459 		  xlabuf[k++] = xc & 0xff;
2460 		  xlabuf[k++] = (xc >> 8) & 0xff;
2461 		  debug(F001,"xgnbyte->UCS2LE",
2462 			ckitox((int)xlabuf[0]),xlabuf[1]);
2463 	      }
2464 #endif /* COMMENT */
2465 	      c = xlabuf[0];
2466 	      xlaptr = 1;
2467 	      xlacount = k-1;
2468 	      debug(F101,"xgnbyte c","",c);
2469 	      debug(F101,"xgnbyte xlaptr","",xlaptr);
2470 	      debug(F011,"xgnbyte xlabuf",xlabuf,xlacount);
2471 	      return((unsigned int)c);
2472 	  }
2473       }
2474 #endif /* UNICODE */
2475       case XLA_NONE:
2476 	return((fn ? (*fn)() : zminchar()));
2477       case XLA_BYTE:			/* Byte-for-Byte translation */
2478 	rt = x;
2479 	if (sx)
2480 	  rt = (*sx)(rt);
2481 #ifdef UNICODE
2482 	if (utferror) {
2483 	    xlaptr = 0;
2484 	    xlacount = 1;
2485 	    xlabuf[0] = rt;
2486 	    return(UNK);
2487 	} else
2488 #endif /* UNICODE */
2489 	  return((unsigned int)rt);
2490 
2491 #ifdef KANJI
2492       case XLA_JAPAN:			/* Come here with Shift-JIS */
2493 	if (tcs == FC_JEUC) {		/* It better be... */
2494 	    xlaptr = 0;
2495 	    xlacount = 0;
2496 	    if (!havesj) {
2497 		printf("BAD BAD\n");
2498 		return(-2);
2499 	    }
2500 	    if (!haveeu)		/* We might already have EUC too */
2501 	      eu.x_short = sj_to_eu(sj.x_short);
2502 	    if (eu.x_char[byteorder]) {
2503 		xlabuf[xlacount++] = eu.x_char[1-byteorder];
2504 		return(eu.x_char[byteorder]);
2505 	    } else {
2506 		return(eu.x_char[1-byteorder]);
2507 	    }
2508 	    break;
2509 	}
2510 #endif /* KANJI */
2511 
2512       default:
2513 	debug(F101,"xgnbyte bad xlatype","",xlatype);
2514 	return(-2);
2515     }
2516 #ifdef COMMENT
2517 /*
2518   If there is a return() statement here, some compilers complain
2519   about "statement not reached".  If there is no return() statement,
2520   other compilers complain that "Non-void function should return a value".
2521   There is no path through this function that falls through to here.
2522 */
2523     debug(F100,"xgnbyte switch failure","",0);
2524     return(-2);
2525 #endif /* COMMENT */
2526 }
2527 #endif /* NOCSETS */
2528 
2529 #ifndef NOXFER
2530 
2531 /*  G E T P K T  --  Fill a packet data field from the indicated source.  */
2532 
2533 /*
2534   Parameters:
2535     bufmax: Maximum length of entire packet.
2536     xlate:  Flag for whether to translate charsets when in text mode.
2537   Returns:  Number of characters written to packet data field, 0 or more,
2538             Or -1 on failure (internal error),
2539             or -3 on timeout (e.g. when reading from a pipe).
2540 
2541   This is the full version allowing for parity and text-mode conversions;
2542   i.e. it works in all cases.   Also see bgetpkt(), a special lean/mean/fast
2543   packet encoder that works only for binary-mode no-parity transfers.
2544 */
2545 static int uflag = 0;
2546 
2547 int
getpkt(bufmax,xlate)2548 getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
2549     register CHAR rt = t, rnext = NUL;	  /* Register shadows of the globals */
2550     register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
2551     register int x;			/* Loop index. */
2552     register int a7;			/* Low 7 bits of character */
2553 
2554     CHAR xxls, xxdl, xxrc, xxss, xxcq;	/* Pieces of prefixed sequence */
2555 
2556     if (binary) xlate = 0;		/* We don't translate if binary */
2557 
2558     if (!data) {
2559 	debug(F100,"SERIOUS ERROR: getpkt data == NULL","",0);
2560 	return(-1);
2561     }
2562     dp = data;				/* Point to packet data buffer */
2563     size = 0;				/* And initialize its size */
2564 /*
2565   Assume bufmax is the receiver's total receive-packet buffer length.
2566   Our whole packet has to fit into it, so we adjust the data field length.
2567   We also decide optimally whether it is better to use a short-format or
2568   long-format packet when we're near the borderline.
2569 */
2570     bufmax = maxdata();			/* Get maximum data length */
2571 
2572     if (first == 1) {			/* If first character of this file.. */
2573 #ifdef UNICODE
2574 	/* Special end-of-line handling for Unicode */
2575 	if (tcharset == TC_UCS2 || tcharset == TC_UTF8)
2576 	  uflag = 1;
2577 #endif /* UNICODE */
2578 	debug(F101,"getpkt first uflag","",uflag);
2579 	debug(F101,"getpkt first rt","",rt);
2580 	if (!memstr && !funcstr)	/* and real file... */
2581 	  ffc = (CK_OFF_T)0;		/* reset file character counter */
2582 #ifdef COMMENT
2583 	/* Moved to below... */
2584 	first = 0;			/* Next character won't be first */
2585 #endif /* COMMENT */
2586 	*leftover = '\0';		/* Discard any interrupted leftovers */
2587 	nleft = 0;
2588 #ifndef NOCSETS
2589 	setxlatype(tcharset,fcharset);	/* Set up charset translations */
2590 #endif /* NOCSETS */
2591 
2592 	/* Get first character of file into rt, watching out for null file */
2593 
2594 #ifdef CALIBRATE
2595 	if (calibrate && !memstr) {
2596 #ifdef NORANDOM
2597 	    x = rt = 53;
2598 #else
2599 	    x = rt = cal_a[rand() & 0xff];
2600 #endif /* NORANDOM */
2601 	    first = 0;
2602 	    ffc++;
2603 	} else
2604 #endif /* CALIBRATE */
2605 #ifdef KANJI
2606 	if (xlate && tcharset == TC_JEUC) { /* Kanji text */
2607 	    x = zkanjf();
2608 	    if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
2609 	        first = -1;
2610 	        size = 0;
2611 	        if (x == -2) {
2612 	            debug(F100,"getpkt zkanji: input error","",0);
2613 	            cxseen = 1;
2614 	        } else debug(F100,"getpkt zkanji: empty string/file","",0);
2615 	        return(0);
2616 	    }
2617 	    rt = x;
2618 	    first = 0;
2619 	    if (!memstr) {
2620 		ffc++;
2621 		if (docrc && (what & W_SEND)) /* Accumulate file crc */
2622 		  dofilcrc((int)rt);
2623 	    }
2624 	} else {			/* Not Kanji text */
2625 #endif /* KANJI */
2626 	    if (memstr) {		/* Reading data from memory string */
2627 		/* This will not be Unicode */
2628 		if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
2629 		    first = -1;
2630 		    size = 0;
2631 		    debug(F100,"getpkt: empty string","",0);
2632 		    return(0);
2633 		}
2634 		first = 0;
2635 	    } else if (funcstr) {	/* Reading data from a function */
2636 		/* This will not be Unicode */
2637 		if ((x = (*funcptr)()) < 0) { /* End of input  */
2638 		    first = -1;
2639 		    size = 0;		/* Empty */
2640 		    return(0);
2641 		}
2642 		ffc++;			/* Count a file character */
2643 		rt = (CHAR) x;		/* Convert int to char */
2644 		first = 0;
2645 		debug(F000,"getpkt funcstr","",rt);
2646 
2647 	    } else {			/* Reading data from a file */
2648 #ifndef NOCSETS
2649 		if (xlate && !binary) {	/* Could be Unicode */
2650 		    if (xlatype == XLA_UNICODE) {
2651 			/* Get next translated byte */
2652 			x = xgnbyte(cseqtab[tcharset],fcharset,NULL);
2653 			debug(F101,"getpkt xgnbyte","",x);
2654 		    } else {		/* Not Unicode */
2655 			x = zminchar();	/* Get next byte, translate below */
2656 			debug(F101,"getpkt zminchar A","",x);
2657 		    }
2658 		} else {		/* Just get next byte */
2659 #endif /* NOCSETS */
2660 		    x = zminchar();
2661 		    debug(F101,"getpkt zminchar B","",x);
2662 #ifndef NOCSETS
2663 		}
2664 #endif /* NOCSETS */
2665 		if (x < 0) {		/* End of file or input error */
2666 		    if (x == -3) {	/* Timeout. */
2667 			size = (dp-data);
2668 			debug(F101,"getpkt timeout size","",size);
2669 			return((size == 0) ? x : size);
2670 		    }
2671 		    first = -1;
2672 		    size = 0;
2673 		    if (x == -2) {	/* Error */
2674 			debug(F100,"getpkt: input error","",0);
2675 			cxseen = 1;	/* Interrupt the file transfer */
2676 		    } else {
2677 			debug(F100,"getpkt empty file","",0);
2678 		    }
2679 		    return(0);
2680 		}
2681 		first = 0;		/* Next character won't be first */
2682 		rt = (CHAR) x;		/* Convert int to char */
2683 #ifndef NOCSETS
2684 		if (xlatype != XLA_UNICODE || binary) {
2685 		    ffc++;
2686 		    if (sx)
2687 		      rt = (*sx)(rt);
2688 		    if (docrc && (what & W_SEND))
2689 		      dofilcrc(x);
2690 		}
2691 #endif /* NOCSETS */
2692 #ifdef DEBUG
2693 		if (deblog)
2694 		  debug(F101,"getpkt 1st char","",rt);
2695 #endif /* DEBUG */
2696 		if (/* !haveuc && */ docrc && (what & W_SEND)) /* File CRC */
2697 		  dofilcrc(x);
2698 	    }
2699 #ifdef KANJI
2700 	}
2701 #endif /* KANJI */
2702 	/* PWP: handling of feol is done later (in the while loop)... */
2703 
2704     } else if ((first == -1) && (nleft == 0)) { /* EOF from last time */
2705 #ifdef DEBUG
2706 	if (deblog) {
2707 	    debug(F101,"getpkt eof crc16","",crc16);
2708 	    debug(F101,"getpkt eof ffc","",ffc);
2709 	}
2710 #endif /* DEBUG */
2711         return(size = 0);
2712     }
2713 /*
2714   Here we handle characters that were encoded for the last packet but
2715   did not fit, and so were saved in the "leftover" array.
2716 */
2717     debug(F101,"getpkt nleft","",nleft);
2718     if (nleft) {
2719 	for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */
2720 	  *dp++ = *p1++;
2721 	*leftover = '\0';			/* Delete leftovers */
2722 	nleft = 0;
2723     }
2724     if (first == -1)			/* Handle EOF */
2725       return(size = (dp - data));
2726 
2727 /* Now fill up the rest of the packet. */
2728 
2729     rpt = 0;				/* Initialize character repeat count */
2730 
2731     while (first > -1) {		/* Until EOF... */
2732 #ifdef CALIBRATE
2733 	if (calibrate && !memstr) {	/* We generate our own "file" */
2734 	    if (ffc >= calibrate) {	/* EOF */
2735 		first = -1;
2736 		ffc--;
2737 	    } else {			/* Generate next character */
2738 		if (cal_j > CAL_M * ffc)
2739 		  cal_j = cal_a[ffc & 0xff];
2740 		x = (unsigned)cal_a[(cal_j & 0xff)];
2741 		if (x == rt) x ^= 2;
2742 	    }
2743 	    cal_j += (unsigned int)(ffc + CAL_O);
2744 	    ffc++;
2745 	} else
2746 #endif /* CALIBRATE */
2747 #ifdef KANJI
2748 	  if (xlate && tcharset == TC_JEUC) {
2749 	      if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
2750 		  first = -1;
2751 		  if (x == -2) cxseen = 1;
2752 	      } else if (!memstr) ffc++;
2753 	      rnext = (CHAR) (x & fmask);
2754 	  } else {
2755 #endif /* KANJI */
2756 	    if (memstr) {		/* Get next char from memory string */
2757 		if ((x = *memptr++) == '\0') /* End of string means EOF */
2758 		  first = -1;		/* Flag EOF for next time. */
2759 		rnext = (CHAR) (x & fmask); /* Apply file mask */
2760 	    } else if (funcstr) {	/* Get next char from function */
2761 		if ((x = (*funcptr)()) < 0) /* End of string means EOF */
2762 		  first = -1;		/* Flag EOF for next time. */
2763 		rnext = (CHAR) (x & fmask); /* Apply file mask */
2764 	    } else {			/* From file... */
2765 #ifndef NOCSETS
2766 		if (xlate && !binary) {	/* Could be Unicode */
2767 		    if (xlatype == XLA_UNICODE) {
2768 			/* Get next translated byte */
2769 			x = xgnbyte(cseqtab[tcharset],fcharset,NULL);
2770 		    } else {		/* Not Unicode */
2771 			x = zminchar(); /* Get next byte, translate below */
2772 			/* debug(F101,"xgnbyte B zminchar","",x); */
2773 		    }
2774 		} else {		/* Just get next byte */
2775 #endif /* NOCSETS */
2776 		    x = zminchar();
2777 		    /* debug(F101,"xgnbyte C zminchar","",x); */
2778 #ifndef NOCSETS
2779 		}
2780 #endif /* NOCSETS */
2781 		if (x < 0) {		/* Check for EOF */
2782 		    if (x == -3) {	/* Timeout reading from pipe */
2783 			t = rt;
2784 			size = (dp-data);
2785 			debug(F101,"getpkt timeout size","",size);
2786 			return((size == 0) ? x : size);
2787 		    }
2788 		    first = -1;		/* Flag eof for next time. */
2789 		    if (x == -2) cxseen = 1; /* If error, cancel this file. */
2790 		}
2791 		rnext = (CHAR) (x & fmask); /* Apply file mask */
2792 #ifndef NOCSETS
2793 		if (xlatype != XLA_UNICODE) {
2794 #endif /* NOCSETS */
2795 		    ffc++;
2796 #ifndef NOCSETS
2797 		    if (sx)
2798 		      rt = (*sx)(rt);
2799 #endif /* NOCSETS */
2800 		    if (docrc && (what & W_SEND))
2801 		      dofilcrc(x);
2802 
2803 #ifndef NOCSETS
2804 		}
2805 #endif /* NOCSETS */
2806 	    }
2807 #ifdef KANJI
2808 	}
2809 #endif /* KANJI */
2810 /*
2811   At this point, the character we just read is in rnext,
2812   and the character we are about to encode into the packet is in rt.
2813 */
2814 	odp = dp;			/* Remember where we started. */
2815  	xxls = xxdl = xxrc = xxss = xxcq = NUL;	/* Clear these. */
2816 /*
2817   Now encode the character according to the options that are in effect:
2818     ctlp[]: whether this control character needs prefixing.
2819     binary: text or binary mode.
2820     rptflg: repeat counts enabled.
2821     ebqflg: 8th-bit prefixing enabled.
2822     lscapu: locking shifts enabled.
2823 */
2824 	if (rptflg) {			/* Repeat processing is on? */
2825 	    if (!uflag &&
2826 		/*
2827 		 * If the next char is really CRLF, then we cannot
2828 		 * be doing a repeat (unless CR,CR,LF which becomes
2829 		 * "~ <n-1> CR CR LF", which is OK but not most efficient).
2830 		 * I just plain don't worry about this case.  The actual
2831 		 * conversion from NL to CRLF is done after the rptflg if...
2832 		 */
2833 		(!feol || binary || (feol && (rnext != feol))) &&
2834 		(rt == rnext) && (first == 0)) { /* Got a run... */
2835 		if (++rpt < 94) {	/* Below max, just count */
2836 		    continue;		/* go back and get another */
2837 		} else if (rpt == 94) {	/* Reached max, must dump */
2838 		    xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
2839 		    rptn += rpt;	/* Accumulate it for statistics */
2840 		    rpt = 0;		/* And reset it */
2841 		}
2842 	    } else if (rpt > 1) {	/* More than two */
2843 		xxrc = (CHAR) tochar(++rpt); /* and count. */
2844 		rptn += rpt;
2845 		rpt = 0;		/* Reset repeat counter. */
2846 	    }
2847 	    /*
2848 	      If (rpt == 1) we must encode exactly two characters.
2849 	      This is done later, after the first character is encoded.
2850 	    */
2851 	}
2852 	/* If it's the newline character... */
2853 	if (!uflag && !binary && feol && (rt == feol)) {
2854 	    if (lscapu && lsstate) {	/* If SHIFT-STATE is SHIFTED */
2855 		if (ebqflg) {		/* If single shifts enabled, */
2856 		    *dp++ = (CHAR) ebq;	/* insert a single shift. */
2857 		} else {		/* Otherwise must shift in. */
2858 		    *dp++ = myctlq;	/* Insert shift-out code */
2859 		    *dp++ = 'O';
2860 		    lsstate = 0;	/* Change shift state */
2861 		}
2862 	    }
2863 #ifdef CK_SPEED
2864 	    if (ctlp[CR]) {
2865 		*dp++ = myctlq;		/* Insert carriage return directly */
2866 		*dp++ = 'M';
2867 		ccp++;
2868 	    } else {
2869 		*dp++ = CR;		/* Perhaps literally */
2870 		ccu++;
2871 	    }
2872 #else /* !CK_SPEED */
2873 	    *dp++ = myctlq;		/* Insert carriage return directly */
2874 	    *dp++ = 'M';
2875 	    ccp++;
2876 #endif /* CK_SPEED */
2877 	    rt = LF;			/* Now make next char be linefeed. */
2878 	}
2879 /*
2880   Now handle the 8th bit of the file character.  If we have an 8-bit
2881   connection, we preserve the 8th bit.  If we have a 7-bit connection,
2882   we employ either single or locking shifts (if they are enabled).
2883 */
2884 	a7 = rt & 0177;			/* Get low 7 bits of character */
2885 	if (rt & 0200) {		/* 8-bit character? */
2886 	    if (lscapu) {		/* Locking shifts enabled? */
2887 		if (!lsstate) {		/* Not currently shifted? */
2888 		    x = lslook(0200);	/* Look ahead */
2889 		    if (x != 0 || ebqflg == 0) { /* Locking shift decision */
2890 			xxls = 'N';	   /* Need locking shift-out */
2891 			lsstate = 1;	   /* and change to shifted state */
2892 		    } else if (ebqflg) {   /* Not worth it */
2893 			xxss = (CHAR) ebq; /* Use single shift */
2894 		    }
2895 		}
2896 		rt = (CHAR) a7;		/* Replace character by 7-bit value */
2897 	    } else if (ebqflg) {	/* 8th bit prefixing is on? */
2898 		xxss = (CHAR) ebq;	/* Insert single shift */
2899 		rt = (CHAR) a7;		/* Replace character by 7-bit value */
2900 	    }
2901 /*
2902   In case we have a 7-bit connection and this is an 8-bit character, AND
2903   neither locking shifts nor single shifts are enabled, then the character's
2904   8th bit will be destroyed in transmission, and a block check error will
2905   occur.
2906 */
2907 	} else if (lscapu) {		/* 7-bit character */
2908 
2909 	    if (lsstate) {		/* Comes while shifted out? */
2910 		x = lslook(0);		/* Yes, look ahead */
2911 		if (x || ebqflg == 0) {	/* Time to shift in. */
2912 		    xxls = 'O';		/* Set shift-in code */
2913 		    lsstate = 0;	/* Exit shifted state */
2914 		} else if (ebqflg) {	/* Not worth it, stay shifted out */
2915 		    xxss = (CHAR) ebq;	/* Insert single shift */
2916 		}
2917 	    }
2918 	}
2919 	/* If data character is significant to locking shift protocol... */
2920 	if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
2921 	  xxdl = 'P';			/* Insert datalink escape */
2922 
2923 	if (
2924 #ifdef CK_SPEED
2925 	    /*
2926 	      Thwart YET ANOTHER unwanted, unneeded, and unloved sign
2927 	      extension.  This one was particularly nasty because it prevented
2928 	      255 (Telnet IAC) from being prefixed on some platforms -- e.g.
2929 	      VMS with VAX C -- but not others, thus causing file transfers to
2930 	      fail on Telnet connections by sending bare IACs.  Not to mention
2931 	      the stray memory reference.  Signed chars are a BAD idea.
2932 	    */
2933 	    ctlp[(unsigned)(rt & 0xff)]	/* Lop off any "sign" extension */
2934 #else
2935 	    (a7 < SP) || (a7 == DEL)
2936 #endif /* CK_SPEED */
2937 	    ) {				/* Do control prefixing if necessary */
2938 	    xxcq = myctlq;		/* The prefix */
2939 	    ccp++;			/* Count it */
2940 	    rt = (CHAR) ctl(rt);	/* Uncontrollify the character */
2941 	}
2942 #ifdef CK_SPEED
2943 	else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
2944 	  ccu++;
2945 #endif /* CK_SPEED */
2946 
2947 	if (a7 == myctlq)		/* Always prefix the control prefix */
2948 	  xxcq = myctlq;
2949 
2950 	if ((rptflg) && (a7 == rptq))	/* If it's the repeat prefix, */
2951 	  xxcq = myctlq;		/* prefix it if doing repeat counts */
2952 
2953 	if ((ebqflg) && (a7 == ebq))	/* Prefix the 8th-bit prefix */
2954 	  xxcq = myctlq;		/* if doing 8th-bit prefixes */
2955 
2956 /* Now construct the entire sequence */
2957 
2958 	if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
2959 	odp2 = dp;				    /* (Save this place) */
2960 	if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
2961 	if (xxrc) { *dp++ = (CHAR) rptq; *dp++ = xxrc; } /* Repeat count */
2962 	if (xxss) { *dp++ = (CHAR) ebq; }           /* Single shift */
2963 	if (xxcq) { *dp++ = myctlq; }	    	    /* Control prefix */
2964 	*dp++ = rt;			/* Finally, the character itself */
2965 
2966 	if (rpt == 1) {			/* Exactly two copies? */
2967 	    rpt = 0;
2968 	    p2 = dp;			/* Save place temporarily */
2969 	    for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
2970 	      *dp++ = *p1;
2971 	    if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
2972 	    if ((p2-data) < bufmax) odp = p2; /* Check packet bounds */
2973 	}
2974 	rt = rnext;			/* Next character is now current. */
2975 
2976 /* Done encoding the character.  Now take care of packet buffer overflow. */
2977 
2978 	if ((dp-data) >= bufmax) {	/* If too big, save some for next. */
2979 
2980 	    debug(F000,"getpkt EOP","",rt);
2981 
2982 	    size = (dp-data);		/* Calculate the size. */
2983 	    *dp = '\0';			/* Mark the end. */
2984 	    if (memstr) {		/* No leftovers for memory strings */
2985 		if (rt)			/* Char we didn't encode yet */
2986 		  memptr--;		/* (for encstr()) */
2987 		return(size);
2988 	    }
2989 	    if ((dp-data) > bufmax) {	/* if packet is overfull */
2990 		/* copy the part that doesn't fit into the leftover buffer, */
2991 		/* taking care not to split a prefixed sequence. */
2992 		int i;
2993 		nleft = dp - odp;
2994 		for (i = 0, p1 = leftover, p2 = odp; i < nleft; i++) {
2995 		    *p1++ = *p2++;
2996 		    if (memstr) memptr--; /* (for encstr) */
2997 		}
2998 		debug(F111,"getpkt leftover",leftover,size);
2999 		debug(F101,"getpkt osize","",(odp-data));
3000 		size = (odp-data);	/* Return truncated packet. */
3001 		*odp = '\0';		/* Mark the new end */
3002 	    }
3003 	    t = rt;			/* Save for next time */
3004 	    return(size);
3005 	}
3006     }					/* Otherwise, keep filling. */
3007     size = (dp-data);			/* End of file */
3008     *dp = '\0';				/* Mark the end of the data. */
3009     debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
3010     return(size);		     /* return partially filled last packet. */
3011 }
3012 
3013 /*  T I N I T  --  Initialize a transaction  */
3014 
3015 int epktrcvd = 0, epktsent = 0;
3016 
3017 /*
3018   Call with 1 to reset everything before S/I/Y negotiation, or 0 to
3019   reset only the things that are not set in the S/I/Y negotiation.
3020   Returns -1 on failure (e.g. to create packet buffers), 0 on success.
3021 */
3022 int
tinit(flag)3023 tinit(flag) int flag; {
3024     int x;
3025 #ifdef CK_TIMERS
3026     extern int rttflg;
3027 #endif /* CK_TIMERS */
3028     extern int rcvtimo;
3029     extern int fatalio;
3030 
3031     debug(F101,"tinit flag","",flag);
3032 
3033     *epktmsg = NUL;
3034     epktrcvd = 0;
3035     epktsent = 0;
3036     ofperms = "";
3037     diractive = 0;			/* DIR / REMOTE DIR not active */
3038     interrupted = 0;			/* Not interrupted */
3039     fatalio = 0;			/* No fatal i/o error */
3040     if (server) {
3041 	moving  = 0;
3042 	pipesend = 0; /* This takes care of multiple GETs sent to a server. */
3043     }
3044     bestlen = 0;			/* For packet length optimization */
3045     maxsend = 0;			/* Biggest data field we can send */
3046 #ifdef STREAMING
3047     streamok = 0;			/* Streaming negotiated */
3048     streaming = 0;			/* Streaming being done now */
3049 #endif /* STREAMING */
3050 
3051     binary = b_save;			/* ... */
3052     gnf_binary = binary;		/* Per-file transfer mode */
3053     retrans = 0;			/* Packet retransmission count */
3054     sndtyp = 0;				/* No previous packet */
3055     xflg = 0;				/* Reset x-packet flag */
3056     memstr = 0;				/* Reset memory-string flag */
3057     memptr = NULL;			/*  and buffer pointer */
3058     funcstr = 0;			/* Reset "read from function" flag */
3059     funcptr = NULL;			/*  and function pointer */
3060     autopar = 0;			/* Automatic parity detection flag */
3061 
3062     /* This stuff is only for BEFORE S/I/Y negotiation, not after */
3063 
3064     if (flag) {
3065 	if (bctf) {		      /* Force Block Check 3 on all packets */
3066 	    bctu = bctl = 3;		/* Set block check type to 3 */
3067 	} else {
3068 	    bctu = bctl = 1;		/* Reset block check type to 1 */
3069 	}
3070 	myinit[0] = '\0';		/* Haven't sent init string yet */
3071 	rqf = -1;			/* Reset 8th-bit-quote request flag */
3072 	ebq = MYEBQ;			/* Reset 8th-bit quoting stuff */
3073 	ebqflg = 0;			/* 8th bit quoting not enabled */
3074 	ebqsent = 0;			/* No 8th-bit prefix bid sent yet */
3075 	sq = 'Y';			/* 8th-bit prefix bid I usually send */
3076 	spsiz = spsizr;			/* Initial send-packet size */
3077 	debug(F101,"tinit spsiz","",spsiz);
3078 	wslots = 1;			/* One window slot */
3079 	wslotn = 1;			/* No window negotiated yet */
3080 	justone = 0;			/* (should this be zero'd here?) */
3081 	whoareu[0] = NUL;		/* Partner's system type */
3082 	sysindex = -1;
3083 	wearealike = 0;
3084 	what = W_INIT;			/* Doing nothing so far... */
3085     }
3086     fncnv = f_save;			/* Back to what user last said */
3087     pktnum = 0;				/* Initial packet number to send */
3088     cxseen = czseen = discard = 0;	/* Reset interrupt flags */
3089     *filnam = '\0';			/* Clear file name */
3090     spktl = 0;				/* And its length */
3091     nakstate = 0;			/* Assume we're not in a NAK state */
3092     numerrs = 0;			/* Transmission error counter */
3093     idletmo = 0;			/* No idle timeout yet */
3094     if (server) { 			/* If acting as server, */
3095 	if (srvidl > 0)			/* If an idle timeout is given */
3096 	  timint = srvidl;
3097 	else
3098 	  timint = srvtim;		/* use server timeout interval. */
3099     } else {				/* Otherwise */
3100 	timint = chktimo(rtimo,timef);	/* and use local timeout value */
3101     }
3102     debug(F101,"tinit timint","",timint);
3103 
3104 #ifdef CK_TIMERS
3105     if (rttflg && timint > 0)		/* Using round-trip timers? */
3106       rttinit();
3107     else
3108 #endif /* CK_TIMERS */
3109       rcvtimo = timint;
3110 
3111     winlo = 0;				/* Packet 0 is at window-low */
3112     debug(F101,"tinit winlo","",winlo);
3113     x = mksbuf(1);			/* Make a 1-slot send-packet buffer */
3114     if (x < 0) return(x);
3115     x = getsbuf(0);			/* Allocate first send-buffer. */
3116     debug(F101,"tinit getsbuf","",x);
3117     if (x < 0) return(x);
3118     dumpsbuf();
3119     x = mkrbuf(wslots);			/* & a 1-slot receive-packet buffer. */
3120     if (x < 0) return(x);
3121     lsstate = 0;			/* Initialize locking shift state */
3122     if (autopath) {			/* SET RECEIVE PATHNAMES AUTO fixup */
3123 	fnrpath = PATH_AUTO;
3124 	autopath = 0;
3125     }
3126     return(0);
3127 }
3128 
3129 VOID
pktinit()3130 pktinit() {				/* Initialize packet sequence */
3131     pktnum = 0;				/* number & window low. */
3132     winlo = 0;
3133     debug(F101,"pktinit winlo","",winlo);
3134 }
3135 
3136 /*  R I N I T  --  Respond to S or I packet  */
3137 
3138 VOID
rinit(d)3139 rinit(d) CHAR *d; {
3140     char *tp = NULL;
3141     ztime(&tp);
3142     tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
3143     tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
3144     tlog(F110,"Collision action:", fncnam[fncact],0);
3145     tlog(F100,"","",0);
3146     debug(F101,"rinit fncact","",fncact);
3147     filcnt = filrej = 0;		/* Init file counters */
3148     spar(d);
3149     ack1(rpar());
3150 #ifdef datageneral
3151     if ((local) && (!quiet))            /* Only do this if local & not quiet */
3152         consta_mt();                    /* Start the asynch read task */
3153 #endif /* datageneral */
3154 }
3155 
3156 
3157 /*  R E S E T C  --  Reset per-transaction character counters */
3158 
3159 VOID
resetc()3160 resetc() {
3161     rptn = 0;				/* Repeat counts */
3162     fsecs = flci = flco = (CK_OFF_T)0;	/* File chars in and out */
3163 #ifdef GFTIMER
3164     fpfsecs = 0.0;
3165 #endif /* GFTIMER */
3166     tfc = tlci = tlco = (CK_OFF_T)0;	/* Total file, line chars in & out */
3167     ccu = ccp = 0L;			/* Control-char statistics */
3168 #ifdef COMMENT
3169     fsize = (CK_OFF_T)-1;		/* File size */
3170 #else
3171     if (!(what & W_SEND))
3172       fsize = (CK_OFF_T)-1;
3173     debug(F101,"resetc fsize","",fsize);
3174 #endif /* COMMENT */
3175     timeouts = retrans = 0;		/* Timeouts, retransmissions */
3176     spackets = rpackets = 0;		/* Packet counts out & in */
3177     crunched = 0;			/* Crunched packets */
3178     wcur = 0;				/* Current window size */
3179     wmax = 0;				/* Maximum window size used */
3180     peakcps = 0;                        /* Peak chars per second */
3181 }
3182 
3183 /*  S I N I T  --  Get & verify first file name, then send Send-Init packet */
3184 /*
3185  Returns:
3186    1 if send operation begins successfully
3187    0 if send operation fails
3188 */
3189 #ifdef DYNAMIC
3190 char *cmargbuf = NULL;
3191 #else
3192 char cmargbuf[CKMAXPATH+1];
3193 #endif /* DYNAMIC */
3194 char *cmargp[2];
3195 
3196 VOID
fnlist()3197 fnlist() {
3198     if (!calibrate)
3199       sndsrc = (nfils < 0) ? -1 : nfils; /* Source for filenames */
3200 #ifdef DYNAMIC
3201     if (!cmargbuf && !(cmargbuf = malloc(CKMAXPATH+1)))
3202       fatal("fnlist: no memory for cmargbuf");
3203 #endif /* DYNAMIC */
3204     cmargbuf[0] = NUL;			/* Initialize name buffer */
3205 
3206     debug(F101,"fnlist nfils","",nfils);
3207     debug(F110,"fnlist cmarg",cmarg,0);
3208     debug(F110,"fnlist cmarg2",cmarg2,0);
3209     if (!cmarg2) cmarg2 = "";
3210     if (nfils == 0) {			/* Sending from stdin or memory. */
3211 	if ((cmarg2 != NULL) && (*cmarg2)) {
3212 	    cmarg = cmarg2;		/* If F packet, "as-name" is used */
3213 	    cmarg2 = "";		/* if provided */
3214 	} else
3215 	  cmarg = "stdin";		/* otherwise just use "stdin" */
3216 	ckstrncpy(cmargbuf,cmarg,CKMAXPATH+1);
3217 	cmargp[0] = cmargbuf;
3218 	cmargp[1] = "";
3219 	cmlist = cmargp;
3220 	nfils = 1;
3221     }
3222 }
3223 
3224 int
sinit()3225 sinit() {
3226     int x;				/* Worker int */
3227     char *tp, *xp, *m;			/* Worker string pointers */
3228 
3229     filcnt = filrej = 0;		/* Initialize file counters */
3230 
3231     fnlist();
3232 
3233     xp = "";
3234     if (nfils < 0) {
3235 #ifdef PIPESEND
3236 	if (usepipes && protocol == PROTO_K && *cmarg == '!') {
3237 	    pipesend = 1;
3238 	    cmarg++;
3239 	}
3240 #endif /* PIPESEND */
3241 	xp = cmarg;
3242     } else {
3243 #ifndef NOMSEND
3244 	if (addlist)
3245 	  xp = filehead->fl_name;
3246 	else
3247 #endif /* NOMSEND */
3248 	  if (filefile)
3249 	    xp = filefile;
3250 	  else if (calibrate)
3251 	    xp = "Calibration";
3252 	  else
3253 	    xp = *cmlist;
3254     }
3255     debug(F110,"sinit xp",xp,0);
3256     x = gnfile();			/* Get first filename. */
3257     debug(F111,"sinit gnfile",ckitoa(gnferror),x);
3258     if (x == 0) x = gnferror;		/* If none, get error reason */
3259     m = NULL;				/* Error message pointer */
3260     debug(F101,"sinit gnfil","",x);
3261     switch (x) {
3262       case -6: m = "No files meet selection criteria"; break;
3263       case -5: m = "Too many files match wildcard"; break;
3264       case -4: m = "Cancelled"; break;
3265       case -3: m = "Read access denied"; break;
3266       case -2: m = "File is not readable"; break;
3267 #ifdef COMMENT
3268       case -1: m = iswild(filnam) ? "No files match" : "File not found";
3269 	break;
3270       case  0: m = "No filespec given!"; break;
3271 #else
3272       case  0:
3273       case -1: m = iswild(filnam) ? "No files match" : "File not found";
3274 	break;
3275 #endif /* COMMENT */
3276       default:
3277 	break;
3278     }
3279     debug(F101,"sinit nfils","",nfils);
3280     debug(F110,"sinit filnam",filnam,0);
3281     if (x < 1) {			/* Didn't get a file. */
3282 	debug(F111,"sinit msg",m,x);
3283 	if (server) {			/* Doing GET command */
3284 	    errpkt((CHAR *)m);		/* so send Error packet. */
3285 	} else if (!local) { 		/* Doing SEND command */
3286 	    interrupted = 1;		/* (To suppress hint) */
3287 	    printf("?%s\r\n",m);
3288 	} else {
3289 	    xxscreen(SCR_EM,0,0l,m);	/* so print message. */
3290 	}
3291 	tlog(F110,xp,m,0L);		/* Make transaction log entry. */
3292 	freerbuf(rseqtbl[0]);		/* Free the buffer the GET came in. */
3293 	return(0);			/* Return failure code */
3294     }
3295     if (!local && !server && ckdelay > 0) /* OS-9 sleep(0) == infinite */
3296       sleep(ckdelay);			/* Delay if requested */
3297 #ifdef datageneral
3298     if ((local) && (!quiet))            /* Only do this if local & not quiet */
3299       consta_mt();			/* Start the async read task */
3300 #endif /* datageneral */
3301     freerbuf(rseqtbl[0]);		/* Free the buffer the GET came in. */
3302     sipkt('S');				/* Send the Send-Init packet. */
3303     ztime(&tp);				/* Get current date/time */
3304     tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
3305     tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
3306     tlog(F100,"","",0);
3307     debug(F111,"sinit ok",filnam,0);
3308     return(1);
3309 }
3310 
3311 int
3312 #ifdef CK_ANSIC
sipkt(char c)3313 sipkt(char c)				/* Send S or I packet. */
3314 #else
3315 sipkt(c) char c;
3316 #endif
3317 /* sipkt */ {
3318     CHAR *rp; int k, x;
3319     extern int sendipkts;
3320     debug(F101,"sipkt pktnum","",pktnum); /* (better be 0...) */
3321     ttflui();				/* Flush pending input. */
3322     /*
3323       If this is an I packet and SET SEND I-PACKETS is OFF, don't send it;
3324       set sstate to 'Y' which makes the next input() call return 'Y' as if we
3325       had received an ACK to the I packet we didn't send.  This is to work
3326       around buggy Kermit servers that can't handle I packets.
3327     */
3328     if ((sendipkts == 0) && (c == 'I')) { /* I packet but don't send I pkts? */
3329 	sstate = 'Y';			  /* Yikes! */
3330 	return(0);			  /* (see input()..)*/
3331     }
3332     k = sseqtbl[pktnum];		/* Find slot for this packet */
3333     if (k < 0) {			/* No slot? */
3334 	k = getsbuf(winlo = pktnum);	/* Make one. */
3335 	debug(F101,"sipkt getsbuf","",k);
3336     }
3337     rp = rpar();			/* Get protocol parameters. */
3338     if (!rp) rp = (CHAR *)"";
3339     x = spack(c,pktnum,(int)strlen((char *)rp),rp); /* Send them. */
3340     return(x);
3341 }
3342 
3343 /*  X S I N I T  --  Retransmit S-packet  */
3344 /*
3345   For use in the GET-SEND sequence, when we start to send, but receive another
3346   copy of the GET command because the receiver didn't get our S packet.
3347   This retransmits the S packet and frees the receive buffer for the ACK.
3348   This special case is necessary because packet number zero is being re-used.
3349 */
3350 VOID
xsinit()3351 xsinit() {
3352     int k;
3353     k = rseqtbl[0];
3354     debug(F101,"xsinit k","",k);
3355     if (k > -1)
3356     freerbuf(k);
3357     resend(0);
3358 }
3359 
3360 /*  R C V F I L -- Receive a file  */
3361 
3362 /*
3363   Incoming filename is in data field of F packet.
3364   This function decodes it into the srvcmd buffer, substituting an
3365   alternate "as-name", if one was given.
3366   Then it does any requested transformations (like converting to
3367   lowercase), and finally if a file of the same name already exists,
3368   takes the desired collision action.
3369   Returns:
3370     1 on success.
3371     0 on failure.
3372 */
3373 char ofn1[CKMAXPATH+4];			/* Buffer for output file name */
3374 char * ofn2;				/* Pointer to backup file name */
3375 int ofn1x;				/* Flag output file already exists */
3376 CK_OFF_T ofn1len = (CK_OFF_T)0;
3377 int opnerr;				/* Flag for open error */
3378 
3379 int					/* Returns success ? 1 : 0 */
rcvfil(n)3380 rcvfil(n) char *n; {
3381     extern int en_cwd;
3382     int i, skipthis;
3383     char * n2;
3384     char * dispo;
3385 #ifdef OS2ONLY
3386     char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */
3387 #endif /* OS2ONLY */
3388 #ifdef DTILDE
3389     char *dirp;
3390 #endif /* DTILDE */
3391     int dirflg, x, y;
3392 #ifdef PIPESEND
3393     extern char * rcvfilter;
3394 #endif /* PIPESEND */
3395 #ifdef CALIBRATE
3396     extern int dest;
3397     CK_OFF_T csave;
3398     csave = calibrate;			/* So we can decode filename */
3399     calibrate = (CK_OFF_T)0;
3400 #endif /* CALIBRATE */
3401 
3402     ofperms = "";			/* Reset old-file permissions */
3403     opnerr = 0;				/* No open error (yet) */
3404     ofn2 = NULL;			/* No new name (yet) */
3405     lsstate = 0;			/* Cancel locking-shift state */
3406     srvptr = srvcmd;			/* Decode file name from packet. */
3407 
3408 #ifdef UNICODE
3409     xpnbyte(-1,0,0,NULL);		/* Reset UCS-2 byte counter. */
3410 #endif /* UNICODE */
3411 
3412     debug(F110,"rcvfil rdatap",rdatap,0);
3413     decode(rdatap,putsrv,0);		/* Don't xlate charsets. */
3414 #ifdef CALIBRATE
3415     calibrate = csave;
3416     if (dest == DEST_N) {
3417 	calibrate = 1;
3418 	cmarg2 = "CALIBRATE";
3419     }
3420 #endif /* CALIBRATE */
3421     if (*srvcmd == '\0')		/* Watch out for null F packet. */
3422       ckstrncpy((char *)srvcmd,"NONAME",srvcmdlen);
3423     makestr(&prrfspec,(char *)srvcmd);	/* New preliminary filename */
3424 #ifdef DTILDE
3425     if (*srvcmd == '~') {
3426 	dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
3427 	if (*dirp != '\0')
3428 	  ckstrncpy((char *)srvcmd,dirp,srvcmdlen);
3429     }
3430 #else
3431 #ifdef OS2
3432     if (isalpha(*srvcmd) && srvcmd[1] == ':' && srvcmd[2] == '\0')
3433       ckstrncat((char *)srvcmd,"NONAME",srvcmdlen);
3434 #endif /* OS2 */
3435 #endif /* DTILDE */
3436 
3437 #ifndef NOICP
3438 #ifndef NOSPL
3439 /* File dialog when downloading...  */
3440     if (
3441 #ifdef CK_APC
3442 	(apcactive == APC_LOCAL && adl_ask) || /* Autodownload with ASK */
3443 #endif /* CK_APC */
3444 	(clcmds && haveurl)		/* Or "kermit:" or "iksd:" URL */
3445 	) {
3446 	int x;
3447 	char fnbuf[CKMAXPATH+1];	/* Result buffer */
3448 	char * preface;
3449 
3450 	if (clcmds && haveurl)
3451 	  preface = "\r\nIncoming file from Kermit server...\r\n\
3452 Please confirm output file specification or supply an alternative:";
3453 	else
3454 	  preface = "\r\nIncoming file from remote Kermit...\r\n\
3455 Please confirm output file specification or supply an alternative:";
3456 
3457 	x = uq_file(preface,		/* Preface */
3458 		    NULL,		/* Prompt (let uq_file() built it) */
3459 		    3,			/* Output file */
3460 		    NULL,		/* Help text */
3461 		    (char *)srvcmd,	/* Default */
3462 		    fnbuf,		/* Result buffer */
3463 		    CKMAXPATH+1		/* Size of result buffer */
3464 		    );
3465 	if (x < 1) {			/* Refused */
3466 	    rf_err = "Refused by user";
3467 	    return(0);
3468 	}
3469 	ckstrncpy((char *)srvcmd,fnbuf,CKMAXPATH+1);
3470 	if (isabsolute((char *)srvcmd)) { /* User gave an absolute path */
3471 	    g_fnrpath = fnrpath;	/* Save current RECEIVE PATHNAMES */
3472 	    fnrpath = PATH_ABS;		/* switch to ABSOLUTE */
3473 	}
3474     }
3475 #endif /* NOSPL */
3476 #endif /* NOICP */
3477 
3478     if (!ENABLED(en_cwd)) {		/* CD is disabled */
3479 	zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
3480 	if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
3481 	    rf_err = "Access denied";
3482 	    return(0);
3483 	}
3484     }
3485 #ifdef COMMENT
3486     /* Wrong place for this -- handle cmarg2 first -- see below...  */
3487 
3488     if (zchko((char *)srvcmd) < 0) {	/* Precheck for write access */
3489 	debug(F110,"rcvfil access denied",srvcmd,0);
3490 	rf_err = "Write access denied";
3491 	discard = opnerr = 1;
3492 	return(0);
3493     }
3494     xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
3495     debug(F110,"rcvfil srvcmd 1",srvcmd,0);
3496     tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
3497 #endif /* COMMENT */
3498 
3499     skipthis = 0;			/* This file in our exception list? */
3500     for (i = 0; i < NSNDEXCEPT; i++) {
3501 	if (!rcvexcept[i]) {
3502 	    break;
3503 	}
3504 	if (ckmatch(rcvexcept[i],(char *)srvcmd,filecase,1)) {
3505 	    skipthis = 1;
3506 	    break;
3507 	}
3508     }
3509 
3510 #ifdef DEBUG
3511     if (deblog && skipthis) {
3512 	debug(F111,"rcvfil rcvexcept",rcvexcept[i],i);
3513 	debug(F110,"rcvfil skipping",srvcmd,0);
3514     }
3515 #endif /* DEBUG */
3516 
3517     if (skipthis) {			/* Skipping this file */
3518 	discard = 1;
3519 	rejection = 1;
3520 	rf_err = "Exception list";
3521 	debug(F101,"rcvfil discard","",discard);
3522 	tlog(F100," refused: exception list","",0);
3523 	return(1);
3524     }
3525 
3526     /* File is not in exception list */
3527 
3528     if (!cmarg2)			/* No core dumps please */
3529       cmarg2 = "";
3530     debug(F110,"rcvfil cmarg2",cmarg2,0);
3531 
3532     if (*cmarg2) {			/* Check for alternate name */
3533 #ifndef NOSPL
3534 	int y; char *s;			/* Pass it thru the evaluator */
3535 	extern int cmd_quoting;
3536 	if (cmd_quoting) {
3537 	    y = MAXRP;
3538 	    ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* for \v(filename) */
3539 	    s = (char *)srvcmd;
3540 	    zzstring(cmarg2,&s,&y);
3541 	} else
3542 	  *srvcmd = NUL;
3543 	if (!*srvcmd)			/* If we got something */
3544 #endif /* NOSPL */
3545 	  ckstrncpy((char *)srvcmd,cmarg2,srvcmdlen);
3546     }
3547     debug(F110,"rcvfil srvcmd 2",srvcmd,0);
3548 
3549 #ifdef PIPESEND
3550     /* If it starts with "bang", it's a pipe, not a file. */
3551     if (usepipes && protocol == PROTO_K && *srvcmd == '!' && !rcvfilter) {
3552 	CHAR *s;
3553 	s = srvcmd+1;			/* srvcmd[] is not a pointer. */
3554 	while (*s) {			/* So we have to slide the contents */
3555 	    *(s-1) = *s;		/* over 1 space to the left. */
3556 	    s++;
3557 	}
3558 	*(s-1) = NUL;
3559 	pipesend = 1;
3560     }
3561 #endif /* PIPESEND */
3562 
3563 #ifdef COMMENT
3564 /*
3565   This is commented out because we need to know whether the name we are
3566   using was specified by the local user as an override, or came from the
3567   incoming packet.  In the former case, we don't do stuff to it (like
3568   strip the pathname) that we might do to it in the latter.
3569 */
3570     cmarg2 = "";			/* Done with alternate name */
3571 #endif /* COMMENT */
3572 
3573     if ((int)strlen((char *)srvcmd) > CKMAXPATH) /* Watch out for overflow */
3574       *(srvcmd + CKMAXPATH - 1) = NUL;
3575 
3576     /* At this point, srvcmd[] contains the incoming filename or as-name. */
3577     /* So NOW we check for write access. */
3578 
3579     if (zchko((char *)srvcmd) < 0) {	/* Precheck for write access */
3580 	debug(F110,"rcvfil access denied",srvcmd,0);
3581 	rf_err = "Write access denied";
3582 	discard = opnerr = 1;
3583 	return(0);
3584     }
3585     xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
3586     debug(F110,"rcvfil srvcmd 1",srvcmd,0);
3587     tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
3588 
3589 #ifdef CK_LABELED
3590 #ifdef VMS
3591 /*
3592   If we have an as-name, this overrides the internal name if we are doing
3593   a labeled-mode transfer.
3594 */
3595     if (*cmarg2) {
3596 	extern int lf_opts;
3597 	lf_opts &= ~LBL_NAM;
3598     }
3599 #endif /* VMS */
3600 #endif /* CK_LABELED */
3601 
3602     debug(F111,"rcvfil pipesend",srvcmd,pipesend);
3603 
3604 #ifdef PIPESEND
3605     /* Skip all the filename manipulation and collision actions */
3606     if (pipesend) {
3607 	dirflg = 0;
3608 	ofn1[0] = '!';
3609 	ckstrncpy(&ofn1[1],(char *)srvcmd,CKMAXPATH+1);
3610 	ckstrncpy(n,ofn1,CKMAXPATH+1);
3611 	ckstrncpy(fspec,ofn1,CKMAXPATH+1);
3612 	makestr(&prfspec,fspec);	/* New preliminary filename */
3613 	debug(F110,"rcvfil pipesend",ofn1,0);
3614 	goto rcvfilx;
3615     }
3616 #endif /* PIPESEND */
3617 /*
3618   This is to avoid passing email subjects through nzrtol().
3619   We haven't yet received the A packet so we don't yet know it's e-mail,
3620   so in fact we go ahead and convert it anyway, but later we get the
3621   original back from ofilnam[].
3622 */
3623     dispos = 0;
3624     ckstrncpy(ofilnam,(char *)srvcmd,CKMAXPATH+1);
3625 
3626 #ifdef NZLTOR
3627     if (*cmarg2)
3628       ckstrncpy((char *)ofn1,(char *)srvcmd,CKMAXPATH+1);
3629     else
3630       nzrtol((char *)srvcmd,		/* Filename from packet */
3631 	     (char *)ofn1,		/* Where to put result */
3632 	     fncnv,			/* Filename conversion */
3633 	     fnrpath,			/* Pathname handling */
3634 	     CKMAXPATH			/* Size of result buffer */
3635 	     );
3636 #else
3637     debug(F101,"rcvfil fnrpath","",fnrpath); /* Handle pathnames */
3638     if (fnrpath == PATH_OFF && !*cmarg2) { /* RECEIVE PATHNAMES OFF? */
3639 	char *t;			/* Yes. */
3640 	zstrip((char *)srvcmd,&t);	/* If there is a pathname, strip it */
3641 	debug(F110,"rcvfil PATH_OFF zstrip",t,0);
3642 	if (!t)				/* Be sure we didn't strip too much */
3643 	  sprintf(ofn1,"FILE%02ld",filcnt);
3644 	else if (*t == '\0')
3645 	  sprintf(ofn1,"FILE%02ld",filcnt);
3646 	else
3647 	  ckstrncpy(ofn1,t,CKMAXPATH+1);
3648 	ckstrncpy((char *)srvcmd,ofn1,srvcmdlen); /* Now copy it back. */
3649     }
3650 /*
3651   SET RECEIVE PATHNAMES RELATIVE...
3652   The following doesn't belong here but doing it right would require
3653   defining and implementing a new file routine for all ck?fio.c modules.
3654   So for now...
3655 */
3656 #ifdef UNIXOROSK
3657     else if (fnrpath == PATH_REL && !*cmarg2) {
3658 	if (isabsolute((char *)srvcmd)) {
3659 	    ofn1[0] = '.';
3660 	    ckstrncpy(&of1n[1],(char *)srvcmd,CKMAXPATH+1);
3661 	    ckstrncpy((char *)srvcmd,ofn1,srvcmdlen);
3662 	    debug(F110,"rcvfil PATH_REL",ofn1,0);
3663 	}
3664     }
3665 #else
3666 #ifdef OS2
3667     else if (fnrpath == PATH_REL && !*cmarg2) {
3668 	if (isabsolute((char *)srvcmd)) {
3669 	    char *p = (char *)srvcmd;
3670 	    if (isalpha(*p) && *(p+1) == ':')
3671 	      p += 2;
3672 	    if (*p == '\\' || *p == '/')
3673 	      p++;
3674 	    ckstrncpy(ofn1,p,CKMAXPATH+1);
3675 	    ckstrncpy((char *)srvcmd,ofn1,srvcmdlen);
3676 	    debug(F110,"rcvfil OS2 PATH_REL",ofn1,0);
3677 	}
3678     }
3679 #endif /* OS2 */
3680 #endif /* UNIXOROSK */
3681 
3682     /* Now srvcmd contains incoming filename with path possibly stripped */
3683 
3684     if (fncnv)				/* FILE NAMES CONVERTED? */
3685       zrtol((char *)srvcmd,(char *)ofn1); /* Yes, convert to local form */
3686     else
3687       ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* No, copy literally. */
3688 #endif /* NZLTOR */
3689 
3690 #ifdef PIPESEND
3691     if (rcvfilter) {
3692 	char * p = NULL, * q;
3693 	int nn = MAXRP;
3694 	pipesend = 1;
3695 	debug(F110,"rcvfil rcvfilter ",rcvfilter,0);
3696 #ifndef NOSPL
3697 	if ((p = (char *) malloc(nn + 1))) {
3698 	    q = p;
3699 #ifdef COMMENT
3700             /* We have already processed srvcmd and placed it into ofn1 */
3701             ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* For \v(filename) */
3702 #endif /* COMMENT */
3703 	    debug(F110,"rcvfile pipesend filter",rcvfilter,0);
3704 	    zzstring(rcvfilter,&p,&nn);
3705 	    debug(F111,"rcvfil pipename",q,nn);
3706 	    if (nn <= 0) {
3707 		printf(
3708 		       "?Sorry, receive filter + filename too long, %d max.\n",
3709 		       CKMAXPATH
3710 		       );
3711 		rf_err = "Name too long";
3712 		free(q);
3713 		return(0);
3714 	    }
3715 	    ckstrncpy((char *)srvcmd,q,MAXRP);
3716 	    free(q);
3717 	}
3718 #endif /* NOSPL */
3719     }
3720 #endif /* PIPESEND */
3721 
3722     /* Now the incoming filename, possibly converted, is in ofn1[]. */
3723 
3724 #ifdef OS2
3725     /* Don't refuse the file just because the name is illegal. */
3726     if (!IsFileNameValid(ofn1)) {	/* Name is OK for OS/2? */
3727 #ifdef OS2ONLY
3728 	char *zs = NULL;
3729 	zstrip(ofn1, &zs);		/* Not valid, strip unconditionally */
3730 	if (zs) {
3731 	    if (iattr.longname.len &&	/* Free previous longname, if any */
3732 		iattr.longname.val)
3733 	      free(iattr.longname.val);
3734 	    iattr.longname.len = strlen(zs); /* Store in attribute structure */
3735 	    iattr.longname.val = (char *) malloc(iattr.longname.len + 1);
3736 	    if (iattr.longname.val)	/* Remember this (illegal) name */
3737 	      strcpy(iattr.longname.val, zs); /* safe */
3738 	}
3739 #endif /* OS2ONLY */
3740 	debug(F110,"rcvfil: invalid file name",ofn1,0);
3741 	ChangeNameForFAT(ofn1);	/* Change to an acceptable name */
3742 	debug(F110,"rcvfil: FAT file name",ofn1,0);
3743 
3744     } else {				/* Name is OK. */
3745 
3746 	debug(F110,"rcvfil: valid file name",ofn1,0);
3747 #ifdef OS2ONLY
3748 	if (iattr.longname.len &&
3749 	     iattr.longname.val)	/* Free previous longname, if any */
3750 	  free(iattr.longname.val);
3751 	iattr.longname.len = 0;
3752 	iattr.longname.val = NULL;	/* This file doesn't need a longname */
3753 #endif /* OS2ONLY */
3754     }
3755 #endif /* OS2 */
3756     debug(F110,"rcvfil as",ofn1,0);
3757 
3758 /* Filename collision action section. */
3759 
3760     dirflg =				/* Is it a directory name? */
3761 #ifdef CK_TMPDIR
3762         isdir(ofn1)
3763 #else
3764 	0
3765 #endif /* CK_TMPDIR */
3766 	  ;
3767     debug(F101,"rcvfil dirflg","",dirflg);
3768     ofn1len = zchki(ofn1);		/* File already exists? */
3769     debug(F111,"rcvfil ofn1len",ofn1,ofn1len);
3770     ofn1x = (ofn1len != (CK_OFF_T)-1);
3771 
3772     if ( (
3773 #ifdef UNIX
3774 	strcmp(ofn1,"/dev/null") &&	/* It's not the null device? */
3775 #else
3776 #ifdef OSK
3777 	strcmp(ofn1,"/nil") &&
3778 #endif /* OSK */
3779 #endif /* UNIX */
3780 	!stdouf ) &&			/* Not copying to standard output? */
3781 	ofn1x ||			/* File of same name exists? */
3782 	dirflg ) {			/* Or file is a directory? */
3783         debug(F111,"rcvfil exists",ofn1,fncact);
3784 #ifdef CK_PERMS
3785 	ofperms = zgperm((char *)ofn1);	/* Get old file's permissions */
3786 	debug(F110,"rcvfil perms",ofperms,0);
3787 #endif /* CK_PERMS */
3788 
3789 	debug(F101,"rcvfil fncact","",fncact);
3790 	switch (fncact) {		/* Yes, do what user said. */
3791 	  case XYFX_A:			/* Append */
3792 	    ofperms = "";
3793 	    debug(F100,"rcvfil append","",0);
3794 	    if (dirflg) {
3795 		rf_err = "Can't append to a directory";
3796 		tlog(F100," error - can't append to directory","",0);
3797 		discard = opnerr = 1;
3798 		return(0);
3799 	    }
3800 	    tlog(F110," appending to",ofn1,0);
3801 	    break;
3802 #ifdef COMMENT
3803 	  case XYFX_Q:			/* Query (Ask) */
3804 	    break;			/* not implemented */
3805 #endif /* COMMENT */
3806 	  case XYFX_B:			/* Backup (rename old file) */
3807 	    if (dirflg) {
3808 		rf_err = "Can't rename existing directory";
3809 		tlog(F100," error - can't rename directory","",0);
3810 		discard = opnerr = 1;
3811 		return(0);
3812 	    }
3813 	    znewn(ofn1,&ofn2);		/* Get new unique name */
3814 	    tlog(F110," backup:",ofn2,0);
3815 	    debug(F110,"rcvfil backup ofn1",ofn1,0);
3816 	    debug(F110,"rcvfil backup ofn2",ofn2,0);
3817 #ifdef CK_LABELED
3818 #ifdef OS2ONLY
3819 /*
3820   In case this is a FAT file system, we can't change only the FAT name, we
3821   also have to change the longname from the extended attributes block.
3822   Otherwise, we'll have many files with the same longname and if we copy them
3823   to an HPFS volume, only one will survive.
3824 */
3825 	    if (os2getlongname(ofn1, &longname) > -1) {
3826 		if (strlen(longname)) {
3827 		    char tmp[10];
3828 		    extern int ck_znewn;
3829 		    sprintf(tmp,".~%d~",ck_znewn);
3830 		    newlongname =
3831 		      (char *) malloc(strlen(longname) + strlen(tmp) + 1);
3832 		    if (newlongname) {
3833 			strcpy(newlongname, longname); /* safe (prechecked) */
3834 			strcat(newlongname, tmp); /* safe (prechecked) */
3835 			os2setlongname(ofn1, newlongname);
3836 			free(newlongname);
3837 			newlongname = NULL;
3838 		    }
3839 		}
3840 	    } else debug(F100,"rcvfil os2getlongname failed","",0);
3841 #endif /* OS2ONLY */
3842 #endif /* CK_LABELED */
3843 
3844 #ifdef COMMENT
3845 	    /* Do this later, in opena()... */
3846 	    if (zrename(ofn1,ofn2) < 0) {
3847 		rf_err = "Can't transform filename";
3848 		debug(F110,"rcvfil rename fails",ofn1,0);
3849 		discard = opnerr = 1;
3850 		return(0);
3851 	    }
3852 #endif /* COMMENT */
3853 	    break;
3854 
3855 	  case XYFX_D:			/* Discard (refuse new file) */
3856 	    ofperms = "";
3857 	    discard = 1;
3858 	    rejection = 1;		/* Horrible hack: reason = name */
3859 	    debug(F101,"rcvfil discard","",discard);
3860 	    tlog(F100," refused: name","",0);
3861 	    break;
3862 
3863 	  case XYFX_R:			/* Rename incoming file */
3864 	    znewn(ofn1,&ofn2);		/* Make new name for it */
3865 #ifdef OS2ONLY
3866 	    if (iattr.longname.len) {
3867 		char tmp[10];
3868 		extern int ck_znewn;
3869 		sprintf(tmp,".~%d~",ck_znewn);
3870 		newlongname =
3871 		  (char *) malloc(iattr.longname.len + strlen(tmp) + 1);
3872 		if (newlongname) {
3873 		    strcpy(newlongname, iattr.longname.val); /* safe */
3874 		    strcat(newlongname, tmp); /* safe */
3875 		    debug(F110,
3876 			  "Rename Incoming: newlongname",newlongname,0);
3877 		    if (iattr.longname.len &&
3878 			iattr.longname.val)
3879 		      free(iattr.longname.val);
3880 		    iattr.longname.len = strlen(newlongname);
3881 		    iattr.longname.val = newlongname;
3882 		    /* free(newlongname) here ? */
3883 		}
3884 	    }
3885 #endif /* OS2ONLY */
3886 	    break;
3887 	  case XYFX_X:			/* Replace old file */
3888 	    debug(F100,"rcvfil overwrite","",0);
3889 	    if (dirflg) {
3890 		rf_err = "Can't overwrite existing directory";
3891 		tlog(F100," error - can't overwrite directory","",0);
3892 		discard = opnerr = 1;
3893 #ifdef COMMENT
3894 		return(0);
3895 #else
3896 		break;
3897 #endif /* COMMENT */
3898 	    }
3899 	    tlog(F110,"overwriting",ofn1,0);
3900 	    break;
3901 	  case XYFX_U:			/* Refuse if older */
3902 	    debug(F110,"rcvfil update",ofn1,0);
3903 	    if (dirflg) {
3904 		rf_err = "File has same name as existing directory";
3905 		tlog(F110," error - directory exists:",ofn1,0);
3906 		discard = opnerr = 1;
3907 #ifdef COMMENT
3908 		/* Don't send an error packet, just refuse the file */
3909 		return(0);
3910 #endif /* COMMENT */
3911 	    }
3912 	    break;			/* Not here, we don't have */
3913 					/* the attribute packet yet. */
3914 	  default:
3915 	    ofperms = "";
3916 	    debug(F101,"rcvfil bad collision action","",fncact);
3917 	    break;
3918 	}
3919     }
3920     debug(F110,"rcvfil ofn1",ofn1,0);
3921     debug(F110,"rcvfil ofn2",ofn2,0);
3922     debug(F110,"rcvfil ofperms",ofperms,0);
3923     if (fncact == XYFX_R && ofn1x && ofn2) { /* Renaming incoming file? */
3924 	xxscreen(SCR_AN,0,0l,ofn2);	/* Display renamed name */
3925 	ckstrncpy(n, ofn2, CKMAXPATH+1); /* Return it */
3926     } else {				/* No */
3927 	xxscreen(SCR_AN,0,0l,ofn1);	/* Display regular name */
3928 	ckstrncpy(n, ofn1, CKMAXPATH+1); /* and return it. */
3929     }
3930 
3931 #ifdef CK_MKDIR
3932 /*  Create directory(s) if necessary.  */
3933     if (!discard && fnrpath != PATH_OFF) { /* RECEIVE PATHAMES ON? */
3934 	int x;
3935 	debug(F110,"rcvfil calling zmkdir",ofn1,0); /* Yes */
3936 	if ((x = zmkdir(ofn1)) < 0) {
3937 	    debug(F100,"zmkdir fails","",0);
3938 	    tlog(F110," error - directory creation failure:",ofn1,0);
3939 	    rf_err = "Directory creation failure.";
3940 	    discard = 1;
3941 	    return(0);
3942 	}
3943 #ifdef TLOG
3944 	else if (x > 0)
3945 	  tlog(F110," path created:",ofn1,0);
3946 #endif /* TLOG */
3947     }
3948 #else
3949     debug(F110,"rcvfil CK_MKDIR not defined",ofn1,0);
3950 #endif /* CK_MKDIR */
3951 
3952     if (calibrate)
3953       ckstrncpy(fspec,ofn1,CKMAXPATH+1);
3954     else
3955       zfnqfp(ofn1,fspeclen,fspec);
3956     debug(F110,"rcvfil fspec",fspec,0);
3957 
3958 #ifdef COMMENT
3959     /* See comments with VMS zfnqfp()... */
3960 #ifdef VMS
3961     /* zfnqfp() does not return the version number */
3962     if (!calibrate) {
3963 	int x, v;
3964 	x = strlen(ofn1);
3965 	if (x > 0) {
3966 	    if (ofn1[x-1] == ';') {
3967 		v = getvnum(ofn1);
3968 		ckstrncpy(&ofn1[x],ckitoa(v),CKMAXPATH-x);
3969 	    }
3970 	}
3971     }
3972 #endif /* VMS */
3973 #endif /* COMMENT */
3974     fspec[fspeclen] = NUL;
3975     makestr(&prfspec,fspec);		/* New preliminary filename */
3976 
3977 #ifdef PIPESEND
3978   rcvfilx:
3979 #endif /* PIPESEND */
3980 
3981     debug(F110,"rcvfilx: n",n,0);
3982     debug(F110,"rcvfilx: ofn1",ofn1,0);
3983     ffc = (CK_OFF_T)0;			/* Init per-file counters */
3984     cps = oldcps = 0L;
3985     rs_len = (CK_OFF_T)0;
3986     rejection = -1;
3987     fsecs = gtimer();			/* Time this file started */
3988 #ifdef GFTIMER
3989     fpfsecs = gftimer();
3990     debug(F101,"rcvfil fpfsecs","",fpfsecs);
3991 #endif /* GFTIMER */
3992     filcnt++;
3993     intmsg(filcnt);
3994     return(1);				/* Successful return */
3995 }
3996 
3997 
3998 /*  R E O F  --  Receive End Of File packet for incoming file */
3999 
4000 /*
4001   Closes the received file.
4002   Returns:
4003     0 on success.
4004    -1 if file could not be closed.
4005     2 if disposition was mail, mail was sent, but temp file not deleted.
4006     3 if disposition was print, file was printed, but not deleted.
4007    -2 if disposition was mail and mail could not be sent
4008    -3 if disposition was print and file could not be printed
4009    -4 if MOVE-TO: failed
4010    -5 if RENAME-TO: failed
4011 */
4012 int
reof(f,yy)4013 reof(f,yy) char *f; struct zattr *yy; {
4014     extern char * rcv_move, * rcv_rename;
4015     extern int o_isopen;
4016     int rc = 0;				/* Return code */
4017     char *p;
4018     char c;
4019 
4020     debug(F111,"reof fncact",f,fncact);
4021     debug(F101,"reof discard","",discard);
4022     success = 1;			/* Assume status is OK */
4023     lsstate = 0;			/* Cancel locking-shift state */
4024     if (discard) {			/* Handle attribute refusals, etc. */
4025 	debug(F101,"reof discarding","",0);
4026 	success = 0;			/* Status = failed. */
4027 	if (rejection == '#' ||		/* Unless rejection reason is */
4028 	    rejection ==  1  ||		/* date or name (SET FILE COLLISION */
4029 	    rejection == '?')		/* UPDATE or DISCARD) */
4030 	  success = 1;
4031 	debug(F101,"reof success","",success);
4032 	filrej++;			/* Count this rejection. */
4033 	discard = 0;			/* We never opened the file, */
4034 	return(0);			/* so we don't close it. */
4035     }
4036 #ifdef DEBUG
4037     if (deblog) {
4038 	debug(F101,"reof cxseen","",cxseen);
4039 	debug(F101,"reof czseen","",czseen);
4040 	debug(F110,"reof rdatap",rdatap,0);
4041     }
4042 #endif /* DEBUG */
4043 
4044     if (cxseen == 0)			/* Got cancel directive? */
4045       cxseen = (*rdatap == 'D');
4046     if (cxseen || czseen)		/* (for hints) */
4047       interrupted = 1;
4048     success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */
4049     if (!success)			  /* "Uncount" this file */
4050       filrej++;
4051     debug(F101,"reof o_isopen","",o_isopen);
4052 
4053     if (o_isopen) {			/* If an output file was open... */
4054 
4055 #ifdef CK_CTRLZ
4056 	if (success) {
4057 	    debug(F101,"reof lastchar","",lastchar);
4058 	    if (!binary && eofmethod == XYEOF_Z && lastchar != 26 &&
4059 		(!xflg || (xflg && remfile)))
4060 	      pnbyte((char)26,putfil);
4061 	}
4062 #endif /* CK_CTRLZ */
4063 
4064 	rc = clsof(cxseen || czseen);	/* Close the file (resets cxseen) */
4065 	debug(F101,"reof closf","",rc);
4066 	if (rc < 0) {			/* If failure to close, FAIL */
4067 	    if (success) filrej++;
4068 	    success = 0;
4069 	}
4070 	if (!calibrate) {
4071 	    /* Set file modification date and/or permissions */
4072 	    if (success)
4073 	      zstime(f,yy,0);
4074 #ifdef OS2ONLY
4075 #ifdef CK_LABELED
4076 	    if (success && yy->longname.len)
4077 	      os2setlongname(f, yy->longname.val);
4078 #endif /* CK_LABELED */
4079 #endif /* OS2ONLY */
4080 	}
4081 	if (success == 0) {		/* And program return code */
4082 	    xitsta |= W_RECV;
4083 	} else if (success == 1) {	/* File rec'd successfully */
4084 	    makestr(&rrfspec,prrfspec);	/* Record it for wheremsg */
4085 	    makestr(&rfspec,prfspec);
4086 	}
4087 
4088 /* Handle dispositions from attribute packet... */
4089 
4090 	c = NUL;
4091 #ifndef NOFRILLS
4092 	if (!calibrate && yy->disp.len != 0) {
4093 	    p = yy->disp.val;
4094 	    c = *p++;
4095 #ifndef UNIX
4096 /*
4097   See ckcpro.w.  In UNIX we don't use temp files any more -- we pipe the
4098   stuff right into mail or lpr.
4099 */
4100 	    if (c == 'M') {		/* Mail to user. */
4101 		rc = zmail(p,filnam);	/* Do the system's mail command */
4102 		if (rc < 0) success = 0;	/* Remember status */
4103 		tlog(F110,"mailed",filnam,0L);
4104 		tlog(F110," to",p,0L);
4105 		zdelet(filnam);		/* Delete the file */
4106 	    } else if (c == 'P') {	/* Print the file. */
4107 		rc = zprint(p,filnam);	/* Do the system's print command */
4108 		if (rc < 0) success = 0; /* Remember status */
4109 		tlog(F110,"printed",filnam,0L);
4110 		tlog(F110," with options",p,0L);
4111 #ifndef VMS
4112 #ifndef STRATUS
4113 		/* spooler deletes file after print complete in VOS & VMS */
4114 		if (zdelet(filnam) && rc == 0) rc = 3; /* Delete the file */
4115 #endif /* STRATUS */
4116 #endif /* VMS */
4117 	    }
4118 #endif /* UNIX */
4119 	}
4120 #endif /* NOFRILLS */
4121 
4122 	if (success &&
4123 	    !pipesend &&
4124 	    !calibrate && c != 'M' && c != 'P') {
4125 	    if (rcv_move) {		/* If /MOVE-TO was given... */
4126 		char * p = rcv_move;
4127 #ifdef COMMENT
4128 /* No need for this - it's a directory name */
4129 		char tmpbuf[CKMAXPATH+1];
4130 		extern int cmd_quoting;	/* for \v(filename) */
4131 		if (cmd_quoting) {	/* But only if cmd_quoting is on */
4132 		    int n;
4133 		    n = CKMAXPATH;
4134 		    p = tmpbuf;
4135 		    debug(F111,"reof /move-to",rcv_move,0);
4136 		    zzstring(rcv_move,&p,&n);
4137 		    p = tmpbuf;
4138 		}
4139 #endif /* COMMENT */
4140 /*
4141   Here we could create the directory if it didn't exist (and it was relative)
4142   but there would have to be a user-settable option to say whether to do this.
4143 */
4144 		rc = zrename(filnam,p);
4145 		debug(F111,"reof MOVE zrename",rcv_move,rc);
4146 		if (rc > -1) {
4147 		    tlog(F110," moving received file to",rcv_move,0);
4148 		} else {
4149 		    rc = -4;
4150 		    tlog(F110," FAILED to move received file to",rcv_move,0);
4151 		}
4152 	    } else if (rcv_rename) {	/* Or /RENAME-TO: */
4153 		char *s = rcv_rename;	/* This is the renaming string */
4154 #ifndef NOSPL
4155 		char tmpnam[CKMAXPATH+16];
4156 		extern int cmd_quoting;	/* for \v(filename) */
4157 		if (cmd_quoting) {	/* But only if cmd_quoting is on */
4158 		    int n;		/* Pass it thru the evaluator */
4159 		    n = CKMAXPATH;
4160 		    s = (char *)tmpnam;
4161 		    zzstring(rcv_rename,&s,&n);
4162 		    s = (char *)tmpnam;
4163 		}
4164 #endif /* NOSPL */
4165 		if (s) if (*s) {
4166 		    rc = zrename(filnam,s);
4167 		    debug(F111,"reof RENAME zrename",s,rc);
4168 		    if (rc > -1) {
4169 			tlog(F110," renaming received file to",s,0);
4170 		    } else {
4171 			rc = -5;
4172 			tlog(F110," FAILED to rename received file to",s,0);
4173 		    }
4174 		}
4175 	    }
4176 	}
4177     }
4178     debug(F101,"reof success","",success);
4179     debug(F101,"reof returns","",rc);
4180 
4181     filnam[0] = NUL;			/* Erase the filename */
4182     return(rc);
4183 }
4184 
4185 /*  R E O T  --  Receive End Of Transaction  */
4186 
4187 VOID
reot()4188 reot() {
4189     cxseen = czseen = discard = 0;	/* Reset interruption flags */
4190     tstats();				/* Finalize transfer statistics */
4191 }
4192 
4193 /*  S F I L E -- Send File header or teXt header packet  */
4194 
4195 /*
4196   Call with x nonzero for X packet, zero for F packet.
4197   If X == 0, filename to send is in filnam[], and if cmarg2 is not null
4198   or empty, the file should be sent under this name rather than filnam[].
4199   If sndfilter not NULL, it is the name of a send filter.
4200   Returns 1 on success, 0 on failure.
4201 */
4202 int
sfile(x)4203 sfile(x) int x; {
4204 #ifdef pdp11
4205 #define PKTNL 64
4206 #else
4207 #define PKTNL 256
4208 #endif /* pdp11 */
4209     char pktnam[PKTNL+1];		/* Local copy of name */
4210     char *s;
4211     int rc;
4212     int notafile = 0;
4213     extern int filepeek;
4214 #ifdef PIPESEND
4215     extern char * sndfilter;
4216 
4217     if (sndfilter) {
4218 	pipesend = 1;
4219 	debug(F110,"sfile send filter ",sndfilter,0);
4220     }
4221 #endif /* PIPESEND */
4222 
4223     notafile = calibrate || sndarray || pipesend || x;
4224     debug(F101,"sfile x","",x);
4225     debug(F101,"sfile notafile","",notafile);
4226 
4227 #ifndef NOCSETS
4228     if (tcs_save > -1) {                /* Character sets */
4229         tcharset = tcs_save;
4230         tcs_save = -1;
4231 	debug(F101,"sfile restored tcharset","",tcharset);
4232     }
4233     if (fcs_save > -1) {
4234         fcharset = fcs_save;
4235         fcs_save = -1;
4236 	debug(F101,"sfile restored fcharset","",fcharset);
4237     }
4238     setxlatype(tcharset,fcharset);      /* Translation type */
4239 #endif /* NOCSETS */
4240 
4241     /* cmarg2 or filnam (with that precedence) have the file's name */
4242 
4243     lsstate = 0;			/* Cancel locking-shift state */
4244 #ifdef COMMENT
4245     /* Do this after making sure we can open the file */
4246     if (nxtpkt() < 0) return(0);	/* Bump packet number, get buffer */
4247 #endif /* COMMENT */
4248     pktnam[0] = NUL;			/* Buffer for name we will send */
4249     if (x == 0) {			/* F-Packet setup */
4250 	if (!cmarg2) cmarg2 = "";
4251 #ifdef DEBUG
4252 	if (deblog) {
4253 	    /* debug(F111,"sfile cmarg2",cmarg2,cmarg2); */
4254 	    debug(F101,"sfile binary 1","",binary);
4255 	    debug(F101,"sfile wearealike","",wearealike);
4256 	    debug(F101,"sfile xfermode","",xfermode);
4257 	    debug(F101,"sfile filepeek","",filepeek);
4258 #ifndef NOCSETS
4259 	    debug(F101,"sfile s_cset","",s_cset);
4260 	    debug(F101,"sfile tcharset","",tcharset);
4261 	    debug(F101,"sfile xfrxla","",xfrxla);
4262 #endif /* NOCSETS */
4263 	}
4264 #endif /* DEBUG */
4265 	if (xfermode == XMODE_A		/* TRANSFER MODE AUTOMATIC */
4266 #ifndef NOMSEND
4267 	    && !addlist			/* And not working from a SEND-LIST */
4268 #endif /* NOMSEND */
4269 	    ) {
4270 	    /* Other Kermit is on a like system and no charset translation */
4271 	    if (wearealike
4272 #ifndef NOCSETS
4273 		&& (tcharset == TC_TRANSP || xfrxla == 0)
4274 #endif /* NOCSETS */
4275 		) {
4276 #ifdef VMS
4277 		if (binary != XYFT_I)
4278 #endif /* VMS */
4279 #ifdef CK_LABELED
4280 		  if (binary != XYFT_L)
4281 #endif /* CK_LABELED */
4282 		    binary = XYFT_B;	/* Send all files in binary mode */
4283 	    }
4284 
4285 	    /* Otherwise select transfer mode based on file info */
4286 
4287 	    else if (!notafile		/* but not if sending from pipe */
4288 #ifdef CK_LABELED
4289 		     && binary != XYFT_L /* and not if FILE TYPE LABELED */
4290 #endif /* CK_LABELED */
4291 #ifdef VMS
4292 		     && binary != XYFT_I /* or FILE TYPE IMAGE */
4293 #endif /* VMS */
4294 		     ) {
4295 #ifdef UNICODE
4296 		fileorder = -1;		/* File byte order */
4297 #endif /* UNICODE */
4298 		if (filepeek && !notafile) { /* Real file, FILE SCAN is ON */
4299 		    int k, x;
4300 		    k = scanfile(filnam,&x,nscanfile); /* Scan the file */
4301 		    debug(F101,"sfile scanfile","",k);
4302 		    switch (k) {
4303 		      case FT_TEXT:	/* Unspecified text */
4304 			debug(F100,"sfile scanfile text","",0);
4305 			binary = XYFT_T; /* SET FILE TYPE TEXT */
4306 			break;
4307 #ifndef NOCSETS
4308 		      case FT_7BIT:		/* 7-bit text */
4309 			binary = XYFT_T;	/* SET FILE TYPE TEXT */
4310 			/* If SEND CHARSET-SELECTION AUTO  */
4311 			/* and SET TRANSFER TRANSLATION is ON */
4312 			debug(F100,"sfile scanfile text7","",0);
4313 			if (s_cset == XMODE_A && xfrxla) {
4314 			    if (fcsinfo[fcharset].size != 128) {
4315 				fcs_save = fcharset; /* Current FCS not 7bit */
4316 				fcharset = dcset7;   /* Use default 7bit set */
4317 				debug(F101,"sfile scanfile 7 fcharset",
4318 				      "",fcharset);
4319 			    }
4320 			    /* And also switch to appropriate TCS */
4321 			    if (afcset[fcharset] > -1 &&
4322 				afcset[fcharset] <= MAXTCSETS) {
4323 				tcs_save = tcharset;
4324 				tcharset = afcset[fcharset];
4325 				debug(F101,"sfile scanfile 7 tcharset","",
4326 				      tcharset);
4327 			    }
4328 			    setxlatype(tcharset,fcharset);
4329 			}
4330 			break;
4331 
4332 		      case FT_8BIT:	/* 8-bit text */
4333 			binary = XYFT_T; /* SET FILE TYPE TEXT */
4334 			/* If SEND CHARSET-SELEC AUTO  */
4335 			/* and SET TRANSFER TRANSLATION is ON */
4336 			debug(F100,"sfile scanfile text8","",0);
4337 			if (s_cset == XMODE_A && xfrxla) {
4338 			    if (fcsinfo[fcharset].size != 256) {
4339 				fcs_save = fcharset; /* Current FCS not 8bit */
4340 				fcharset = dcset8; /* Use default 8bit set */
4341 				debug(F101,"sfile scanfile 8 fcharset",
4342 				      "",fcharset);
4343 			    }
4344 			    /* Switch to corresponding transfer charset */
4345 			    if (afcset[fcharset] > -1 &&
4346 				afcset[fcharset] <= MAXTCSETS) {
4347 				tcs_save = tcharset;
4348 				tcharset = afcset[fcharset];
4349 				debug(F101,"sfile scanfile 8 tcharset","",
4350 				      tcharset);
4351 			    }
4352 			    setxlatype(tcharset,fcharset);
4353 			}
4354 			break;
4355 #ifdef UNICODE
4356 		      case FT_UTF8:	/* UTF-8 text */
4357 		      case FT_UCS2:	/* UCS-2 text */
4358 			debug(F101,"sfile scanfile Unicode","",k);
4359 			binary = XYFT_T;
4360 			/* If SEND CHARSET-SELEC AUTO  */
4361 			/* and SET TRANSFER TRANSLATION is ON */
4362 			if (s_cset == XMODE_A && xfrxla) {
4363 			    fcs_save = fcharset;
4364 			    tcs_save = tcharset;
4365 			    fcharset = (k == FT_UCS2) ? FC_UCS2 : FC_UTF8;
4366 			    if (k == FT_UCS2 && x > -1)
4367 			      fileorder = x;
4368 			}
4369 			/* Switch to associated transfer charset if any */
4370 			if (afcset[fcharset] > -1 &&
4371 			    afcset[fcharset] <= MAXTCSETS)
4372 			  tcharset = afcset[fcharset];
4373 			if (tcharset == TC_TRANSP) /* If none */
4374 			  tcharset = TC_UTF8;      /* use UTF-8 */
4375 			setxlatype(tcharset,fcharset);
4376 			debug(F101,"sfile Unicode tcharset","",tcharset);
4377 			break;
4378 #endif /* UNICODE */
4379 #endif /* NOCSETS */
4380 		      case FT_BIN:
4381 			debug(F101,"sfile scanfile binary","",k);
4382 			binary = XYFT_B;
4383 			break;
4384 		    /* Default: Don't change anything */
4385 		    }
4386 		}
4387 	    }
4388 	    debug(F101,"sfile binary 2","",binary);
4389 	    debug(F101,"sfile sendmode","",sendmode);
4390 	}
4391     	if (*cmarg2) {			/* If we have a send-as name... */
4392 	    int y; char *s;
4393 #ifndef NOSPL				/* and a script programming language */
4394 	    extern int cmd_quoting;
4395 	    if (cmd_quoting) {		/* and it's not turned off */
4396 		y = PKTNL;		/* pass as-name thru the evaluator */
4397 		s = pktnam;
4398 		zzstring(cmarg2,&s,&y);
4399 #ifdef COMMENT
4400 /* This ruins macros like BSEND */
4401 		if (!pktnam[0])		/* and make sure result is not empty */
4402 		  sprintf(pktnam,"FILE%02ld",filcnt);
4403 #endif /* COMMENT */
4404 	    } else
4405 #endif /* NOSPL */
4406 	      ckstrncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */
4407 
4408 	    debug(F110,"sfile pktnam",pktnam,0);
4409 #ifdef COMMENT
4410 /* We don't do this any more because now we have filename templates */
4411 	    cmarg2 = "";		/* and blank it out for next time. */
4412 #endif /* COMMENT */
4413     	}
4414 	if (!*pktnam) {			/* No as-name... */
4415 #ifdef NZLTOR
4416 	    int xfncnv, xpath;
4417 	    debug(F101,"sfile fnspath","",fnspath);
4418 	    debug(F101,"sfile fncnv","",fncnv);
4419 	    xfncnv = fncnv;
4420 	    xpath = fnspath;
4421 	    if (notafile) {		/* If not an actual file */
4422 		xfncnv = 0;		/* Don't convert name */
4423 		xpath = PATH_OFF;	/* Leave path off */
4424 	    } else if (xfncnv &&
4425 		       (!strcmp(whoareu,"U1") || !strcmp(whoareu,"UN"))
4426 		       ) {
4427 		/* Less-strict conversion if partner is UNIX or Win32 */
4428 		xfncnv = -1;
4429 	    }
4430 	    debug(F101,"sfile xpath","",xpath);
4431 	    debug(F101,"sfile xfncnv","",xfncnv);
4432 	    nzltor(filnam,pktnam,xfncnv,xpath,PKTNL);
4433 
4434 #else  /* Not NZLTOR */
4435 
4436 	    debug(F101,"sfile fnspath","",fnspath);
4437 	    if (fnspath == PATH_OFF	/* Stripping path names? */
4438 		&& (!notafile)		/* (of actual files) */
4439 		) {
4440 		char *t;		/* Yes. */
4441 		zstrip(filnam,&t);	/* Strip off the path. */
4442 		debug(F110,"sfile zstrip",t,0);
4443 		if (!t) t = "UNKNOWN";	/* Be cautious... */
4444 		else if (*t == '\0')
4445 		  t = "UNKNOWN";
4446 		ckstrncpy(pktnam,t,PKTNL); /* Copy stripped name literally. */
4447 	    } else if (fnspath == PATH_ABS && !notafile) {
4448 		/* Converting to absolute form */
4449 		zfnqfp(filnam,PKTNL,pktnam);
4450 	    } else
4451 		ckstrncpy(pktnam,filnam,PKTNL);
4452 
4453 	    /* pktnam[] has the packet name, filnam[] has the original name. */
4454 	    /* But we still need to convert pktnam if FILE NAMES CONVERTED.  */
4455 
4456 	    debug(F101,"sfile fncnv","",fncnv);
4457 	    if (fncnv && !notafile) {	/* If converting names of files */
4458 		zltor(pktnam,(char *)srvcmd); /* convert it to common form, */
4459 		ckstrncpy(pktnam,(char *)srvcmd,PKTNL);
4460 		*srvcmd = NUL;
4461 	    }
4462 #endif /* NZLTOR */
4463     	}
4464 	if (!*pktnam)			/* Failsafe... */
4465 	  sprintf(pktnam,"FILE%02ld",filcnt);
4466 	debug(F110,"sfile filnam 1",filnam,0);
4467 	debug(F110,"sfile pktnam 1",pktnam,0);
4468 #ifdef PIPESEND
4469 /* If we have a send filter, substitute the current filename into it */
4470 
4471 	if (sndfilter) {
4472 	    char * p = NULL, * q;
4473 	    int n = CKMAXPATH;
4474 #ifndef NOSPL
4475 	    if ((p = (char *) malloc(n + 1))) {
4476 		q = p;
4477 		debug(F110,"sfile pipesend filter",sndfilter,0);
4478 		zzstring(sndfilter,&p,&n);
4479 		debug(F111,"sfile pipename",q,n);
4480 		if (n <= 0) {
4481 		    printf(
4482 			  "?Sorry, send filter + filename too long, %d max.\n",
4483 			   CKMAXPATH
4484 			   );
4485 		    free(q);
4486 		    return(0);
4487 		}
4488 		ckstrncpy(filnam,q,CKMAXPATH+1);
4489 		free(q);
4490 	    }
4491 #endif /* NOSPL */
4492 	}
4493 #endif /* PIPESEND */
4494 
4495     	debug(F110,"sfile filnam 2",filnam,0); /* Log debugging info */
4496     	debug(F110,"sfile pktnam 2",pktnam,0);
4497     	if (openi(filnam) == 0) 	/* Try to open the input file */
4498 	  return(0);
4499 
4500 #ifdef CK_RESEND
4501 /*
4502   The following check is done after openi() is called, since openi() itself
4503   can change the transfer mode (as in VMS).
4504 */
4505         if ((binary == XYFT_T
4506 #ifdef VMS
4507 	     || binary == XYFT_L
4508 #endif /* VMS */
4509 	     ) && sendmode == SM_RESEND) {
4510             /* Trying to RESEND/REGET a file first sent in TEXT mode. */
4511 	    debug(F111,"sfile error - Recover vs Text",filnam,binary);
4512             /* Set appropriate error messages and make log entries here */
4513 #ifdef VMS
4514 	    if (binary == XYFT_L)
4515 	      ckmakmsg((char *)epktmsg,
4516 		       PKTMSGLEN,
4517 		       "Recovery attempted in LABELED mode: ",
4518 		       filnam,
4519 		       NULL,
4520 		       NULL
4521 		       );
4522 	    else
4523 #endif /* VMS */
4524 	      ckmakmsg((char *)epktmsg,
4525 		       PKTMSGLEN,
4526 		       "Recovery attempted in TEXT mode: ",
4527 		       filnam,
4528 		       NULL,
4529 		       NULL
4530 		       );
4531             return(0);
4532         }
4533 	if (sendmode == SM_PSEND)	/* PSENDing? */
4534 	  if (sendstart > (CK_OFF_T)0)	/* Starting position */
4535 	    if (zfseek(sendstart) < 0)	/* seek to it... */
4536 	      return(0);
4537 #endif /* CK_RESEND */
4538     	s = pktnam;			/* Name for packet data field */
4539 #ifdef OS2
4540 	/* Never send a disk letter. */
4541 	if (isalpha(*s) && (*(s+1) == ':'))
4542 	  s += 2;
4543 #endif /* OS2 */
4544 
4545     } else {				/* X-packet setup, not F-packet. */
4546 	binary = XYFT_T;		/* Text always */
4547     	debug(F110,"sfile X packet",cmdstr,0); /* Log debugging info */
4548     	s = cmdstr;			/* Name for data field */
4549     }
4550 
4551     /* Now s points to the string that goes in the packet data field. */
4552 
4553     debug(F101,"sfile binary","",binary); /* Log debugging info */
4554     encstr((CHAR *)s);			/* Encode the name. */
4555 					/* Send the F or X packet */
4556     /* If the encoded string did not fit into the packet, it was truncated. */
4557 
4558     if (nxtpkt() < 0) return(0);	/* Bump packet number, get buffer */
4559 
4560     rc = spack((char) (x ? 'X' : 'F'), pktnum, size, data);
4561     if (rc < 0)
4562       return(rc);
4563 
4564 #ifndef NOCSETS
4565     setxlatype(tcharset,fcharset);	/* Set up charset translations */
4566 #endif /* NOCSETS */
4567 
4568     if (x == 0) {			/* Display for F packet */
4569     	if (displa) {			/* Screen */
4570 	    xxscreen(SCR_FN,'F',(long)pktnum,filnam);
4571 	    xxscreen(SCR_AN,0,0L,pktnam);
4572 	    xxscreen(SCR_FS,0,calibrate ? calibrate : fsize,"");
4573     	}
4574 #ifdef pdp11
4575     	tlog(F110,"Sending",filnam,0L); /* Transaction log entry */
4576 	makestr(&psfspec,filnam);	/* New filename */
4577 #else
4578 #ifndef ZFNQFP
4579     	tlog(F110,"Sending",filnam,0L);
4580 	makestr(&psfspec,filnam);	/* New filename */
4581 #else
4582 	if (notafile) {			/* If not a file log simple name */
4583 	    tlog(F110,"Sending", filnam, 0L);
4584 	} else {			/* Log fully qualified filename */
4585 #ifdef COMMENT
4586 	    /* This section generates bad code in SCO 3.2v5.0.5's cc */
4587 	    char *p = NULL, *q = filnam;
4588 	    debug(F101,"sfile CKMAXPATH","",CKMAXPATH);
4589 	    if ((p = malloc(CKMAXPATH+1))) {
4590 		debug(F111,"sfile calling zfnqfp",filnam,strlen(filnam));
4591 		if (zfnqfp(filnam, CKMAXPATH, p)) {
4592 		    debug(F111,"sfile zfnqfp ok",p,strlen(p));
4593 		    q = p;
4594 		}
4595 	    }
4596 #else
4597 	    char tmpbuf[CKMAXPATH+1];
4598 	    char *p = tmpbuf, *q = filnam;
4599 	    if (zfnqfp(filnam, CKMAXPATH, p))
4600 	      q = p;
4601 #endif /* COMMENT */
4602 	    debug(F111,"sfile q",q,strlen(q));
4603 	    tlog(F110,"Sending",q,0L);
4604 	    makestr(&psfspec,q);	/* New preliminary filename */
4605 #ifdef COMMENT
4606 	    if (p) free(p);
4607 #endif /* COMMENT */
4608 	}
4609 #endif /* ZFNQFP */
4610 #endif /* pdp11 */
4611     	tlog(F110," as",pktnam,0L);
4612 	if (binary) {			/* Log file mode in transaction log */
4613 	    tlog(F101," mode: binary","",(long) binary);
4614 	} else {			/* If text mode, check character set */
4615 	    tlog(F100," mode: text","",0L);
4616 #ifndef NOCSETS
4617 	    if (tcharset == TC_TRANSP || xfrxla == 0) {
4618 		tlog(F110," character set","transparent",0L);
4619 	    } else {
4620 		tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
4621 		tlog(F110," file character set",fcsinfo[fcharset].name,0L);
4622 	    }
4623 #endif /* NOCSETS */
4624 	}
4625     } else {				/* Display for X-packet */
4626 
4627     	xxscreen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */
4628     	tlog(F110,"Sending from:",cmdstr,0L);	/* Transaction log */
4629     }
4630     intmsg(++filcnt);			/* Count file, give interrupt msg */
4631     first = 1;				/* Init file character lookahead. */
4632     ffc = (CK_OFF_T)0;			/* Init file character counter. */
4633     cps = oldcps = 0L;			/* Init cps statistics */
4634     rejection = -1;
4635     fsecs = gtimer();			/* Time this file started */
4636 #ifdef GFTIMER
4637     fpfsecs = gftimer();
4638     debug(F101,"SFILE fpfsecs","",fpfsecs);
4639 #endif /* GFTIMER */
4640     debug(F101,"SFILE fsecs","",fsecs);
4641     return(1);
4642 }
4643 
4644 /*  S D A T A -- Send a data packet */
4645 
4646 /*
4647   Returns -1 if no data to send (end of file), -2 if connection is broken.
4648   If there is data, a data packet is sent, and sdata() returns 1.
4649 
4650   In the streaming case, the window is regarded as infinite and we keep
4651   sending data packets until EOF or there appears to be a Kermit packet on the
4652   reverse channel.  When not streaming and the window size is greater than 1,
4653   we keep sending data packets until window is full or characters start to
4654   appear from the other Kermit.
4655 
4656   In the windowing or streaming case, when there is no more data left to send
4657   (or when sending has been interrupted), sdata() does nothing and returns 0
4658   each time it is called until the acknowledgement sequence number catches up
4659   to the last data packet that was sent.
4660 */
4661 int
sdata()4662 sdata() {
4663     int i, x, len;
4664     char * s;
4665 
4666     debug(F101,"sdata entry, first","",first);
4667     debug(F101,"sdata drain","",drain);
4668 /*
4669   The "drain" flag is used with window size > 1.  It means we have sent
4670   our last data packet.  If called and drain is not zero, then we return
4671   0 as if we had sent an empty data packet, until all data packets have
4672   been ACK'd, then then we can finally return -1 indicating EOF, so that
4673   the protocol can switch to seof state.  This is a kludge, but at least
4674   it's localized...
4675 */
4676     if (first == 1) drain = 0;		/* Start of file, init drain flag. */
4677 
4678     if (drain) {			/* If draining... */
4679 	debug(F101,"sdata draining, winlo","",winlo);
4680 	if (winlo == pktnum)		/* If all data packets are ACK'd */
4681 	  return(-1);			/* return EOF indication */
4682 	else				/* otherwise */
4683 	  return(0);			/* pretend we sent a data packet. */
4684     }
4685     debug(F101,"sdata sbufnum","",sbufnum);
4686     for (i = sbufnum;
4687 	 i > 0
4688 #ifdef STREAMING
4689 	 || streaming
4690 #endif /* STREAMING */
4691 	 ;
4692 	 i--) {
4693 	if (i < 0)
4694 	  break;
4695         debug(F101,"sdata countdown","",i);
4696 #ifdef STREAMING
4697 	if (streaming) {
4698 	    pktnum = (pktnum + 1) % 64;
4699 	    winlo = pktnum;
4700 	    debug(F101,"sdata streaming pktnum","",pktnum);
4701 	} else {
4702 #endif /* STREAMING */
4703 	    x = nxtpkt();		/* Get next pkt number and buffer */
4704 	    debug(F101,"sdata nxtpkt pktnum","",pktnum);
4705 	    if (x < 0) return(0);
4706 #ifdef STREAMING
4707 	}
4708 #endif /* STREAMING */
4709 	debug(F101,"sdata packet","",pktnum);
4710 	if (chkint() < 0)		/* Especially important if streaming */
4711 	  return(-9);
4712 	if (cxseen || czseen) {		/* If interrupted, done. */
4713 	    if (wslots > 1) {
4714 		drain = 1;
4715 		debug(F100,"sdata cx/zseen windowing","",0);
4716 		return(0);
4717 	    } else {
4718 		debug(F100,"sdata cx/zseen nonwindowing","",0);
4719 		return(-1);
4720 	    }
4721 	}
4722 #ifdef DEBUG
4723 	if (deblog) {
4724 	    debug(F101,"sdata spsiz","",spsiz);
4725 	    debug(F101,"sdata binary","",binary);
4726 	    debug(F101,"sdata parity","",parity);
4727 	}
4728 #endif /* DEBUG */
4729 #ifdef CKTUNING
4730 	if (binary && !parity && !memstr && !funcstr)
4731 	  len = bgetpkt(spsiz);
4732 	else
4733 	  len = getpkt(spsiz,1);
4734 #else
4735 	len = getpkt(spsiz,1);
4736 #endif /* CKTUNING */
4737 	s = (char *)data;
4738 	if (len == -3) {		/* Timed out (e.g.reading from pipe) */
4739 	    s = "";			/* Send an empty data packet. */
4740 	    len = 0;
4741 	} else if (len == 0) {		/* Done if no data. */
4742 	    if (pktnum == winlo)
4743 	      return(-1);
4744 	    drain = 1;			/* But can't return -1 until all */
4745 	    debug(F101,"sdata eof, drain","",drain);
4746 	    return(0);			/* ACKs are drained. */
4747 	}
4748 	debug(F101,"sdata pktnum","",pktnum);
4749 	debug(F101,"sdata len","",len);
4750 	debug(F011,"sdata data",data,52);
4751 
4752 	x = spack('D',pktnum,len,(CHAR *)s); /* Send the data packet. */
4753 	debug(F101,"sdata spack","",x);
4754 	if (x < 0) {			/* Error */
4755 	    ttchk();			/* See if connection is still there */
4756 	    return(-2);
4757 	}
4758 #ifdef STREAMING
4759 	if (streaming)			/* What an ACK would do. */
4760 	  winlo = pktnum;
4761 #endif /* STREAMING */
4762 	x = ttchk();			/* Peek at input buffer. */
4763 	debug(F101,"sdata ttchk","",x);	/* ACKs waiting, maybe?  */
4764 	if (x < 0)			/* Or connection broken? */
4765 	  return(-2);
4766 /*
4767   Here we check to see if any ACKs or NAKs have arrived, in which case we
4768   break out of the D-packet-sending loop and return to the state switcher
4769   to process them.  This is what makes our windows slide instead of lurch.
4770 */
4771 	if (
4772 #ifdef GEMDOS
4773 /*
4774   In the Atari ST version, ttchk() can only return 0 or 1.  But note: x will
4775   probably always be > 0, since the as-yet-unread packet terminator from the
4776   last packet is probably still in the buffer, so sliding windows will
4777   probably never happen when the Atari ST is the file sender.  The alternative
4778   is to say "if (0)", in which case the ST will always send a window full of
4779   packets before reading any ACKs or NAKs.
4780 */
4781 	    x > 0
4782 
4783 #else /* !GEMDOS */
4784 /*
4785   In most other versions, ttchk() returns the actual count.
4786   It can't be a Kermit packet if it's less than five bytes long.
4787 */
4788 	    x > 4 + bctu
4789 
4790 #endif /* GEMDOS */
4791 	    )
4792 	  return(1);			/* Yes, stop sending data packets */
4793     }					/* and go try to read the ACKs. */
4794     return(1);
4795 }
4796 
4797 
4798 /*  S E O F -- Send an End-Of-File packet */
4799 
4800 /*  Call with a string pointer to character to put in the data field, */
4801 /*  or else a null pointer or "" for no data.  */
4802 
4803 /*
4804   There are two "send-eof" functions.  seof() is used to send the normal eof
4805   packet at the end of a file's data (even if the file has no data), or when
4806   a file transfer is interrupted.  sxeof() is used to send an EOF packet that
4807   occurs because of attribute refusal or interruption prior to entering data
4808   state.  The difference is purely a matter of buffer allocation and packet
4809   sequence number management.  Both functions act as "front ends" to the
4810   common send-eof function, szeof().
4811 */
4812 
4813 /* Code common to both seof() and sxeof() */
4814 
4815 int
szeof(s)4816 szeof(s) CHAR *s; {
4817     int x;
4818     lsstate = 0;			/* Cancel locking-shift state */
4819     if (!s) s = (CHAR *)"";
4820     debug(F111,"szeof",s,pktnum);
4821     if (*s) {
4822 	x = spack('Z',pktnum,1,s);
4823 	xitsta |= W_SEND;
4824 #ifdef COMMENT
4825 	tlog(F100," *** interrupted, sending discard request","",0L);
4826 #endif /* COMMENT */
4827 	filrej++;
4828     } else {
4829 	x = spack('Z',pktnum,0,(CHAR *)"");
4830     }
4831     if (x < 0)
4832       return(x);
4833 
4834 #ifdef COMMENT
4835     /* No, too soon */
4836     discard = 0;			/* Turn off per-file discard flag */
4837 #endif /* COMMENT */
4838 
4839 /* If we were sending from a pipe, we're not any more... */
4840     pipesend = 0;
4841     return(0);
4842 }
4843 
4844 int
seof(x)4845 seof(x) int x; {
4846     char * s;
4847 /*
4848   ckcpro.w, before calling seof(), sets window size back to 1 and then calls
4849   window(), which clears out the old buffers.  This is OK because the final
4850   data packet for the file has been ACK'd.  However, sdata() has already
4851   called nxtpkt(), which set the new value of pktnum which seof() will use.
4852   So all we need to do here is is allocate a new send-buffer.
4853 */
4854     s = x ? "D" : "";
4855     debug(F111,"seof",s,pktnum);
4856     if (getsbuf(pktnum) < 0) {	/* Get a buffer for packet n */
4857 	debug(F101,"seof can't get s-buffer","",pktnum);
4858 	return(-1);
4859     }
4860     return(szeof((CHAR *)s));
4861 }
4862 
4863 /*
4864   Version of seof() to be called when sdata() has not been called before.  The
4865   difference is that this version calls nxtpkt() to allocate a send-buffer and
4866   get the next packet number.
4867 */
4868 int
sxeof(x)4869 sxeof(x) int x; {
4870     char * s;
4871     s = x ? "D" : "";
4872     if (nxtpkt() < 0)			/* Get next pkt number and buffer */
4873       debug(F101,"sxeof nxtpkt fails","",pktnum);
4874     else
4875       debug(F101,"sxeof packet","",pktnum);
4876     return(szeof((CHAR *)s));
4877 }
4878 
4879 /*  S E O T -- Send an End-Of-Transaction packet */
4880 
4881 int
seot()4882 seot() {
4883     int x;
4884     x = nxtpkt();
4885     debug(F101,"seot nxtpkt","",x);
4886     if (x < 0) return(-1);		/* Bump packet number, get buffer */
4887     x = spack('B',pktnum,0,(CHAR *)"");	/* Send the EOT packet */
4888     if (x < 0)
4889       return(x);
4890     cxseen = czseen = discard = 0;	/* Reset interruption flags */
4891     tstats();				/* Log timing info */
4892     return(0);
4893 }
4894 
4895 
4896 /*   R P A R -- Fill the data array with my send-init parameters  */
4897 
4898 int q8flag = 0;
4899 
4900 CHAR dada[32];				/* Use this instead of data[]. */
4901 					/* To avoid some kind of wierd */
4902 					/* addressing foulup in spack()... */
4903 					/* (which might be fixed now...) */
4904 
4905 CHAR *
rpar()4906 rpar() {
4907     char *p;
4908     int i, x, max;
4909     extern int sprmlen;
4910 
4911     max = maxdata();			/* Biggest data field I can send */
4912     debug(F101, "rpar max 1","",max);
4913     debug(F101, "rpar sprmlen","",sprmlen);
4914     if (sprmlen > 1 && sprmlen < max)	/* User override */
4915       max = sprmlen;
4916     debug(F101, "rpar max 2","",max);
4917 
4918     if (rpsiz > MAXPACK)		/* Biggest normal packet I want. */
4919       dada[0] = (char) tochar(MAXPACK);	/* If > 94, use 94, but specify */
4920     else				/* extended packet length below... */
4921       dada[0] = (char) tochar(rpsiz);	/* else use what the user said. */
4922     dada[1] = (char) tochar(chktimo(pkttim,0)); /* When to time me out */
4923     dada[2] = (char) tochar(mypadn);	/* How much padding I need (none) */
4924     dada[3] = (char) ctl(mypadc);	/* Padding character I want */
4925     dada[4] = (char) tochar(eol);	/* End-Of-Line character I want */
4926     dada[5] = myctlq;			/* Control-Quote character I send */
4927 
4928     if (max < 6) { dada[6] = NUL; rqf = 0; ebq = sq = NUL; return(dada); }
4929 
4930     switch (rqf) {			/* 8th-bit prefix (single-shift) */
4931       case -1:				/* I'm opening the bids */
4932       case  1:				/* Other Kermit already bid 'Y' */
4933 	if (parity) ebq = sq = MYEBQ;	/* So I reply with '&' if parity */
4934 	break;				/*  otherwise with 'Y'. */
4935       case  2:				/* Other Kermit sent a valid prefix */
4936 	if (q8flag)
4937 	  sq = ebq;			/* Fall through on purpose */
4938       case  0:				/* Other Kermit bid nothing */
4939 	break;				/* So I reply with 'Y'. */
4940     }
4941     debug(F000,"rpar 8bq sq","",sq);
4942     debug(F000,"rpar 8bq ebq","",ebq);
4943     if (lscapu == 2)			/* LOCKING-SHIFT FORCED */
4944       dada[6] = 'N';			/* requires no single-shift */
4945     else				/* otherwise send prefix or 'Y' */
4946       dada[6] = (char) sq;
4947     ebqsent = dada[6];			/* And remember what I really sent */
4948 
4949     if (max < 7) { dada[7] = NUL; bctr = 1; return(dada); }
4950 
4951     dada[7] = (char) (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */
4952 
4953     if (max < 8) { dada[8] = NUL; rptflg = 0; return(dada); }
4954 
4955     if (rptena) {
4956 	if (rptflg)			/* Run length encoding */
4957 	  dada[8] = (char) rptq;	/* If receiving, agree */
4958 	else				/* by replying with same character. */
4959 	  dada[8] = (char) (rptq = myrptq); /* When sending use this. */
4960     } else dada[8] = SP;		/* Not enabled, put a space here. */
4961 
4962     /* CAPAS mask */
4963 
4964     if (max < 9) {
4965 	dada[9] = NUL;
4966 	atcapr = 0;
4967 	lpcapr = 0;
4968 	swcapr = 0;
4969 	rscapr = 0;
4970 	return(dada);
4971     }
4972     dada[9] = (char) tochar((lscapr ? lscapb : 0) | /* Locking shifts */
4973 		     (atcapr ? atcapb : 0) | /* Attribute packets */
4974 		     (lpcapr ? lpcapb : 0) | /* Long packets */
4975 		     (swcapr ? swcapb : 0) | /* Sliding windows */
4976 		     (rscapr ? rscapb : 0)); /* RESEND */
4977     if (max < 10) { wslotr = 1; return(dada); }
4978     dada[10] = (char) tochar(swcapr ? wslotr : 1); /* CAPAS+1 = Window size */
4979 
4980     if (max < 12) { rpsiz = 80; return(dada); }
4981     if (urpsiz > 94)
4982       rpsiz = urpsiz - 1;		/* Long packets ... */
4983     dada[11] = (char) tochar(rpsiz / 95); /* Long packet size, big part */
4984     dada[12] = (char) tochar(rpsiz % 95); /* Long packet size, little part */
4985 
4986     if (max < 16) return(dada);
4987     dada[13] = '0';			/* CAPAS+4 = WONT CHKPNT */
4988     dada[14] = '_';			/* CAPAS+5 = CHKINT (reserved) */
4989     dada[15] = '_';			/* CAPAS+6 = CHKINT (reserved) */
4990     dada[16] = '_';			/* CAPAS+7 = CHKINT (reserved) */
4991     if (max < 17) return(dada);
4992 #ifndef WHATAMI
4993     dada[17] = ' ';
4994 #else
4995     x = 0;
4996     if (server) x |= WMI_SERVE;		/* Whether I am a server */
4997     if (binary) x |= WMI_FMODE;		/* My file transfer mode is ... */
4998     if (fncnv)  x |= WMI_FNAME;		/* My filename conversion is ... */
4999 #ifdef STREAMING
5000     if (streamrq == SET_ON)
5001       x |= WMI_STREAM;
5002     else if (streamrq == SET_AUTO && reliable == SET_ON)
5003       x |= WMI_STREAM;
5004     /*
5005       Always offer to stream when in remote mode and STREAMING is AUTO
5006       and RELIABLE is not OFF (i.e. is ON or AUTO).
5007     */
5008     else if (!local && streamrq == SET_AUTO && reliable != SET_OFF)
5009       x |= WMI_STREAM;
5010 #endif /* STREAMING */
5011 #ifdef TCPSOCKET
5012     if (clearrq == SET_ON)
5013       x |= WMI_CLEAR;
5014     else if (clearrq == SET_AUTO &&	/* SET CLEAR-CHANNEL AUTO */
5015 	     ((network && nettype == NET_TCPB /* TCP/IP */
5016 #ifdef RLOGCODE
5017                 && ttnproto != NP_RLOGIN/* Rlogin is not clear */
5018                 && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN)
5019 #endif /* RLOGCODE */
5020 	       )
5021 #ifdef SSHBUILTIN
5022               || (network && nettype == NET_SSH)
5023 #endif /* SSHBUILTIN */
5024 #ifdef IKSD
5025 	      || inserver		/* We are IKSD */
5026 #endif /* IKSD */
5027 	      ))
5028       x |= WMI_CLEAR;
5029 #endif /* TCPSOCKET */
5030     x |= WMI_FLAG;
5031     dada[17] = (char) tochar(x);
5032 #endif /* WHATAMI */
5033     i = 18;				/* Position of next field */
5034     p = cksysid;			/* WHOAMI (my system ID) */
5035     x = strlen(p);
5036     if (max - i < x + 1) return(dada);
5037     if (x > 0) {
5038 	dada[i++] = (char) tochar(x);
5039 	while (*p)
5040 	  dada[i++] = *p++;
5041     }
5042 
5043     if (max < i+1) return(dada);
5044 #ifndef WHATAMI				/* WHATAMI2 */
5045     dada[i++] = ' ';
5046 #else
5047     debug(F101,"rpar xfermode","",xfermode);
5048     x = WMI2_FLAG;			/* Is-Valid flag */
5049     if (xfermode != XMODE_A)		/* If TRANSFER MODE is MANUAL */
5050       x |= WMI2_XMODE;			/* set the XFERMODE bit */
5051     if (recursive > 0)			/* If this is a recursive transfer */
5052       x |= WMI2_RECU;			/* set the RECURSIVE bit */
5053     dada[i++] = tochar(x);
5054     debug(F101,"rpar whatami2","",x);
5055 #endif /* WHATAMI */
5056 
5057     dada[i] = '\0';			/* Terminate the init string */
5058 
5059 #ifdef DEBUG
5060     if (deblog) {
5061 	debug(F110,"rpar",dada,0);
5062 	rdebu(dada,(int)strlen((char *)dada));
5063     }
5064 #endif /* DEBUG */
5065     ckstrncpy((char *)myinit,(char *)dada,MYINITLEN);
5066     return(dada);			/* Return pointer to string. */
5067 }
5068 
5069 int
spar(s)5070 spar(s) CHAR *s; {			/* Set parameters */
5071     int x, y, lpsiz, biggest;
5072     extern int rprmlen, lastspmax;
5073     extern struct sysdata sysidlist[];
5074 
5075     whatru = 0;
5076     whoareu[0] = NUL;
5077 #ifdef STREAMING
5078     streamok = 0;
5079     streaming = 0;
5080 #endif /* STREAMING */
5081     biggest = rln;
5082 
5083     debug(F101, "spar biggest 1","",biggest);
5084     debug(F101, "spar rprmlen","",rprmlen);
5085     if (rprmlen > 1 && rprmlen < biggest)
5086       biggest = rprmlen;
5087     debug(F101, "rpar biggest 2","",biggest);
5088     debug(F110,"spar packet",s,0);
5089 
5090     s--;				/* Line up with field numbers. */
5091 
5092 /* Limit on size of outbound packets */
5093     x = (biggest >= 1) ? xunchar(s[1]) : 80;
5094     lpsiz = spsizr;			/* Remember what they SET. */
5095     if (spsizf) {			/* SET-command override? */
5096 	if (x < spsizr) spsiz = x;	/* Ignore LEN unless smaller */
5097     } else {				/* otherwise */
5098 	spsiz = (x < 10) ? 80 : x;	/* believe them if reasonable */
5099     }
5100     spmax = spsiz;			/* Remember maximum size */
5101 
5102 /* Timeout on inbound packets */
5103     if (timef) {
5104 	timint = rtimo;			/* SET SEND TIMEOUT value overrides */
5105     } else {				/* Otherwise use requested value, */
5106 	x = (biggest >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */
5107 	timint = (x < 0) ? rtimo : x;
5108     }
5109     timint = chktimo(timint,timef);	/* Adjust if necessary */
5110 
5111 /* Outbound Padding */
5112     npad = 0; padch = '\0';
5113     if (biggest >= 3) {
5114 	npad = xunchar(s[3]);
5115 	if (biggest >= 4) padch = (CHAR) ctl(s[4]); else padch = 0;
5116     }
5117     if (npad) {
5118 	int i;
5119 	for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
5120     }
5121 
5122 /* Outbound Packet Terminator */
5123     seol = (CHAR) (biggest >= 5) ? xunchar(s[5]) : CR;
5124     if ((seol < 1) || (seol > 31)) seol = CR;
5125 
5126 /* Control prefix that the other Kermit is sending */
5127     x = (biggest >= 6) ? s[6] : '#';
5128     ctlq = (CHAR) (((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#');
5129 
5130 /* 8th-bit prefix */
5131 /*
5132   NOTE: Maybe this could be simplified using rcvtyp.
5133   If rcvtyp == 'Y' then we're reading the ACK,
5134   otherwise we're reading the other Kermit's initial bid.
5135   But his horrendous code has been working OK for years, so...
5136 */
5137     rq = (biggest >= 7) ? s[7] : 0;
5138     if (rq == 'Y') rqf = 1;
5139       else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
5140         else rqf = 0;
5141     debug(F000,"spar 8bq rq","",rq);
5142     debug(F000,"spar 8bq sq","",sq);
5143     debug(F000,"spar 8bq ebq","",ebq);
5144     debug(F101,"spar 8bq rqf","",rqf);
5145     switch (rqf) {
5146       case 0:				/* Field is missing from packet. */
5147 	ebqflg = 0;			/* So no 8th-bit prefixing. */
5148 	break;
5149       case 1:				/* Other Kermit sent 'Y' = Will Do. */
5150 	/*
5151           When I am the file receiver, ebqsent is 0 because I didn't send a
5152           negotiation yet.  If my parity is set to anything other than NONE,
5153           either because my user SET PARITY or because I detected parity bits
5154           on this packet, I reply with '&', otherwise 'Y'.
5155 
5156 	  When I am the file sender, ebqsent is what I just sent in rpar(),
5157           which can be 'Y', 'N', or '&'.  If I sent '&', then this 'Y' means
5158           the other Kermit agrees to do 8th-bit prefixing.
5159 
5160           If I sent 'Y' or 'N', but then detected parity on the ACK packet
5161           that came back, then it's too late: there is no longer any way for
5162           me to tell the other Kermit that I want to do 8th-bit prefixing, so
5163           I must not do it, and in that case, if there is any 8-bit data in
5164           the file to be transferred, the transfer will fail because of block
5165           check errors.
5166 
5167           The following clause covers all of these situations:
5168 	*/
5169 	if (parity && (ebqsent == 0 || ebqsent == '&')) {
5170 	    ebqflg = 1;
5171 	    ebq = MYEBQ;
5172 	}
5173 	break;
5174       case 2:				/* Other Kermit sent a valid prefix */
5175 	ebqflg = (ebq == sq || sq == 'Y');
5176 	if (ebqflg) {
5177 	    ebq = rq;
5178 	    debug(F101,"spar setting parity to space","",ebq);
5179 	    if (!parity) parity = ttprty = 's';
5180 	}
5181     }
5182     if (lscapu == 2) {     /* But no single-shifts if LOCKING-SHIFT FORCED */
5183 	ebqflg = 0;
5184 	ebq = 'N';
5185     }
5186 
5187 /* Block check */
5188     x = 1;
5189     if (biggest >= 8) {
5190 	if (s[8] == 'B') x = 4;
5191 	else x = s[8] - '0';
5192 	if ((x < 1) || (x > 5)) x = 1;	/* "5" 20110605 */
5193     }
5194     bctr = x;
5195 
5196 /* Repeat prefix */
5197 
5198     rptflg = 0;				/* Assume no repeat-counts */
5199     if (biggest >= 9) {			/* Is there a repeat-count field? */
5200 	char t;				/* Yes. */
5201 	t = s[9];			/* Get its contents. */
5202 /*
5203   If I'm sending files, then I'm reading these parameters from an ACK, and so
5204   this character must agree with what I sent.
5205 */
5206 	if (rptena) {			/* If enabled ... */
5207 	    if ((char) rcvtyp == 'Y') {	/* Sending files, reading ACK. */
5208 		if (t == myrptq) rptflg = 1;
5209 	    } else {			/* I'm receiving files */
5210 		if ((t > 32 && t < 63) || (t > 95 && t < 127)) {
5211 		    rptflg = 1;
5212 		    rptq = t;
5213 		}
5214 	    }
5215 	} else rptflg = 0;
5216     }
5217 
5218 /* Capabilities */
5219 
5220     atcapu = lpcapu = swcapu = rscapu = 0; /* Assume none of these. */
5221     if (lscapu != 2) lscapu = 0;	/* Assume no LS unless forced. */
5222     y = 11;				/* Position of next field, if any */
5223     if (biggest >= 10) {
5224         x = xunchar(s[10]);
5225 	debug(F101,"spar capas","",x);
5226         atcapu = (x & atcapb) && atcapr; /* Attributes */
5227 	lpcapu = (x & lpcapb) && lpcapr; /* Long packets */
5228 	swcapu = (x & swcapb) && swcapr; /* Sliding windows */
5229 	rscapu = (x & rscapb) && rscapr; /* RESEND */
5230 	debug(F101,"spar lscapu","",lscapu);
5231 	debug(F101,"spar lscapr","",lscapr);
5232 	debug(F101,"spar ebqflg","",ebqflg);
5233 	if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0;
5234 	debug(F101,"spar swcapr","",swcapr);
5235 	debug(F101,"spar swcapu","",swcapu);
5236 	debug(F101,"spar lscapu","",lscapu);
5237 	for (y = 10; (xunchar(s[y]) & 1) && (biggest >= y); y++);
5238 	debug(F101,"spar y","",y);
5239     }
5240 
5241 /* Long Packets */
5242     debug(F101,"spar lpcapu","",lpcapu);
5243     if (lpcapu) {
5244         if (biggest > y+1) {
5245 	    x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
5246 	    debug(F101,"spar lp len","",x);
5247 	    if (spsizf) {		/* If overriding negotiations */
5248 		spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
5249 	    } else {			         /* otherwise */
5250 		spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
5251 	    }
5252 	    if (spsiz < 10) spsiz = 80;	/* Be defensive... */
5253 	}
5254     }
5255     /* (PWP) save current send packet size for optimal packet size calcs */
5256     spmax = spsiz;			/* Maximum negotiated length */
5257     lastspmax = spsiz;			/* For stats */
5258     if (slostart && spsiz > 499)	/* Slow start length */
5259       spsiz = 244;
5260     debug(F101,"spar slow-start spsiz","",spsiz);
5261     debug(F101,"spar lp spmax","",spmax);
5262     timint = chktimo(timint,timef);	/* Recalculate the packet timeout */
5263 
5264 /* Sliding Windows... */
5265 
5266     if (swcapr) {			/* Only if requested... */
5267         if (biggest > y) {		/* See what other Kermit says */
5268 	    x = xunchar(s[y+1]);
5269 	    debug(F101,"spar window","",x);
5270 	    wslotn = (x > MAXWS) ? MAXWS : x;
5271 /*
5272   wslotn = negotiated size (from other Kermit's S or I packet).
5273   wslotr = requested window size (from this Kermit's SET WINDOW command).
5274 */
5275 	    if (wslotn > wslotr)	/* Use the smaller of the two */
5276 	      wslotn = wslotr;
5277 	    if (wslotn < 1)		/* Watch out for bad negotiation */
5278 	      wslotn = 1;
5279 	    if (wslotn > 1) {
5280 		swcapu = 1;		/* We do windows... */
5281 		if (wslotn > maxtry)	/* Retry limit must be greater */
5282 		  maxtry = wslotn + 1;	/* than window size. */
5283 	    }
5284 	    debug(F101,"spar window after adjustment","",x);
5285 	} else {			/* No window size specified. */
5286 	    wslotn = 1;			/* We don't do windows... */
5287 	    debug(F101,"spar window","",x);
5288 	    swcapu = 0;
5289 	    debug(F101,"spar no windows","",wslotn);
5290 	}
5291     }
5292 
5293 /* Now recalculate packet length based on number of windows.   */
5294 /* The nogotiated number of window slots will be allocated,    */
5295 /* and the maximum packet length will be reduced if necessary, */
5296 /* so that a windowful of packets can fit in the big buffer.   */
5297 
5298     if (wslotn > 1) {			/* Shrink to fit... */
5299 	x = adjpkl(spmax,wslotn,bigsbsiz);
5300 	if (x < spmax) {
5301 	    spmax = x;
5302 	    lastspmax = spsiz;
5303 	    if (slostart && spsiz > 499) spsiz = 244; /* Slow start again */
5304 	    debug(F101,"spar sending, redefine spmax","",spmax);
5305 	}
5306     }
5307 #ifdef WHATAMI
5308     debug(F101,"spar biggest","",biggest);
5309     if (biggest > y+7) {		/* Get WHATAMI info if any */
5310 	whatru = xunchar(s[y+8]);
5311 	debug(F101,"spar whatru","",whatru);
5312     }
5313     if (whatru & WMI_FLAG) {		/* Only valid if this bit is set */
5314 #ifdef STREAMING
5315 	if (whatru & WMI_STREAM) {
5316 	    if (streamrq == SET_ON ||
5317 		(streamrq == SET_AUTO &&
5318 		 (reliable == SET_ON || (reliable == SET_AUTO && !local)
5319 #ifdef TN_COMPORT
5320                   && !istncomport()
5321 #endif /* TN_COMPORT */
5322 #ifdef IKSD
5323                    || inserver
5324 #endif /* IKSD */
5325                    ))) {
5326 		streamok = 1;		/* Streaming negotiated */
5327 		slostart = 0;		/* Undo slow-start machinations */
5328 		spsiz = lastspmax;
5329 	    }
5330 	}
5331 	streamed = streamok;
5332 	debug(F101,"spar streamok","",streamok);
5333 	debug(F101,"spar clearrq","",clearrq);
5334 	if (clearrq == SET_ON ||
5335              (clearrq == SET_AUTO &&
5336                ((network && nettype == NET_TCPB
5337 #ifdef RLOGCODE
5338                 && ttnproto != NP_RLOGIN/* Rlogin is not clear */
5339                 && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN)
5340 #endif /* RLOGCODE */
5341 #ifdef TN_COMPORT
5342                 && !istncomport()
5343 #endif /* TN_COMPORT */
5344                   )
5345 #ifdef SSHBUILTIN
5346                  || (network && nettype == NET_SSH)
5347 #endif /* SSHBUILTIN */
5348 #ifdef IKSD
5349                  || inserver
5350 #endif /* IKSD */
5351                  )))
5352           urclear = (whatru & WMI_CLEAR);
5353 	debug(F101,"spar urclear","",urclear);
5354 #ifdef CK_SPEED
5355 	if (urclear)
5356 	  setprefix(PX_NON);
5357 #endif /* CK_SPEED */
5358 	cleared = urclear;
5359 #endif /* STREAMING */
5360     }
5361 #endif /* WHATAMI */
5362 
5363     if (biggest > y+8) {		/* Get WHOAREYOU info if any */
5364 	int x, z;
5365 	x = xunchar(s[y+9]);		/* Length of it */
5366 	z = y;
5367 	y += (9 + x);
5368 	debug(F101,"spar sysindex x","",x);
5369 	debug(F101,"spar sysindex y","",y);
5370 	debug(F101,"spar sysindex biggest","",biggest);
5371 
5372 	if (x > 0 && x < 16 && biggest >= y) {
5373 	    strncpy(whoareu,(char *)s+z+10,x); /* Other Kermit's system ID */
5374 	    debug(F111,"spar whoareyou",whoareu,whoareu[0]);
5375 	    if (whoareu[0]) {		/* Got one? */
5376 		sysindex = getsysix((char *)whoareu);
5377 		debug(F101,"spar sysindex",whoareu,sysindex);
5378 	    }
5379 	}
5380     } else
5381       goto xspar;
5382 
5383 #ifdef WHATAMI
5384     y++;				/* Advance pointer */
5385     if (biggest >= y) {
5386 	whatru2 = xunchar(s[y]);	/* Next field is WHATAMI2 */
5387 	debug(F101,"spar whatru2","",whatru2);
5388 	if (whatru2 & WMI2_FLAG) {	/* Valid only if this bit is set */
5389 	    if (server) {		/* Server obeys client's xfer mode */
5390 		xfermode = (whatru2 & WMI2_XMODE) ? XMODE_M : XMODE_A;
5391 		debug(F101,"spar whatru2 xfermode","",xfermode);
5392 	    }
5393 	    if (whatru2 & WMI2_RECU) {	/* RECURSIVE transfer */
5394 		if (fnrpath == PATH_AUTO) { /* If REC PATH AUTO */
5395 		    fnrpath = PATH_REL;	/* Set it to RELATIVE */
5396 		    autopath = 1;	/* and remember we did this */
5397 		}
5398 	    }
5399 	}
5400     }
5401 #endif /* WHATAMI */
5402 
5403   xspar:
5404     if (sysindex > -1) {
5405 	char * p;
5406 	p = sysidlist[sysindex].sid_name;
5407 	tlog(F110,"Remote system type: ",p,0L);
5408 	if (sysindex > 0) {		/* If partnet's system type known */
5409 	    whoarewe();			/* see if we are a match. */
5410 #ifdef CK_SPEED
5411 /* Never unprefix XON and XOFF when sending to VMS */
5412 	    debug(F111,"proto whoareu",whoareu,sysindex);
5413 	    if (!strcmp((char *)whoareu,"D7")) {
5414 		debug(F111,"proto special VMS prefixing","",0);
5415 		ctlp[XON] = ctlp[XOFF] = 1;
5416 		ctlp[XON+128] = ctlp[XOFF+128] = 1;
5417 		ctlp[3] = 1;		/* Ctrl-C might be dangerous too */
5418 		ctlp[14] = ctlp[15] = 1; /* And SO/SI */
5419 		ctlp[24] = ctlp[25] = 1; /* And ^X/^Y */
5420 		ctlp[141] = 1;		/* And CR+128 */
5421 	    }
5422 #endif /* CK_SPEED */
5423 	}
5424     }
5425 
5426 /* Record parameters in debug log */
5427 #ifdef DEBUG
5428     if (deblog) sdebu(biggest);
5429 #endif /* DEBUG */
5430     numerrs = 0;			/* Start counting errors here. */
5431     return(0);
5432 }
5433 
5434 /*  G N F I L E  --  Get name of next file to send  */
5435 /*
5436   Expects global sndsrc to be:
5437    -9: if we are generating a file internally for calibration.
5438    -1: next filename to be obtained by calling znext().
5439     0: no next file name
5440     1: (or greater) next filename to be obtained from **cmlist,
5441        or if addlist != 0, from the "filehead" linked list,
5442        or if filefile pointer not null from that file (which is already open).
5443   Returns:
5444     1, with name of next file in filnam.
5445     0, no more files, with filnam set to empty string.
5446    -1, file not found
5447    -2, file is not readable (but then we just skip to the next one if any)
5448    -3, read access denied
5449    -4, cancelled
5450    -5, too many files match wildcard
5451    -6, no files selected
5452   NOTE:
5453     If gnfile() returns 0, then the global variable gnferror should be checked
5454     to find out the most recent gnfile() error, and use that instead of the
5455     return code (for reasons too hard to explain).
5456 */
5457 int
gnfile()5458 gnfile() {
5459     int i = 0, x = 0;
5460     CK_OFF_T filesize = 0;
5461     int dodirstoo = 0;
5462     int retcode = 0;
5463 
5464     char fullname[CKMAXPATH+1];
5465 
5466     dodirstoo = ((what & (W_FTP|W_SEND)) == (W_FTP|W_SEND)) && recursive;
5467 
5468     debug(F101,"gnfile sndsrc","",sndsrc);
5469     debug(F101,"gnfile filcnt","",filcnt);
5470     debug(F101,"gnfile what","",what);
5471     debug(F101,"gnfile recursive","",recursive);
5472     debug(F101,"gnfile dodirstoo","",dodirstoo);
5473     gnferror = 0;
5474     fsize = (CK_OFF_T)-1;		/* Initialize file size */
5475     fullname[0] = NUL;
5476 
5477 #ifdef VMS
5478     /*
5479       In VMS, zopeni() sets binary 0/1 automatically from the file
5480       attributes.  Don't undo it here.
5481     */
5482     debug(F101,"gnfile VMS binary","",binary);
5483 #else  /* VMS */
5484     if (!(what & W_REMO) && (xfermode == XMODE_A)
5485 #ifndef NOMSEND
5486 	&& !addlist
5487 #endif /* NOMSEND */
5488 	) {
5489 	extern int stdinf;
5490 	if (!stdinf)			/* Not if sending from stdin */
5491 #ifdef WHATAMI
5492 	  /* We don't do this in server mode because it undoes WHATAMI */
5493 	  if (!server || (server && ((whatru & WMI_FLAG) == 0)))
5494 #endif /* WHATAMI */
5495 	    binary = gnf_binary;	/* Restore prevailing transfer mode */
5496 	debug(F101,"gnfile binary = gnf_binary","",gnf_binary);
5497     }
5498 #endif	/* VMS */
5499 
5500 #ifdef PIPESEND
5501     debug(F101,"gnfile pipesend","",pipesend);
5502     if (pipesend) {			/* First one */
5503 	if (filcnt == 0) {
5504 	    ckstrncpy(filnam,cmarg,CKMAXPATH+1);
5505 	    return(1);
5506 	} else {			/* There's only one... */
5507 	    *filnam = NUL;
5508 	    pipesend = 0;
5509 	    return(0);
5510 	}
5511     }
5512 #endif /* PIPESEND */
5513 
5514 #ifdef CALIBRATE
5515     if (sndsrc == -9) {
5516 	debug(F100,"gnfile calibrate","",0);
5517 	ckstrncpy(filnam,"CALIBRATION",CKMAXPATH);
5518 	nfils = 0;
5519 	cal_j = 0;
5520 	fsize = calibrate;
5521 	sndsrc = 0;			/* For next time */
5522 	nfils = 0;
5523 	return(1);
5524     }
5525 #endif /* CALIBRATE */
5526 
5527 #ifndef NOSPL
5528     if (sndarray) {			/* Sending from an array */
5529 	extern char sndxnam[];		/* Pseudo filename */
5530 	debug(F100,"gnfile array","",0);
5531 	nfils = 0;
5532 	fsize = (CK_OFF_T)-1;		/* Size unknown */
5533 	sndsrc = 0;
5534 	ckstrncpy(filnam,sndxnam,CKMAXPATH);
5535 	return(1);
5536     }
5537 #endif /* NOSPL */
5538 
5539     if (sndsrc == 0) {			/* It's not really a file */
5540 	if (nfils > 0) {		/* It's a pipe, or stdin */
5541 	    ckstrncpy(filnam,*cmlist,CKMAXPATH+1); /* Copy its "name" */
5542 	    nfils = 0;			/* There is no next file */
5543 	    return(1);			/* OK this time */
5544 	} else return(0);		/* but not next time */
5545     }
5546 
5547 /* If file group interruption (C-Z) occurred, fail.  */
5548 
5549     if (czseen) {
5550 	tlog(F100,"Transaction cancelled","",0L);
5551         debug(F100,"gnfile czseen","",0);
5552 	return(-4);
5553     }
5554 
5555 /* Loop through file list till we find a readable, sendable file */
5556 
5557     filesize = (CK_OFF_T)-1;		/* Loop exit (file size) variable */
5558     while (filesize < 0) {		/* Keep trying till we get one... */
5559 	retcode = 0;
5560 	if (sndsrc > 0) {		/* File list in cmlist or file */
5561 	    if (filefile) {		/* Reading list from file... */
5562 		if (zsinl(ZMFILE,filnam,CKMAXPATH) < 0) { /* Read a line */
5563 		    zclose(ZMFILE);	                  /* Failed */
5564 		    debug(F110,"gnfile filefile EOF",filefile,0);
5565 		    makestr(&filefile,NULL);
5566 		    return(0);
5567 		}
5568 		debug(F110,"gnfile filefile filnam",filnam,0);
5569 	    }
5570 	    debug(F101,"gnfile nfils","",nfils);
5571 	    if (nfils-- > 0 || filefile) { /* Still some left? */
5572 #ifndef NOMSEND
5573 		if (addlist) {
5574 		    if (filenext && filenext->fl_name) {
5575 			ckstrncpy(filnam,filenext->fl_name,CKMAXPATH+1);
5576 			cmarg2 =
5577 			  filenext->fl_alias ?
5578 			    filenext->fl_alias :
5579 			      "";
5580 			binary = filenext->fl_mode;
5581 		    } else {
5582 			printf("?Internal error expanding ADD list\n");
5583 			return(-5);
5584 		    }
5585 		    filenext = filenext->fl_next;
5586 		    debug(F111,"gnfile addlist filnam",filnam,nfils);
5587 		} else if (sndsrc > 0 && !filefile) {
5588 #endif /* NOMSEND */
5589 		    ckstrncpy(filnam,*cmlist++,CKMAXPATH+1);
5590 		    debug(F111,"gnfile cmlist filnam",filnam,nfils);
5591 #ifndef NOMSEND
5592 		}
5593 #endif /* NOMSEND */
5594 		i = 0;
5595 #ifndef NOSERVER
5596 		debug(F101,"gnfile ngetpath","",ngetpath);
5597 #endif /* NOSERVER */
5598 nextinpath:
5599 #ifndef NOSERVER
5600 		fromgetpath = 0;
5601 		if (server && !isabsolute(filnam) && (ngetpath > i)) {
5602 		    ckstrncpy(fullname,getpath[i],CKMAXPATH+1);
5603 		    ckstrncat(fullname,filnam,CKMAXPATH);
5604 		    debug(F111,"gnfile getpath",fullname,i);
5605 		    fromgetpath = 1;
5606 		    i++;
5607 		} else {
5608 		    i = ngetpath + 1;
5609 #else
5610 		    i = 1;		/* ? */
5611 #endif /* NOSERVER */
5612 		    ckstrncpy(fullname,filnam,CKMAXPATH+1);
5613 		    debug(F110,"gnfile absolute",fullname,0);
5614 #ifndef NOSERVER
5615 		}
5616 #endif /* NOSERVER */
5617 		if (iswild(fullname)
5618 #ifdef RECURSIVE
5619 		    || recursive > 0 || !strcmp(fullname,".")
5620 #endif /* RECURSIVE */
5621 		    ) {	/* It looks wild... */
5622 		    /* First check if a file with this name exists */
5623 		    debug(F110,"gnfile wild",fullname,0);
5624 		    if (zchki(fullname) >= 0) {
5625 			/*
5626 			   Here we have a file whose name actually
5627 			   contains wildcard characters.
5628 			*/
5629 			goto gotnam;
5630 		    }
5631 #ifdef COMMENT
5632 		    nzxopts = ZX_FILONLY; /* (was 0: 25 Jul 2001 fdc) */
5633 #else
5634 		    nzxopts = recursive ? 0 : ZX_FILONLY; /* 30 Jul 2001 */
5635 #endif /* COMMENT */
5636 		    if (nolinks) nzxopts |= ZX_NOLINKS;	/* (26 Jul 2001 fdc) */
5637 #ifdef UNIXOROSK
5638 		    if (matchdot) nzxopts |= ZX_MATCHDOT;
5639 #endif /* UNIXOROSK */
5640 		    if (recursive) nzxopts |= ZX_RECURSE;
5641 		    x = nzxpand(fullname,nzxopts); /* Expand wildcards */
5642 		    debug(F101,"gnfile nzxpand","",x);
5643 		    if (x == 1) {
5644 			int xx;
5645 			xx = znext(fullname);
5646 			debug(F111,"gnfile znext A",fullname,xx);
5647 			goto gotnam;
5648 		    }
5649 		    if (x == 0) {	/* None match */
5650 #ifndef NOSERVER
5651 			if (server && ngetpath > i)
5652 			  goto nextinpath;
5653 #endif /* NOSERVER */
5654 			retcode = -1;
5655 			debug(F101,"gnfile gnferror A","",gnferror);
5656 			gnferror = -1;
5657 			continue;
5658 		    }
5659 		    if (x < 0) {	/* Too many to expand */
5660 			debug(F101,"gnfile gnferror B","",gnferror);
5661 			gnferror = -5;
5662 			return(-5);
5663 		    }
5664 		    sndsrc = -1;	/* Change send-source to znext() */
5665 		}
5666 	    } else {			/* We're out of files. */
5667 		debug(F111,"gnfile done",ckitoa(gnferror),nfils);
5668 		*filnam = '\0';
5669 		return(0);
5670 	    }
5671 	}
5672 
5673 /* Otherwise, step to next element of internal wildcard expansion list. */
5674 
5675 	if (sndsrc == -1) {
5676 	    int xx = 0;
5677 	    while (1) {
5678 		debug(F111,"gnfile znext X",filnam,xx);
5679 		xx = znext(filnam);
5680 		debug(F111,"gnfile znext B",filnam,xx);
5681 		if (!filnam[0])
5682 		  break;
5683 		if (dodirstoo) {
5684 		    debug(F111,"gnfile FTP MPUT /RECURSIVE",filnam,xx);
5685 		    break;
5686 		}
5687 		if (!isdir(filnam))
5688 		  break;
5689 	    }
5690 	    debug(F111,"gnfile znext C",filnam,x);
5691 	    if (!filnam[0]) {		/* If no more, */
5692 		sndsrc = 1;		/* go back to previous list */
5693 		debug(F101,"gnfile setting sndsrc back","",sndsrc);
5694 		continue;
5695 	    } else
5696 	      ckstrncpy(fullname,filnam,CKMAXPATH+1);
5697 	}
5698 
5699 /* Get here with a filename. */
5700 
5701 gotnam:
5702 	debug(F110,"gnfile fullname",fullname,0);
5703 	if (fullname[0]) {
5704 #ifdef DTILDE
5705 	    char * dirp = "";
5706 	    if (fullname[0] == '~') {
5707 		dirp = tilde_expand((char *)fullname);
5708 		if (*dirp) ckstrncpy(fullname,dirp,CKMAXPATH+1);
5709 	    }
5710 #endif /* DTILDE */
5711 	    filesize = zchki(fullname);	/* Check if file readable */
5712 	    debug(F111,"gnfile zchki",fullname,filesize);
5713 	    retcode = filesize;		/* Possible return code */
5714 	    if (filesize == (CK_OFF_T)-2 && dodirstoo) {
5715 		filesize = 0;
5716 	    }
5717 	    if (filesize < 0) {
5718 		gnferror = (int)filesize;
5719 		debug(F101,"gnfile gnferror C","",gnferror);
5720 	    }
5721 	    if (filesize == (CK_OFF_T)-1) { /* If not found */
5722 		debug(F100,"gnfile -1","",0);
5723 #ifndef NOSERVER
5724 		if (server && ngetpath > i)
5725 		  goto nextinpath;
5726 #endif /* NOSERVER */
5727 		debug(F110,"gnfile skipping:",fullname,0);
5728 		tlog(F110,fullname,": open failure - skipped",0);
5729 		xxscreen(SCR_FN,0,0l,fullname);
5730 		xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname);
5731 #ifdef TLOG
5732 		if (tralog && !tlogfmt)
5733 		  doxlog(what,fullname,fsize,binary,1,"Skipped");
5734 #endif /* TLOG */
5735 		continue;
5736 	    } else if (filesize < 0) {
5737 		if (filesize == (CK_OFF_T)-3) { /* Exists but not readable */
5738 		    debug(F100,"gnfile -3","",0);
5739 		    filrej++;		/* Count this one as not sent */
5740 		    tlog(F110,"Read access denied",fullname,0); /* Log this */
5741 		    xxscreen(SCR_FN,0,0l,fullname);
5742 		    xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname); /* Display it */
5743 #ifdef TLOG
5744 		    if (tralog && !tlogfmt)
5745 		      doxlog(what,fullname,fsize,binary,1,"Skipped");
5746 #endif /* TLOG */
5747 		}
5748 		continue;
5749 	    } else {
5750 		int xx;
5751 		fsize = filesize;
5752 /* +++ */
5753     debug(F111,"gnfile sndsmaller",ckfstoa(sndsmaller),sndsmaller);
5754     debug(F111,"gnfile sndlarger",ckfstoa(sndlarger),sndlarger);
5755     debug(F111,"gnfile (CK_OFF_T)-1",ckfstoa((CK_OFF_T)-1),(CK_OFF_T)-1);
5756 
5757 		xx = fileselect(fullname,
5758 				sndafter, sndbefore,
5759 				sndnafter,sndnbefore,
5760 				sndsmaller,sndlarger,
5761 				skipbup,
5762 				NSNDEXCEPT,sndexcept);
5763 		debug(F111,"gnfile fileselect",fullname,xx);
5764 		if (!xx) {
5765 		    filesize = (CK_OFF_T)-1;
5766 		    gnferror = -6;
5767 		    debug(F101,"gnfile gnferror D","",gnferror);
5768 		    continue;
5769 		}
5770 		ckstrncpy(filnam,fullname,CKMAXPATH+1);
5771 		return(1);
5772 	    }
5773 #ifdef COMMENT
5774 	/* This can't be right! */
5775 	} else {			/* sndsrc is 0... */
5776 	    if (!fileselect(fullname,
5777 			    sndafter, sndbefore,
5778 			    sndnafter,sndnbefore,
5779 			    sndsmaller,sndlarger,
5780 			    skipbup,
5781 			    NSNDEXCEPT,sndexcept)) {
5782 		gnferror = -6;
5783 		debug(F111,"gnfile fileselect",fullname,gnferror);
5784 		filesize = (CK_OFF_T)-1;
5785 		continue;
5786 	    }
5787 	    ckstrncpy(filnam,fullname,CKMAXPATH+1);
5788 	    return(1);
5789 #endif /* COMMENT */
5790 	}
5791     }
5792     debug(F101,"gnfile result","",retcode);
5793     *filnam = '\0';
5794     return(0);
5795 }
5796 
5797 /*
5798   The following bunch of routines feed internally generated data to the server
5799   to send to the client in response to REMOTE commands like DIRECTORY, DELETE,
5800   and so on.  We have to write these lines in the format appropriate to our
5801   platform, so they can be converted to generic (CRLF) text format by the
5802   packetizer.
5803 */
5804 #ifdef UNIX
5805 char * endline = "\12";
5806 #else
5807 #ifdef datageneral
5808 char * endline = "\12";
5809 #else
5810 #ifdef MAC
5811 char * endline = "\15";
5812 #else
5813 #ifdef OSK
5814 char * endline = "\15";
5815 #else
5816 char * endline = "\15\12";
5817 #endif /* OSK */
5818 #endif /* MAC */
5819 #endif /* datageneral */
5820 #endif /* UNIX */
5821 
5822 #ifdef MAC
5823 #define FNCBUFL 256
5824 #else
5825 #ifdef CKSYMLINK
5826 #define FNCBUFL (CKMAXPATH + CKMAXPATH + 64)
5827 #else
5828 #define FNCBUFL (CKMAXPATH + 64)
5829 #endif /* CKSYMLINK */
5830 #endif /* MAC */
5831 
5832 /* NB: The minimum FNCBUFL is 255 */
5833 
5834 static CHAR funcbuf[FNCBUFL];
5835 static int  funcnxt =  0;
5836 static int  funclen =  0;
5837 static int  nxpnd   = -1;
5838 static long ndirs   =  0;
5839 static long nfiles  =  0;
5840 static CK_OFF_T nbytes  =  0;
5841 
5842 int
sndstring(p)5843 sndstring(p) char * p; {
5844 #ifndef NOSERVER
5845     nfils = 0;				/* No files, no lists. */
5846     xflg = 1;				/* Flag we must send X packet. */
5847     ckstrncpy(cmdstr,versio,CMDSTRL);	/* Data for X packet. */
5848     first = 1;				/* Init getchx lookahead */
5849     memstr = 1;				/* Just set the flag. */
5850     memptr = p;				/* And the pointer. */
5851     binary = XYFT_T;			/* Text mode for this. */
5852     return(sinit());
5853 #else
5854     return(0);
5855 #endif /* NOSERVER */
5856 }
5857 
5858 /*  S N D H L P  --  Routine to send builtin help  */
5859 
5860 static int srvhlpnum = 0;
5861 
5862 #ifdef IKSD
5863 static char *nmx[] =  { "Disabled", "Disabled", "Enabled", "Enabled" };
5864 #endif /* IKSD */
5865 
5866 static char *
xnm(x)5867 xnm(x) int x; {
5868 #ifdef IKSD
5869     if (inserver)
5870       return(nmx[x]);
5871     else
5872 #endif /* IKSD */
5873       return(nm[x]);
5874 }
5875 
5876 static int
nxthlp(void)5877 nxthlp(
5878 #ifdef CK_ANSIC
5879        void
5880 #endif /* CK_ANSIC */
5881        ) {
5882     int x = 0;
5883     extern int
5884       en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai,
5885       en_pri, en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who,
5886       /* en_ret, */ en_mkd, en_rmd, en_asg, en_que, en_xit, x_login, x_logged,
5887       xfinish;
5888     extern char * ckxsys;
5889 
5890     if (funcnxt < funclen)
5891       return (funcbuf[funcnxt++]);
5892 
5893     switch (srvhlpnum++) {
5894       case 0:
5895 	x = ckstrncpy((char *)funcbuf,
5896 		      "Client Command     Status        Description\n",
5897 		      FNCBUFL
5898 		      );
5899 	if (x_login && !x_logged) {
5900 	    x += ckstrncat((char *)funcbuf,
5901 			   " REMOTE LOGIN       required\n",
5902 			   FNCBUFL
5903 			   );
5904 	}
5905 	if (FNCBUFL - x > 74)
5906 	sprintf((char *)(funcbuf+x)," GET                %-14s%s\n",
5907 		xnm(en_get),
5908 		"Transfer file(s) from server to client."
5909 		);
5910 	break;
5911 
5912 /* NOTE: The minimum funcbuf[] size is 255; all of the following are safe. */
5913 
5914       case 1:
5915 	sprintf((char *)funcbuf," SEND               %-14s%s\n",
5916 		xnm(en_sen),
5917 		"Transfer file(s) from client to server."
5918 		);
5919 	break;
5920 
5921       case 2:
5922 	sprintf((char *)funcbuf," MAIL               %-14s%s\n",
5923 		xnm(inserver ? 0 : en_mai),
5924 		"Send file(s) as e-mail."
5925 		);
5926 	break;
5927 
5928       case 3:
5929 #ifndef NOSPL
5930 	sprintf((char *)funcbuf," REMOTE ASSIGN      %-14s%s\n",
5931 		xnm(en_asg),
5932 		"Assign value to server variable or macro."
5933 		);
5934 #else
5935 	sprintf((char *)funcbuf," REMOTE ASSIGN      not configured\n");
5936 #endif /* NOSPL */
5937 
5938 	break;
5939       case 4:
5940 	sprintf((char *)funcbuf," REMOTE CD          %-14s%s\n",
5941 		xnm(en_cwd),
5942 		"Change server's directory."
5943 		);
5944 	break;
5945 
5946       case 5:
5947 #ifdef ZCOPY
5948 	sprintf((char *)funcbuf," REMOTE COPY        %-14s%s\n",
5949 		xnm(en_cpy),
5950 		"Copy a file on the server."
5951 		);
5952 #else
5953 	sprintf((char *)funcbuf," REMOTE COPY        not configured\n");
5954 #endif /* ZCOPY */
5955 
5956 	break;
5957       case 6:
5958 	sprintf((char *)funcbuf," REMOTE DELETE      %-14s%s\n",
5959 		xnm(en_del),
5960 		"Delete a file on the server."
5961 		);
5962 	break;
5963 
5964       case 7:
5965 	sprintf((char *)funcbuf," REMOTE DIRECTORY   %-14s%s\n",
5966 		xnm(en_dir),
5967 		"List files on the server."
5968 		);
5969 	break;
5970 
5971       case 8:
5972 	sprintf((char *)funcbuf," REMOTE EXIT        %-14s%s\n",
5973 		xnm(en_xit),
5974 		"Exit from Kermit server program."
5975 		);
5976 	break;
5977 
5978       case 9:
5979 	sprintf((char *)funcbuf," REMOTE HOST        %-14s%s\n",
5980 		xnm(inserver ? 0 : en_hos),
5981 #ifdef datageneral
5982 		"Execute a CLI command on the server."
5983 #else
5984 #ifdef VMS
5985 		"Execute a DCL command on the server."
5986 #else
5987 		"Execute a shell command on the server."
5988 #endif /* VMS */
5989 #endif /* datageneral */
5990 		);
5991 	break;
5992 
5993       case 10:
5994 	sprintf((char *)funcbuf," REMOTE PRINT       %-14s%s\n",
5995 		xnm(inserver ? 0 : en_pri),
5996 		"Send a file to the server for printing."
5997 		);
5998 	break;
5999 
6000       case 11:
6001 #ifndef NOSPL
6002 	sprintf((char *)funcbuf," REMOTE QUERY       %-14s%s\n",
6003 		xnm(en_que),
6004 		"Get value of server variable or macro."
6005 		);
6006 
6007 #else
6008 	sprintf((char *)funcbuf," REMOTE QUERY       not configured\n");
6009 #endif /* NOSPL */
6010 
6011 	break;
6012       case 12:
6013 	sprintf((char *)funcbuf," REMOTE MKDIR       %-14s%s\n",
6014 		xnm(en_mkd),
6015 		"Create a directory on the server."
6016 		);
6017 	break;
6018 
6019       case 13:
6020 	sprintf((char *)funcbuf," REMOTE RMDIR       %-14s%s\n",
6021 		xnm(en_rmd),
6022 		"Remove a directory on the server."
6023 		);
6024 	break;
6025 
6026       case 14:
6027 	sprintf((char *)funcbuf," REMOTE RENAME      %-14s%s\n",
6028 		xnm(en_ren),
6029 		"Rename a file on the server."
6030 		);
6031 	break;
6032 
6033       case 15:
6034 	sprintf((char *)funcbuf," REMOTE SET         %-14s%s\n",
6035 		xnm(en_set),
6036 		"Set a parameter on the server"
6037 		);
6038 	break;
6039 
6040       case 16:
6041 	sprintf((char *)funcbuf," REMOTE SPACE       %-14s%s\n",
6042 		xnm(en_spa),
6043 		"Inquire about disk space on the server."
6044 		);
6045 	break;
6046 
6047       case 17:
6048 	sprintf((char *)funcbuf," REMOTE TYPE        %-14s%s\n",
6049 		xnm(en_typ),
6050 		"Display a server file on your screen."
6051 		);
6052 	break;
6053 
6054       case 18:
6055 	sprintf((char *)funcbuf," REMOTE WHO         %-14s%s\n",
6056 		xnm(inserver ? 0 : en_who),
6057 		"List who is logged in to the server."
6058 		);
6059 	break;
6060 
6061       case 19:
6062 	sprintf((char *)funcbuf," FINISH             %-14s%s\n",
6063 		xnm(en_fin),
6064 		xfinish ?
6065 		"Exit from Kermit server program." :
6066 		"Return the server to its command prompt."
6067 		);
6068 	break;
6069 
6070       case 20:
6071 	sprintf((char *)funcbuf," BYE                %-14s%s\n\n",
6072 		xnm(en_bye),
6073 		"Log the server out and disconnect."
6074 		);
6075 	break;
6076 
6077       default:
6078 	return(-1);
6079     }
6080     funcnxt = 0;
6081     funclen = strlen((char *)funcbuf);
6082     return(funcbuf[funcnxt++]);
6083 }
6084 
6085 int
sndhlp()6086 sndhlp() {
6087 #ifndef NOSERVER
6088     extern char * ckxsys;
6089 
6090     first = 1;				/* Init getchx lookahead */
6091     nfils = 0;				/* No files, no lists. */
6092     xflg = 1;				/* Flag we must send X packet. */
6093     ckstrncpy(cmdstr,"REMOTE HELP",CMDSTRL); /* Data for X packet. */
6094     sprintf((char *)funcbuf, "C-Kermit %s,%s\n\n", versio, ckxsys);
6095     funclen = strlen((char *)funcbuf);
6096 #ifdef IKSD
6097     if (inserver) {
6098 	sprintf((char *)(funcbuf+funclen),
6099 		"Internet Kermit Service (EXPERIMENTAL)\n\n");
6100 	funclen = strlen((char *)funcbuf);
6101     }
6102 #endif /* IKSD */
6103     funcnxt = 0;
6104     funcptr = nxthlp;
6105     funcstr = 1;
6106     srvhlpnum = 0;
6107     binary = XYFT_T;			/* Text mode for this. */
6108     return(sinit());
6109 #else
6110     return(0);
6111 #endif /* NOSERVER */
6112 }
6113 
6114 /*
6115    Returns the next available character,
6116   -1 if no more data.
6117 */
6118 static int
nxttype(void)6119 nxttype(
6120 #ifdef CK_ANSIC
6121        void
6122 #endif /* CK_ANSIC */
6123 	) {
6124     int c;
6125     if (zchin(ZIFILE,&c) < 0) {
6126         zclose(ZIFILE);
6127         return(-1);
6128     } else {
6129 	return((unsigned)c);
6130     }
6131 }
6132 
6133 /*  S N D T Y P -- TYPE a file to remote client */
6134 
6135 int
sndtype(file)6136 sndtype(file) char * file; {
6137 #ifndef NOSERVER
6138     char name[CKMAXPATH+1];
6139 
6140 #ifdef OS2
6141     char * p = NULL;
6142 
6143     if (*file) {
6144         ckstrncpy(name, file, CKMAXPATH+1);
6145         /* change / to \. */
6146         p = name;
6147         while (*p) {			/* Change them back to \ */
6148             if (*p == '/') *p = '\\';
6149             p++;
6150         }
6151     } else
6152       return(0);
6153 #else
6154     ckstrncpy(name, file, CKMAXPATH+1);
6155 #endif /* OS2 */
6156 
6157     funcnxt = 0;
6158     funclen = strlen((char *)funcbuf);
6159     if (zchki(name) == -2) {
6160         /* Found a directory */
6161         return(0);
6162     }
6163     if (!zopeni(ZIFILE,name))
6164       return(0);
6165 
6166     nfils = 0;				/* No files, no lists. */
6167     xflg = 1;				/* Flag we must send X packet. */
6168     ckstrncpy(cmdstr,"type",CMDSTRL);	/* Data for X packet. */
6169     first = 1;				/* Init getchx lookahead */
6170     funcstr = 1;			/* Just set the flag. */
6171     funcptr = nxttype;			/* And the pointer. */
6172     binary = XYFT_T;			/* Text mode for this */
6173     return(sinit());
6174 #else
6175     return(0);
6176 #endif /* NOSERVER */
6177 }
6178 
6179 /*
6180    N X T D I R  --  Provide data for senddir()
6181 
6182    Returns the next available character or -1 if no more data.
6183 */
6184 #ifndef NOICP
6185 /* Directory listing parameters set by the user interface, if any. */
6186 extern int dir_head, dir_dots, dir_back;
6187 #endif /* NOICP */
6188 static int sd_hdg, sd_bkp, sd_dot;	/* Local listing parameters */
6189 
6190 static int
nxtdir(void)6191 nxtdir(
6192 #ifdef CK_ANSIC
6193        void
6194 #endif /* CK_ANSIC */
6195        ) {
6196     char name[CKMAXPATH+1], dbuf[24], *p = NULL;
6197     char *dstr = NULL, * lnk = "";
6198     CHAR c, * linebuf = funcbuf;
6199 #ifdef OSK
6200     /* Work around bugs in OSK compiler */
6201     char *dirtag = "directories";
6202     char *filetag = "files";
6203     char *bytetag = "bytes";
6204 #endif /* OSK */
6205     CK_OFF_T len = 0;
6206     int x, itsadir = 0, gotone = 0;
6207 
6208 #ifdef DEBUG
6209     if (deblog) {
6210 	debug(F101,"nxtdir funcnxt","",funcnxt);
6211 	debug(F101,"nxtdir funclen","",funclen);
6212 	debug(F110,"nxtdir funcbuf",funcbuf+funcnxt,0);
6213     }
6214 #endif /* DEBUG */
6215     if (funcnxt < funclen) {		/* Return next character from buffer */
6216 	c = funcbuf[funcnxt++];
6217 	debug(F000,"nxtdir return 1","",(unsigned)(c & 0xff));
6218 	return((unsigned)(c & 0xff));
6219     }
6220     while (nxpnd > 0) {			/* Buffer needs refill */
6221         nxpnd--;
6222 	znext(name);			/* Get next filename */
6223         if (!name[0]) {			/* None left - done */
6224             nxpnd = 0;
6225             return(nxtdir());
6226         }
6227 	if (sd_bkp) {			/* Showing backup files? */
6228 	    gotone = 1;			/* Yes, no need to check. */
6229 	    break;
6230 	}
6231 	x = ckmatch(			/* No - see if this is one */
6232 #ifdef CKREGEX
6233 		    "*.~[0-9]*~"	/* Not perfect but close enough. */
6234 #else
6235 		    "*.~*~"		/* Less close. */
6236 #endif /* CKREGEX */
6237 		    ,name,filecase,1);
6238 	debug(F111,"nxtdir ckmatch",name,x);
6239 	if (x) {
6240 	    continue;			/* It's a backup file - skip it */
6241 	} else {
6242 	    gotone = 1;			/* It's not, break from loop. */
6243 	    break;
6244 	}
6245     }
6246     if (gotone) {
6247         len = zgetfs(name);		/* Get file size */
6248 	debug(F111,"nxtdir zgetfs",name,len);
6249 #ifdef VMSORUNIX
6250 	itsadir = zgfs_dir;		/* See if it's a directory */
6251 #else
6252 	itsadir = (len == -2 || isdir(name));
6253 #endif /* VMSORUNIX */
6254         dstr = zfcdat(name);
6255 	debug(F111,"nxtdir zcfdat",dstr,0);
6256 	if (!dstr)
6257 	  dstr = "0000-00-00 00:00:00";
6258 	if (!*dstr) {
6259 	  dstr = "0000-00-00 00:00:00";
6260 	} else {
6261 	    dbuf[0] = dstr[0];
6262 	    dbuf[1] = dstr[1];
6263 	    dbuf[2] = dstr[2];
6264 	    dbuf[3] = dstr[3];
6265 	    dbuf[4] = '-';
6266 	    dbuf[5] = dstr[4];
6267 	    dbuf[6] = dstr[5];
6268 	    dbuf[7] = '-';
6269 	    dbuf[8] = dstr[6];
6270 	    dbuf[9] = dstr[7];
6271 	    strcpy(dbuf+10,dstr+8);
6272 	    dstr = dbuf;
6273 	}
6274 #ifdef CK_PERMS
6275 #ifdef VMSORUNIX
6276 	p = ziperm(name);		/* Get permissions */
6277 #else
6278 	p = zgperm(name);
6279 #endif /* VMSORUNIX */
6280 #else
6281 	p = NULL;
6282 #endif /* CK_PERMS */
6283 	debug(F110,"domydir perms",p,0);
6284 
6285 #ifdef VMS
6286 	/* Make name relative */
6287 	ckstrncpy(name,zrelname(name,zgtdir()),CKMAXPATH+1);
6288 #endif /* VMS */
6289 
6290 	if (itsadir) {
6291 	    ndirs++;
6292 	} else {
6293 	    nfiles++;
6294 	    nbytes += len;
6295 	}
6296 	lnk = "";
6297 #ifdef UNIX
6298 #ifdef CKSYMLINK
6299 	if (zgfs_link) {
6300 	    extern char linkname[];
6301 	    lnk = linkname;
6302 	}
6303 	debug(F111,"nxtdir linkname",lnk,zgfs_link);
6304 #endif /* CKSYMLINK */
6305 #endif /* UNIX */
6306 
6307 /*
6308   The following sprintf's are safe; linebuf is a pointer to funcbuf,
6309   which is 64 bytes larger than CKMAXPATH (or double CKMAXPATH when
6310   symlinks are possible).  64 allows for the fixed-field portions of
6311   the file listing line: permissions, size, and date.  CKMAXPATH allows
6312   for the longest possible pathname.
6313 */
6314 	if (itsadir && len < 0) {	/* Directory */
6315 #ifdef VMS
6316 	    sprintf((char *)linebuf,
6317 		    "%-22s%-10s  %s  %s\n",p,"<DIR>",dstr,name);
6318 #else
6319 	    if (p)
6320 	      sprintf((char *)linebuf,
6321 		      "%10s%-10s  %s  %s\n",p,"<DIR>",dstr,name);
6322 	    else
6323 	      sprintf((char *)linebuf,
6324 		      "%-10s  %s  %s\n", "<DIR>", dstr, name);
6325 #endif /* VMS */
6326 	} else {			/* Regular file */
6327 #ifdef VMS
6328 	    sprintf((char *)linebuf,
6329 		    "%-22s%10s  %s  %s\n", p, ckfstoa(len), dstr, name);
6330 #else
6331 	    if (p)
6332 	      sprintf((char *)linebuf,
6333 		      "%10s%10s  %s  %s%s%s\n",
6334 		      p, ckfstoa(len), dstr, name,
6335 		      *lnk ? " -> " : "",
6336 		      lnk
6337 		      );
6338 	    else
6339 	      sprintf((char *)linebuf,
6340 		      "%10s  %s  %s%s%s\n",
6341 		      ckfstoa(len), dstr, name,
6342 		      *lnk ? " -> " : "",
6343 		      lnk
6344 		      );
6345 #endif /* VMS */
6346 	}
6347         funcnxt = 0;
6348         funclen = strlen((char *)funcbuf);
6349     } else if (sd_hdg && nxpnd == 0) {	/* Done, send summary */
6350 	char *blankline = "";		/* At beginning of summary */
6351 /*
6352   The idea is to prevent (a) unnecessary multiple blanklines, and (b)
6353   prompt-stomping.  Preventing (b) is practically impossible, because it
6354   depends on the client so for now always include that final CRLF.
6355 */
6356 	if (!ndirs || !nbytes || !nfiles)
6357 	  blankline = endline;
6358 #ifdef OSK
6359 /* Workaround bugs in OS-9 compiler... */
6360         if (ndirs == 1)
6361            dirtag = "directory";
6362         if (nfiles == 1)
6363            filetag = "file";
6364         if (nbytes == (CK_OFF_T)1)
6365            bytetag = "byte";
6366         sprintf((char *)funcbuf,
6367 		"%sSummary: %ld %s, %ld %s, %s %s%s",
6368 		blankline,
6369 		ndirs,
6370 		dirtag,
6371 		nfiles,
6372 		filetag,
6373 		ckfstoa(nbytes),
6374 		bytetag,
6375 		endline);
6376 #else
6377         sprintf((char *)funcbuf,
6378 		"%sSummary: %ld director%s, %ld file%s, %s byte%s%s",
6379 		blankline,
6380 		ndirs,
6381 		(ndirs == 1) ? "y" : "ies",
6382 		nfiles,
6383 		(nfiles == 1) ? "" : "s",
6384 		ckfstoa(nbytes),
6385 		(nbytes == (CK_OFF_T)1) ? "" : "s",
6386 		endline
6387 		);
6388 #endif /* OSK */
6389         nxpnd--;
6390         funcnxt = 0;
6391         funclen = strlen((char *)funcbuf);
6392     } else {
6393         funcbuf[0] = '\0';
6394         funcnxt = 0;
6395         funclen = 0;
6396     }
6397     debug(F101,"nxtdir funclen","",funclen);
6398 
6399     if (funcnxt < funclen) {		/* If we have data to send... */
6400 	c = funcbuf[funcnxt++];
6401 	debug(F000,"nxtdir return 2","",(unsigned)(c & 0xff));
6402 	return((unsigned)(c & 0xff));
6403     } else
6404       return(-1);			/* Nothing left, done. */
6405 }
6406 
6407 /*  S N D D I R -- send directory listing  */
6408 
6409 int
snddir(spec)6410 snddir(spec) char * spec; {
6411 #ifndef NOSERVER
6412     char * p = NULL, name[CKMAXPATH+1];
6413     int t = 0, rc = 0;
6414     char fnbuf[CKMAXPATH+1];
6415 
6416     debug(F111,"snddir matchdot",spec,matchdot);
6417 
6418 #ifndef NOICP
6419     debug(F111,"snddir dir_dots",spec,dir_dots);
6420     sd_hdg = dir_head > 0;		/* Import listing parameters if any */
6421     sd_bkp = dir_back > 0;
6422     if (dir_dots > -1)
6423       sd_dot = dir_dots;
6424     else
6425       sd_dot = matchdot;
6426 #else
6427     sd_hdg = 1;				/* Or use hardwired defaults */
6428     sd_bkp = 1;
6429     sd_dot = matchdot;
6430 #endif /* NOICP */
6431 
6432     if (!spec) spec = "";
6433     debug(F111,"snddir sd_dot",spec,sd_dot);
6434     if (*spec) {
6435 #ifdef COMMENT
6436 	zfnqfp(spec,CKMAXPATH,name);
6437 	debug(F110,"snddir zfnqfp",name,0);
6438 #else
6439 	ckstrncpy(name,spec,CKMAXPATH+1);
6440 	debug(F110,"snddir name",name,0);
6441 #endif /* COMMENT */
6442     } else {
6443 #ifdef OS2
6444 	strcpy(name, "*");
6445 #else
6446 #ifdef UNIXOROSK
6447 	strcpy(name, "./*");
6448 #else
6449 #ifdef VMS
6450 	strcpy(name, "*.*");
6451 #else
6452 #ifdef datageneral
6453 	strcpy(name, "+");
6454 #else
6455 	debug(F101,"snddir quit (no filespec)","",0);
6456 	return(0);
6457 #endif /* datageneral */
6458 #endif /* VMS */
6459 #endif /* UNIX */
6460 #endif /* OS2 */
6461     }
6462     debug(F110,"snddir name 1",name,0);
6463     ndirs = 0L;
6464     nfiles = 0L;
6465     nbytes = (CK_OFF_T)0;
6466 
6467     if (zfnqfp(name,CKMAXPATH,fnbuf))
6468 
6469     debug(F110,"snddir name 2",name,0);
6470     p = name + strlen(name);		/* Move it to end of list */
6471 
6472     /* sprintf safe because funcbuf size >= max path len + 64 */
6473 
6474     if (sd_hdg) {
6475 	sprintf((char *)funcbuf,"Listing files: %s%s%s",fnbuf,endline,endline);
6476 	funcnxt = 0;
6477 	funclen = strlen((char *)funcbuf);
6478     }
6479     diractive = 1;
6480 
6481 #ifdef OS2
6482     if (zchki(name) == -2) {		/* Found a directory */
6483         p--;
6484         if (*p == '\\' || *p == '/')
6485           ckstrncat(name, "*", CKMAXPATH);
6486         else if (*p == ':')
6487           ckstrncat(name, ".", CKMAXPATH);
6488         else
6489           ckstrncat(name, "\\*", CKMAXPATH);
6490 	debug(F110,"snddir directory",name,0);
6491     }
6492 #else
6493     if (!iswild(name) && isdir(name)) {
6494 	char * s = name;
6495 	p--;
6496 #ifdef UNIXOROSK
6497 	if (*p == '/')			/* So append wildcard to it */
6498 	  ckstrncat(s, "*", CKMAXPATH);
6499 	else
6500 	  ckstrncat(s, "/*", CKMAXPATH);
6501 #else
6502 #ifdef VMS
6503 	if (*p == ']' || *p == '>' || *p == ':')
6504 	  ckstrncat(s, "*.*", CKMAXPATH);
6505 #else
6506 #ifdef datageneral
6507 	if (*p == ':')
6508 	  ckstrncat(s, "+", CKMAXPATH);
6509 	else
6510 	  ckstrncat(s, ":+", CKMAXPATH);
6511 #else
6512 #ifdef VOS
6513 	if (*p == '>')
6514 	  ckstrncat(s, "*", CKMAXPATH);
6515 	else
6516 	  ckstrncat(s, ">*", CKMAXPATH);
6517 #endif /* VOS */
6518 #endif /* datageneral */
6519 #endif /* VMS */
6520 #endif /* UNIXOROSK */
6521 	debug(F110,"snddir directory",name,0);
6522     }
6523 #endif /* OS2 */
6524 
6525     nzxopts = 0;
6526 #ifdef UNIX
6527     {
6528 	extern char ** mtchs;
6529 	debug(F111,"snddir sd_dot",spec,sd_dot);
6530 	if (sd_dot > 0)
6531 	  nzxopts |= ZX_MATCHDOT;
6532 	if (recursive)
6533 	  nzxopts |= ZX_RECURSE;
6534 	debug(F111,"snddir nzxopts",spec,nzxopts);
6535 	nxpnd = nzxpand(name,nzxopts);	/* Get the array of names */
6536 	sh_sort(mtchs,NULL,nxpnd,0,0,1); /* Sort the array */
6537     }
6538 #else
6539     if (recursive) nzxopts |= ZX_RECURSE;
6540     nxpnd = nzxpand(name,nzxopts);
6541 #endif /* UNIX */
6542 
6543     debug(F101,"snddir nzxpand nxpnd","",nxpnd);
6544     if (nxpnd < 1)
6545       return(-1);
6546     nfils = 0;				/* No files, no lists. */
6547     xflg = 1;				/* Flag we must send X packet. */
6548     if ((int)strlen(name) < CMDSTRL - 11) /* Data for X packet. */
6549       sprintf(cmdstr,"DIRECTORY %s",name); /* safe */
6550     else
6551       ckstrncpy(cmdstr,"DIRECTORY",CMDSTRL);
6552     first = 1;				/* Init getchx lookahead */
6553     funcstr = 1;			/* Just set the flag. */
6554     funcptr = nxtdir;			/* And the pointer. */
6555     binary = XYFT_T;			/* Text mode for this */
6556     rc = sinit();			/* 26 Aug 2005 */
6557     debug(F111,"snddir","sinit()",rc);
6558     return(rc);
6559 #else
6560     return(0);
6561 #endif /* NOSERVER */
6562 }
6563 
6564 /*  N X T D E L -- provide data for delete   */
6565 
6566 /*  Returns the next available character or -1 if no more data  */
6567 
6568 static int
nxtdel(void)6569 nxtdel(
6570 #ifdef CK_ANSIC
6571        void
6572 #endif /* CK_ANSIC */
6573        ) {
6574     char name[257], *p = NULL;
6575     int len = 0;
6576 
6577     if (funcnxt < funclen)
6578       return ((unsigned)funcbuf[funcnxt++]);
6579 
6580     if (nxpnd > 0) {
6581         nxpnd--;
6582 	znext(name);
6583         if (!name[0]) {
6584             nxpnd = 0;
6585             return(nxtdel());
6586         }
6587         len = zchki(name);
6588 
6589         /* Find just the name of the file */
6590 
6591         for (p = name + strlen(name); p != name && *p != '/' ; p--) ;
6592         if (*p == '/') p++;
6593 
6594 	/* sprintf's safe because size of funcbuf >= 64 + maxpathlen */
6595 
6596         if (len > -1L) {
6597 	    if (zdelet(name)) {
6598 		sprintf((char *)funcbuf," %10s: %s%s","skipping",p,endline);
6599 	    } else {
6600 		nfiles++;
6601 		nbytes += len;
6602 		sprintf((char *)funcbuf," %10s: %s%s","deleted",p,endline);
6603 	    }
6604         } else
6605 	  sprintf((char *)funcbuf," directory: %s%s", p, endline);
6606         funcnxt = 0;
6607         funclen = strlen((char *)funcbuf);
6608     } else
6609 
6610     /* If done processing the expanded entries send a summary statement */
6611 
6612       if (nxpnd == 0) {
6613 	  sprintf((char *)funcbuf,
6614 		  "%s%ld file%s deleted, %s byte%s freed%s",
6615 		  endline,
6616 		  nfiles,
6617 		  (nfiles == 1) ? "" : "s",
6618 		  ckfstoa(nbytes),
6619 		  (nbytes == (CK_OFF_T)1) ? "" : "s",
6620 		  endline
6621 		  );
6622 	  nxpnd--;
6623 	  funcnxt = 0;
6624 	  funclen = strlen((char *)funcbuf);
6625       } else {
6626 	  funcbuf[0] = '\0';
6627 	  funcnxt = 0;
6628 	  funclen = 0;
6629       }
6630 
6631     /* If we have data to send */
6632 
6633     if (funcnxt < funclen)
6634       return ((unsigned)funcbuf[funcnxt++]); /* Return a character */
6635     else
6636       return(-1);			/* No more input */
6637 }
6638 
6639 /*  S N D D E L  --  Send delete message  */
6640 
6641 int
snddel(spec)6642 snddel(spec) char * spec; {
6643 #ifndef NOSERVER
6644     char name[CKMAXPATH+1];
6645 #ifdef OS2
6646     char * p = NULL;
6647 #endif /* #ifdef OS2 */
6648 
6649     if (!*spec)
6650       return(0);
6651 
6652     ckstrncpy(name, spec, CKMAXPATH+1);
6653 
6654 #ifdef OS2
6655     /* change / to \. */
6656     p = name;
6657     while (*p) {			/* Change them back to \ */
6658         if (*p == '/') *p = '\\';
6659         p++;
6660     }
6661 #endif /* OS2 */
6662 
6663     nfiles = 0L;
6664     nbytes = (CK_OFF_T)0;
6665     sprintf((char *)funcbuf,"Deleting \"%s\"%s",name,endline);
6666     funcnxt = 0;
6667     funclen = strlen((char *)funcbuf);
6668 
6669     nzxopts = ZX_FILONLY;		/* Files only */
6670 #ifdef UNIXOROSK
6671     if (matchdot) nzxopts |= ZX_MATCHDOT;
6672 #endif /* UNIXOROSK */
6673 #ifdef COMMENT
6674     /* Recursive deleting not supported yet */
6675     if (recursive) nzxopts |= ZX_RECURSE;
6676 #endif /* COMMENT */
6677     nxpnd = nzxpand(name,nzxopts);
6678     if (nxpnd < 1)
6679       return(-1);
6680     nfils = 0;				/* No files, no lists. */
6681     xflg = 1;				/* Flag we must send X packet. */
6682     ckstrncpy(cmdstr,"REMOTE DELETE",CMDSTRL); /* Data for X packet. */
6683     first = 1;				/* Init getchx lookahead */
6684     funcstr = 1;			/* Just set the flag. */
6685     funcptr = nxtdel;			/* And the pointer. */
6686     binary = XYFT_T;			/* Use text mode for this, */
6687     return(sinit());
6688 #else
6689     return(0);
6690 #endif /* NOSERVER */
6691 }
6692 
6693 #ifdef OS2
6694 /*  S N D S P A C E -- send disk space message  */
6695 int
sndspace(drive)6696 sndspace(drive) int drive; {
6697 #ifndef NOSERVER
6698     static char spctext[64];
6699     unsigned long space;
6700 
6701     if (drive) {
6702 	space = zdskspace(drive - 'A' + 1);
6703 	if (space > 0 && space < 1024)
6704 	  sprintf(spctext,
6705 		  " Drive %c: unknown%s",
6706 		  drive,
6707 		  endline
6708 		  );
6709 	else
6710 	  sprintf(spctext,
6711 		  " Drive %c: %ldK free%s",
6712 		  drive,
6713 		  space / 1024L,
6714 		  endline
6715 		  );
6716     } else {
6717 	space = zdskspace(0);
6718 	if (space > 0 && space < 1024)
6719 	  sprintf(spctext, " Free space: unknown%s", endline);
6720 	else
6721 	  sprintf(spctext, " Free space: %ldK%s", space / 1024L, endline);
6722     }
6723     nfils = 0;				/* No files, no lists. */
6724     xflg = 1;				/* Flag we must send X packet. */
6725     ckstrncpy(cmdstr,"free space",CMDSTRL); /* Data for X packet. */
6726     first = 1;				/* Init getchx lookahead */
6727     memstr = 1;				/* Just set the flag. */
6728     memptr = spctext;			/* And the pointer. */
6729     binary = XYFT_T;			/* Text mode for this. */
6730     return(sinit());
6731 #else
6732     return(0);
6733 #endif /* NOSERVER */
6734 }
6735 
6736 /*  S N D W H O -- send who message  */
6737 int
sndwho(who)6738 sndwho(who) char * who; {
6739 #ifndef NOSERVER
6740     nfils = 0;				/* No files, no lists. */
6741     xflg = 1;				/* Flag we must send X packet. */
6742     ckstrncpy(cmdstr,"who",CMDSTRL);	/* Data for X packet. */
6743     first = 1;				/* Init getchx lookahead */
6744     memstr = 1;				/* Just set the flag. */
6745 #ifdef NT
6746     memptr = "\15\12K95 SERVER\15\12";	/* And the pointer. */
6747 #else
6748     memptr = "\15\12K/2 SERVER\15\12";
6749 #endif /* NT */
6750     binary = XYFT_T;			/* Use text mode */
6751     return(sinit());
6752 #else
6753     return(0);
6754 #endif /* NOSERVER */
6755 }
6756 #endif /* OS2 */
6757 
6758 /*  C W D  --  Change server's working directory  */
6759 
6760 /*
6761  String passed has first byte as length of directory name, rest of string
6762  is name.  Returns:
6763   0 on failure.
6764   1 on success after sending short-form response (ACK with name).
6765   2 on success if a CD Message file is to be sent.
6766 */
6767 int
cwd(vdir)6768 cwd(vdir) char *vdir; {
6769     char *cdd, *dirp;
6770 
6771     vdir[xunchar(*vdir) + 1] = '\0';	/* Terminate string with a null */
6772     dirp = vdir+1;
6773     tlog(F110,"Directory requested: ",dirp,0L);
6774     if (zchdir(dirp)) {			/* Try to change */
6775 	cdd = zgtdir();			/* Get new working directory. */
6776 	debug(F110,"cwd",cdd,0);
6777 	if (srvcdmsg) {			/* Send orientation file? */
6778 	    int i;
6779 	    for (i = 0; i < 8; i++) {
6780 		if (zchki(cdmsgfile[i]) > -1) {
6781 		    xxscreen(SCR_CD,0,0l,cdd);
6782 		    tlog(F110,"Changed directory to",cdd,0L);
6783 		    return(2);
6784 		}
6785 	    }
6786 	}
6787 	encstr((CHAR *)cdd);		/* Send short-form reply */
6788 	ack1(data);			/* containing directory name. */
6789 	xxscreen(SCR_CD,0,0l,cdd);
6790 	tlog(F110,"Changed directory to",cdd,0L);
6791 	return(1);
6792     } else {
6793 	debug(F110,"cwd failed",dirp,0);
6794 	tlog(F110,"Failed to change directory to",dirp,0L);
6795 	return(0);
6796     }
6797 }
6798 
6799 
6800 /*  S Y S C M D  --  Do a system command  */
6801 
6802 /*  Command string is formed by concatenating the two arguments.  */
6803 
6804 int
syscmd(prefix,suffix)6805 syscmd(prefix,suffix) char *prefix, *suffix; {
6806     extern int i_isopen;
6807 #ifndef NOPUSH
6808     char *cp;
6809 
6810     i_isopen = 0;
6811     if (!prefix)
6812       return(0);
6813     if (!*prefix)
6814       return(0);
6815     for (cp = cmdstr; *prefix != '\0'; (*cp++ = *prefix++));
6816     while ((*cp++ = *suffix++))
6817 #ifdef OS2
6818         /* This takes away more than we gain in convenience
6819         if (*(cp-1) == '/') *(cp-1) = '\\' */
6820 #endif /* OS2 */
6821       ;					/* Copy suffix */
6822 
6823     debug(F110,"syscmd",cmdstr,0);
6824 
6825     if (zxcmd(ZIFILE,cmdstr) > 0) {
6826     	debug(F110,"syscmd zxcmd ok",cmdstr,0);
6827 	nfils = sndsrc = 0;		/* Flag that input is from stdin */
6828     	xflg = hcflg = 1;		/* And special flags for pipe */
6829 	binary = XYFT_T;		/* Go to text mode */
6830 	i_isopen = 1;
6831     	return (sinit());		/* Send S packet */
6832     } else {
6833     	debug(F100,"syscmd zxcmd failed",cmdstr,0);
6834 	i_isopen = 0;
6835     	return(0);
6836     }
6837 #else
6838     debug(F100,"syscmd zxcmd NOPUSH",cmdstr,0);
6839     i_isopen = 0;
6840     return(0);
6841 #endif /* NOPUSH */
6842 }
6843 
6844 /*  R E M S E T  --  Remote Set  */
6845 /*  Called by server to set variables as commanded in REMOTE SET packets.  */
6846 /*  Returns 1 on success, 0 on failure.  */
6847 
6848 int
remset(s)6849 remset(s) char *s; {
6850     extern int c_save, en_del;
6851     int len, i, x, y;
6852     char *p;
6853 
6854     len = xunchar(*s++);		/* Length of first field */
6855     p = s + len;			/* Pointer to second length field */
6856     *p++ = '\0';			/* Zero out second length field */
6857     x = atoi(s);			/* Value of first field */
6858     debug(F111,"remset",s,x);
6859     debug(F110,"remset",p,0);
6860     switch (x) {			/* Do the right thing */
6861       case 132:				/* Attributes (all, in) */
6862 	atcapr = atoi(p);
6863 	return(1);
6864       case 133:				/* File length attributes */
6865       case 233:				/* IN/OUT combined */
6866       case 148:				/* Both kinds of lengths */
6867       case 248:
6868 	atleni = atleno = atoi(p);
6869 	return(1);
6870       case 134:				/* File Type (text/binary) */
6871       case 234:
6872 	attypi = attypo = atoi(p);
6873 	return(1);
6874       case 135:				/* File creation date */
6875       case 235:
6876 	atdati = atdato = atoi(p);
6877 	return(1);
6878       case 139:				/* File Blocksize */
6879       case 239:
6880 	atblki = atblko = atoi(p);
6881 	return(1);
6882       case 141:				/* Encoding / Character Set */
6883       case 241:
6884 	atenci = atenco = atoi(p);
6885 	return(1);
6886       case 142:				/* Disposition */
6887       case 242:
6888 	atdisi = atdiso = atoi(p);
6889 	return(1);
6890       case 145:				/* System ID */
6891       case 245:
6892 	atsidi = atsido = atoi(p);
6893 	return(1);
6894       case 147:				/* System-Dependent Info */
6895       case 247:
6896 	atsysi = atsyso = atoi(p);
6897 	return(1);
6898       case 232:				/* Attributes (all, out) */
6899 	atcapr = atoi(p);
6900 	return(1);
6901       case 300:				/* File type (text, binary) */
6902 	binary = atoi(p);
6903 	b_save = binary;
6904 #ifndef NOICP
6905 	g_binary = -1;
6906 #endif /* NOICP */
6907 	return(1);
6908       case 301:				/* File name conversion */
6909 	fncnv = 1 - atoi(p);		/* (oops) */
6910 	f_save = fncnv;
6911 #ifndef NOICP
6912 	g_fncnv = -1;
6913 #endif /* NOICP */
6914 	return(1);
6915       case 302:				/* File name collision */
6916 #ifdef IKSD
6917 #ifdef CK_LOGIN
6918 	if (inserver && isguest)	/* May not be changed by guest */
6919 	  return(0);
6920 #endif /* CK_LOGIN */
6921 #endif /* IKSD */
6922 	x = atoi(p);
6923 	if (!ENABLED(en_del) && (x == XYFX_X || x == XYFX_U))
6924 	  return(0);
6925 	if (x == XYFX_R) ckwarn = 1;	/* Rename */
6926 	if (x == XYFX_X) ckwarn = 0;	/* Replace */
6927 	fncact = x;
6928 	return(1);
6929       case 310:				/* Incomplete File Disposition */
6930 	keep = atoi(p);			/* Keep, Discard, Auto */
6931 	return(1);
6932       case 311:				/* Blocksize */
6933 	fblksiz = atoi(p);
6934 	return(1);
6935       case 312:				/* Record Length */
6936 	frecl = atoi(p);
6937 	return(1);
6938       case 313:				/* Record format */
6939 	frecfm = atoi(p);
6940 	return(1);
6941       case 314:				/* File organization */
6942 	forg = atoi(p);
6943 	return(1);
6944       case 315:				/* File carriage control */
6945 	fcctrl = atoi(p);
6946 	return(1);
6947       case 330:				/* Match dotfiles */
6948 #ifndef NOICP
6949 	dir_dots = -1;			/* This undoes DIR /DOT option */
6950 #endif /* NOICP */
6951 	matchdot = atoi(p);
6952 	return(1);
6953       case 331:				/* Match FIFOs */
6954 	matchfifo = atoi(p);
6955 	return(1);
6956       case 400:				/* Block check */
6957 	y = atoi(p);
6958 	if (y < 5 && y > 0) {
6959 	    bctr = y;
6960 	    c_save = -1;
6961 	    return(1);
6962 	} else if (*p == 'B') {
6963 	    bctr = 4;
6964 	    c_save = -1;
6965 	    return(1);
6966 	} else if (*p == '5') {
6967 	    bctr = 3;
6968 	    c_save = -1;
6969 	    return(1);
6970 	}
6971 	return(0);
6972       case 401:				/* Receive packet-length */
6973 	rpsiz = urpsiz = atoi(p);
6974 	if (urpsiz > MAXRP) urpsiz = MAXRP; /* Max long-packet length */
6975 	if (rpsiz > 94) rpsiz = 94;	    /* Max short-packet length */
6976 	urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
6977 	return(1);
6978       case 402:				/* Receive timeout */
6979 	y = atoi(p);			/* Client is telling us */
6980 	if (y > -1 && y < 999) {	/* the timeout that it wants */
6981 	    pkttim = chktimo(y,timef);	/* us to tell it to use. */
6982 	    return(1);
6983 	} else return(0);
6984       case 403:				/* Retry limit */
6985 	y = atoi(p);
6986 	if (y > -1 && y < 95) {
6987 	    maxtry = y;
6988 	    return(1);
6989 	} else return(0);
6990       case 404:				/* Server timeout */
6991 	y = atoi(p);
6992 	if (y < 0) return(0);
6993 	srvtim = y;
6994 	return(1);
6995 
6996 #ifndef NOCSETS
6997       case 405: {				/* Transfer character set */
6998 	  extern int s_cset, axcset[];
6999 	  int i;
7000 	  for (i = 0; i < ntcsets; i++) {
7001 	      if (!strcmp(tcsinfo[i].designator,p)) break;
7002 	  }
7003 	  debug(F101,"remset tcharset lookup","",i);
7004 	  if (i == ntcsets) return(0);
7005 	  tcharset = tcsinfo[i].code;	/* If known, use it */
7006 	  debug(F101,"remset tcharset","",tcharset);
7007 	  if (s_cset == XMODE_A)
7008 	    if (axcset[tcharset] > -1 && axcset[tcharset] > MAXFCSETS)
7009 	      fcharset = axcset[tcharset]; /* Auto-pick file charset */
7010 	  debug(F101,"remset tcharset fcharset","",fcharset);
7011 	  setxlatype(tcharset,fcharset); /* Set up charset translations */
7012 	  debug(F101,"remset xlatype","",xlatype);
7013 	  debug(F101,"remset tcharset after setxlatype","",tcharset);
7014 	  tcs_save = -1;
7015 	  return(1);
7016       }
7017       case 320: {			/* File character set */
7018 	  extern struct keytab fcstab[];
7019 	  extern int nfilc, s_cset, r_cset;
7020 	  x = lookup(fcstab,p,nfilc,&y);
7021 	  debug(F111,"RSET FILE CHAR name",p,x);
7022 	  if (x < 0)
7023 	    return(0);
7024 	  s_cset = XMODE_M;		/* No automatic charset switching */
7025 	  r_cset = XMODE_M;
7026 	  fcharset = x;			/* Set file charset */
7027 	  setxlatype(tcharset,fcharset); /* and translation type */
7028 	  fcs_save = -1;
7029 	  return(1);
7030       }
7031 #endif /* NOCSETS */
7032 
7033       case 406:				/* Window slots */
7034 	y = atoi(p);
7035 	if (y == 0) y = 1;
7036 	if (y < 1 || y > MAXWS) return(0);
7037 	wslotr = y;
7038 	swcapr = 1;
7039 	urpsiz = adjpkl(urpsiz,wslotr,bigrbsiz);
7040 	return(1);
7041 
7042       case 410:				/* Transfer mode */
7043 	y = atoi(p);			/* 0 = automatic, nonzero = manual */
7044 	if (y != 0) y = 1;
7045 	xfermode = y;
7046 	debug(F101,"REMOTE SET xfermode","",xfermode);
7047 	return(1);
7048 
7049       case 420:				/* SERVER CD-MESSAGE { ON, OFF } */
7050 	y = atoi(p);			/* 0 = automatic, nonzero = manual */
7051 	srvcdmsg = y;
7052 	return(1);
7053 
7054       default:				/* Anything else... */
7055 	return(0);
7056     }
7057 }
7058 
7059 /* Adjust packet length based on number of window slots and buffer size */
7060 
7061 int
adjpkl(pktlen,slots,bufsiz)7062 adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
7063     if (protocol != PROTO_K) return(pktlen);
7064     debug(F101,"adjpkl len","",pktlen);
7065     debug(F101,"adjpkl slots","",slots);
7066     debug(F101,"adjpkl bufsiz","",bufsiz);
7067     if (((pktlen + 6) * slots) > bufsiz)
7068       pktlen = (bufsiz / slots) - 6;
7069     debug(F101,"adjpkl new len","",pktlen);
7070     return(pktlen);
7071 }
7072 
7073 /* Set transfer mode and file naming based on comparison of system types */
7074 
7075 
7076 VOID
whoarewe()7077 whoarewe() {
7078 #ifndef NOICP
7079     extern int g_xfermode;
7080 #endif /* NOICP */
7081 
7082     wearealike = 0;
7083 
7084     debug(F101,"whoarewe xfermode","",xfermode);
7085 #ifndef NOICP
7086     debug(F101,"whoarewe g_xfermode","",g_xfermode);
7087 #endif /* NOICP */
7088     if (whoareu[0]) {			/* If we know partner's system type */
7089 	char * p = (char *)whoareu;
7090 	debug(F110,"whoarewe remote sysid",whoareu,0);
7091 	if (!strcmp(p,cksysid))		/* Other system same as us */
7092 	  wearealike = 1;
7093 
7094 #ifdef UNIX
7095 	else if (!strcmp(p,"L3"))	/* UNIX is sort of like AmigaDOS */
7096 	  wearealike = 1;		/* (same directory separator) */
7097 	else if (!strcmp(p,"N3"))	/* UNIX like Aegis */
7098 	  wearealike = 1;
7099 #else
7100 #ifdef AMIGA
7101 /* Like UNIX, but case distinctions are ignored and can begin with device:. */
7102 	else if (!strcmp(p,"U1"))	/* Amiga is sort of like UNIX */
7103 	  wearealike = 1;
7104 	else if (!strcmp(p,"N3"))	/* Amiga is sort of like Aegis */
7105 	  wearealike = 1;
7106 #else
7107 #ifdef OS2				/* (Includes Windows 95/NT) */
7108 
7109 	/* DOS, GEMDOS, Windows 3.x, Windows 95, Windows NT */
7110 	/* All "the same" for FAT partitions but all bets off otherwise */
7111 	/* so this part needs some refinement ...  */
7112 
7113 	else if (!strcmp(p,"U8"))	/* MS-DOS */
7114 	  wearealike = 1;
7115 	else if (!strcmp(p,"UO"))	/* OS/2 */
7116 	  wearealike = 1;
7117 	else if (!strcmp(p,"UN"))	/* Windows NT or 95 */
7118 	  wearealike = 1;
7119 	else if (!strcmp(p,"K2"))	/* GEMDOS */
7120 	  wearealike = 1;
7121 #else
7122 #ifdef GEMDOS
7123 	else if (!strcmp(p,"U8"))
7124 	  wearealike = 1;
7125 	else if (!strcmp(p,"UO"))
7126 	  wearealike = 1;
7127 	else if (!strcmp(p,"UN"))
7128 	  wearealike = 1;
7129 	else if (!strcmp(p,"K2"))
7130 	  wearealike = 1;
7131 #endif /* GEMDOS */
7132 #endif /* OS2 */
7133 #endif /* AMIGA */
7134 #endif /* UNIX */
7135 
7136 	/* Get here with wearealike == 1 if system types match */
7137 
7138 	debug(F101,"whoarewe wearealike","",wearealike);
7139 	if (!wearealike)		/* Not alike */
7140 	  return;
7141 
7142 	fncnv = XYFN_L;			/* Alike, so literal filenames */
7143 	debug(F101,"whoarewe setting fncnv","",fncnv);
7144 
7145 	if (xfermode == XMODE_A) {	/* Current xfer mode is auto */
7146 #ifdef VMS
7147 	    binary = XYFT_L;		/* For VMS-to-VMS, use labeled */
7148 #else
7149 #ifdef OS2
7150 	    /* OS/2 but not Windows */
7151 	    if (!strcmp(cksysid,"UO") && !strcmp((char *)whoareu,"UO"))
7152 	      binary = XYFT_L;		/* For OS/2-to-OS/2, use labeled */
7153 #else
7154 	    binary = XYFT_B;		/* For all others use binary */
7155 #endif /* OS2 */
7156 #endif /* VMS */
7157 	    gnf_binary = binary;	/* Prevailing type for gnfile() */
7158 	    debug(F101,"whoarewe setting binary","",binary);
7159 	}
7160     }
7161 }
7162 #endif /* NOXFER */
7163