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