Standards-Version: 3.9.6 (no changes)
[ckermit.git] / ckcfns.c
1 char *fnsv = "C-Kermit functions, 9.0.233, 3 Jun 2011";
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, 2011,
14     Trustees of Columbia University in the City of New York.
15     All rights reserved.  See the C-Kermit COPYING.TXT file or the
16     copyright text in the ckcmai.c module for disclaimer and permissions.
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 int inserver;
45
46 extern int nolinks;
47 #ifdef VMSORUNIX
48 extern int zgfs_dir;
49 #ifdef CKSYMLINK
50 extern int zgfs_link;
51 #endif /* CKSYMLINK */
52 #endif /* VMSORUNIX */
53
54 #ifndef NOXFER
55
56 #ifndef NOICP
57 #ifndef NOSPL
58 extern char * clcmds;
59 extern int haveurl;
60 #ifdef CK_APC
61 extern int apcactive, adl_ask;
62 #endif /* CK_APC */
63 #endif /* NOSPL */
64 #endif /* NOICP */
65
66 extern int remfile;
67
68 /* (move these prototypes to the appropriate .h files...) */
69
70 #ifdef COMMENT
71 /* Not used */
72 #ifdef VMS
73 _PROTOTYP( int getvnum, (char *) );
74 #endif /* VMS */
75 #endif /* COMMENT */
76
77 _PROTOTYP( static int bgetpkt, (int) );
78 #ifndef NOCSETS
79 _PROTOTYP( int lookup, (struct keytab[], char *, int, int *) );
80 #endif /* NOCSETS */
81 #ifndef NOSPL
82 _PROTOTYP( int zzstring, (char *, char **, int *) );
83 #endif /* NOSPL */
84
85 #ifdef OS2
86 #include <io.h>
87 #ifdef OS2ONLY
88 #include <os2.h>
89 #endif /* OS2ONLY */
90 #endif /* OS2 */
91
92 #ifdef VMS
93 #include <errno.h>
94 #endif /* VMS */
95
96 /* Externals from ckcmai.c */
97
98 extern int srvcdmsg, srvidl, idletmo;
99 extern char * cdmsgfile[];
100 extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
101  rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr, xitsta;
102 extern int pktnum, bctr, bctu, bctf, bctl, clfils, sbufnum, protocol,
103  size, osize, spktl, nfils, ckwarn, timef, spsizf, sndtyp, rcvtyp, success;
104 extern int parity, turn, network, whatru, fsecs, justone, slostart,
105  ckdelay, displa, mypadn, moving, recursive, nettype;
106 extern long filcnt;
107 extern CK_OFF_T
108  tfc, fsize, sendstart, rs_len, flci, flco, tlci, tlco, calibrate;
109 extern long filrej, oldcps, cps, peakcps, ccu, ccp, filestatus;
110 extern int fblksiz, frecl, frecfm, forg, fcctrl, fdispla, skipbup;
111 extern int spackets, rpackets, timeouts, retrans, crunched, wmax, wcur;
112 extern int hcflg, binary, fncnv, b_save, f_save, server;
113 extern int nakstate, discard, rejection, local, xfermode, interrupted;
114 extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
115 extern int fnspath, fnrpath, eofmethod, diractive, whatru2, wearealike;
116 extern int atcapr, atcapb, atcapu;
117 extern int lpcapr, lpcapb, lpcapu;
118 extern int swcapr, swcapb, swcapu;
119 extern int lscapr, lscapb, lscapu;
120 extern int rscapr, rscapb, rscapu;
121 extern int rptena, rptmin;
122 extern int sseqtbl[];
123 extern int numerrs, nzxopts;
124 extern long rptn;
125 extern int maxtry;
126 extern int stdouf;
127 extern int sendmode;
128 extern int carrier, ttprty;
129 extern int g_fnrpath;
130 #ifdef TCPSOCKET
131 extern int ttnproto;
132 #endif /* TCPSOCKET */
133
134 #ifndef NOSPL
135 extern int sndxin, sndxhi, sndxlo;
136 #endif /* NOSPL */
137
138 extern int g_binary, g_fncnv;
139
140 #ifdef GFTIMER
141 extern CKFLOAT fpfsecs;
142 #endif /* GFTIMER */
143
144 #ifdef OS2
145 extern struct zattr iattr;
146 #endif /* OS2 */
147
148 #ifdef PIPESEND
149 extern int usepipes;
150 #endif /* PIPESEND */
151 extern int pipesend;
152
153 #ifdef STREAMING
154 extern int streamrq, streaming, streamed, streamok;
155 #endif /* STREAMING */
156 extern int reliable, clearrq, cleared, urclear;
157
158 extern int
159   atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
160   attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
161
162 extern int bigsbsiz, bigrbsiz;
163 extern char *versio;
164 extern char *filefile;
165 extern char whoareu[], * cksysid;
166
167 #ifndef NOSERVER
168 extern int ngetpath;
169 extern char * getpath[];
170 extern int fromgetpath;
171 #endif /* NOSERVER */
172
173 #ifdef CK_LOGIN
174 extern int isguest;
175 #endif /* CK_LOGIN */
176
177 extern int srvcmdlen;
178 extern CHAR *srvcmd, * epktmsg;
179 extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, myrptq;
180 extern CHAR *data, padbuf[], stchr, mystch;
181 extern CHAR *srvptr;
182 extern CHAR *rdatap;
183 extern char *cmarg, *cmarg2, **cmlist, filnam[], ofilnam[];
184 extern char *rfspec, *prfspec, *rrfspec, *prrfspec, *sfspec, *psfspec, *rfspec;
185 extern char fspec[];
186 extern int fspeclen;
187
188 #ifndef NOMSEND
189 extern struct filelist * filehead, * filenext;
190 extern int addlist;
191 #endif /* NOMSEND */
192
193 _PROTOTYP( int lslook, (unsigned int b) ); /* Locking Shift Lookahead */
194 _PROTOTYP( int szeof, (CHAR *s) );
195 _PROTOTYP( VOID fnlist, (void) );
196 #endif /* NOXFER */
197
198 extern CK_OFF_T ffc;
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 CK_OFF_T sndsmaller = (CK_OFF_T)-1;
267 CK_OFF_T sndlarger  = (CK_OFF_T)-1;
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 CK_OFF_T 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 = (CK_OFF_T)0;
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 && 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[swapping];
993                 output.bytes[1] = uc.x_char[1-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 && 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) 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 = (CK_OFF_T)0;              /* 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) {
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)                   /* 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 == (CK_OFF_T)2) { /* Second char of file */
2055                         debug(F001,"xgnbyte 1st UCS2","",uc.x_short);
2056                         debug(F111,"xgnbyte fileorder","A",fileorder);
2057                         if (fileorder < 0) /* Byte order of this file */
2058                           fileorder = ucsorder; /* Default is ucsorder */
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)               /* 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 /*
2261   (Many years later...) In testing this code I noticed that TRANSLATE'ing
2262   Russian text from UTF-8 to ISO Latin/Cyrillic produced all question marks.
2263   Rereading the previous paragraph it seems to me we are (I am) overloading
2264   this function with responsibilites, satisfying the needs of file transfer
2265   (local file charset -> transfer charset for outbound packet) and local file
2266   conversion.  In the case of TRANSLATE, we call (xgnbyte(), xpnbyte()) in a
2267   loop, expecting the xgnbyte() will feed UCS2 to xpnbyte().  But the
2268   following code does what xpnbyte() is going to do, returning (in this case)
2269   an ISO Latin/Cyrillic byte stream, which xpnbyte() believes to be UCS2, and
2270   comes up with nonsense.  Not wanting to rip the whole thing apart and start
2271   over, I made the following change that should do no harm, upon observing
2272   that if the input character set is UTF-8 or UCS-2, then when we get here it
2273   has already been converted to UCS2, so if we are not transferring a file, we
2274   don't need to do anything else except put the bytes in the right place to be
2275   returned, which is done further along.
2276 */
2277 #ifdef COMMENT
2278           /* Previous code */
2279           xx = (what & W_SEND) ? xut : xuf;
2280 #else
2281           /* New code 2011-06-03 */
2282           if (what & W_SEND) {
2283               xx = xut;
2284           } else {
2285               if (fcs == FC_UCS2 || fcs == FC_UTF8)
2286                 xx = NULL;
2287               else
2288                 xx = xuf;
2289           }
2290 #endif  /* COMMENT */
2291
2292           eolflag = 0;
2293           if (haveuc) {                 /* File is Unicode */
2294               /* See Unicode TR13, "Converting to Other Character Sets" */
2295               if (uc.x_short == 0x2028 || /* Line Separator? */
2296                   uc.x_short == 0x2029 || /* Paragraph Separator */
2297                   (feol && (uc.x_short == (USHORT)feol))
2298                   ) {
2299                   debug(F001,"xgnbyte uc eol","",uc.x_short);
2300                   rc = 0;
2301                   eolflag = 1;          /* Don't translate and handle later */
2302               }
2303               if (xx && !eolflag) {     /* UCS-to-TCS function (UCS->byte) */
2304                   rc = (*xx)(uc.x_short); /* These can fail... */
2305                   debug(F101,"xgnbyte xx rc","",rc);
2306                   if (rc < 0)           /* If it can't be translated */
2307                     uc.x_short = UNK;   /* Put unknown-character symbol */
2308                   else
2309                     uc.x_short = (unsigned)((unsigned)rc & 0xffff);
2310                   debug(F101,"xgnbyte xx uc","",uc.x_short);
2311               }
2312 #ifdef KANJI
2313               if (tcs == FC_JEUC) {     /* Translating to EUC-JP */
2314                   USHORT sj = 0;
2315                   union ck_short eu;
2316                   debug(F001,"xgnbyte UCS->EUC UCS","",uc.x_short);
2317                   if (!havesj)          /* If we don't already have it */
2318                     sj = un_to_sj(uc.x_short); /* convert to Shift-JIS */
2319                   eu.x_short = sj_to_eu(sj);
2320                   debug(F001,"xgnbyte UCS->EUC EUC","",eu.x_short);
2321                   xlaptr = 0;
2322                   xlacount = 0;
2323                   if (eolflag) {
2324                       if (what & W_SEND) {
2325                           xlabuf[xlacount++] = LF;
2326                           return(CR);
2327                       } else {
2328                           return(feol);
2329                       }
2330                   }
2331                   if (eu.x_char[byteorder]) {   /* Two bytes */
2332                       rc = eu.x_char[byteorder];
2333                       xlabuf[xlacount++] = eu.x_char[1-byteorder];
2334                       debug(F001,"xgnbyte UCS->EUC xlabuf[0]","",xlabuf[0]);
2335                   } else {              /* One byte */
2336                       rc = eu.x_char[1-byteorder];
2337                   }
2338                   debug(F101,"xgnbyte UCS->EUC xlacount","",xlacount);
2339                   debug(F001,"xgnbyte UCS->EUC rc","",rc);
2340                   return(rc);
2341               } else
2342 #endif /* KANJI */
2343               if (tcs != FC_UCS2 && tcs != FC_UTF8) {
2344                   if (uc.x_short & 0xff00) {    /* Decoding error */
2345                       debug(F001,"xgnbyte decoding error","",uc.x_short);
2346                       return(-2);
2347                   } else
2348                     return((unsigned int)(uc.x_short & 0xff));
2349               }
2350               xc = uc.x_short;
2351
2352           } else {                      /* File is not Unicode */
2353               USHORT ch;
2354               /* Translate from single FCS byte to UCS-2 */
2355 /*
2356   This is a bit nonobvious...  The blah_u() (Blah-to-Unicode) routines are
2357   called only with pieces of character sets, in the ISO 2022 sense.  So,
2358   for example, if ch is a Latin-1 character, we call the translation
2359   routine only if it is in the right half; if it's in the left half, it
2360   isn't translated, and in fact will give the wrong result if sent to the
2361   translation function.  That's because those functions were designed for
2362   use with the ISO 2022 G0..G3 sets, not for file transfer.  On the other
2363   hand, if it's a 7-bit character set, we *do* call the translation
2364   function.  (To put it another way, the left half of any 8-bit character
2365   set is ASCII and therefore doesn't need to be translated but 7-bit sets
2366   such as ISO 646 German do need translation).
2367 */
2368               ch = (unsigned)(thischar & 0xff);
2369               if (((fcsinfo[fcs].size > 128) && (ch & 0x80)) ||
2370                   fcsinfo[fcs].size <= 128) {
2371                   if (xfu) {             /* FCS-to-UCS function */
2372                       ch = (*xfu)(ch);
2373                   }
2374               }
2375               xc = ch;
2376           }
2377           /* At this point we have a UCS-2 character in native format */
2378           /* (Big Endian or Little Endian) in xc, which is an unsigned int. */
2379
2380           debug(F001,"xgnbyte xc","",xc);
2381
2382           if (tcs == FC_UTF8) {         /* Now convert to UTF-8 */
2383               USHORT c;                 /* NOTE: this is FC_UTF8 on purpose! */
2384               CHAR * buf = NULL;
2385               int i, k = 0, x;
2386
2387               xlaptr = 0;
2388               if (utferror) {
2389                   xlabuf[k++] = 0xff;
2390                   xlabuf[k++] = 0xbd;
2391               }
2392               if (eolflag) {            /* We detected EOL in source file */
2393                   if (what & W_SEND) {  /* Convert to CRLF */
2394                       xlabuf[k++] = LF;
2395                       xlacount = k;
2396                       return((unsigned int)CR);
2397 #ifdef COMMENT
2398                   } else {              /* Or to local line-end */
2399                       xlacount = k;
2400                       return((unsigned int)feol);
2401 #endif /* COMMENT */
2402                   }
2403               }
2404               c = xc;
2405               if ((x = ucs2_to_utf8(c,&buf)) < 1) {
2406                   debug(F101,"xgnbyte ucs2_to_utf8 error","",c);
2407                   return(-2);
2408               }
2409               debug(F101,"xgnbyte UTF8 buf[0]","",buf[0]);
2410               for (i = 1; i < x; i++) {
2411                   xlabuf[k+i-1] = buf[i];
2412                   debug(F111,"xgnbyte UTF8 xlabuf",ckitoa(i-1),buf[i]);
2413               }
2414               xlaptr = 0;
2415               xlacount = x - 1;
2416               debug(F101,"xgnbyte UTF8 xlacount","",xlacount);
2417               return((unsigned int)buf[0]);
2418           } else {                      /* Or keep it as UCS-2 */
2419               int k = 0;
2420               CHAR c;
2421               xlaptr = 0;
2422               if (utferror) {
2423                   xlabuf[k++] = 0xff;
2424                   xlabuf[k++] = 0xfd;
2425                   debug(F101,"xgnbyte error","",k);
2426               }
2427               if (eolflag) {            /* We detected EOL in source file */
2428                   if (what & W_SEND) {  /* Convert to CRLF */
2429                       xlabuf[k++] = CR;
2430                       xlabuf[k++] = NUL;
2431                       xlabuf[k++] = LF;
2432                       xlacount = k;
2433                       debug(F101,"xgnbyte send CRLF","",k);
2434                       return(0);        /* Return NUL */
2435                   } else {              /* Or to local line-end */
2436 #ifdef COMMENT
2437                       /* This bypasses byte swapping that we might need */
2438                       xlabuf[k++] = (CHAR)feol;
2439                       xlacount = k;
2440                       debug(F101,"xgnbyte send feol","",k);
2441                       return(0);        /* Return NUL */
2442 #else
2443                       xc = (CHAR)feol;
2444 #endif /* COMMENT */
2445                   }
2446               }
2447               /* In which order should we return the bytes? */
2448 #ifdef COMMENT
2449               if ( (what & W_SEND) || (what & W_FTP) || (fileorder == 0)) {
2450 #endif /* COMMENT */
2451                   /* ALWAYS RETURN IN BIG ENDIAN ORDER... 7 Sep 2002   */
2452                   /* xgnbyte() is almost always used to feed xpnbyte() */
2453                   /* which requires bytes in BE order. In cases where  */
2454                   /* xgnbyte is used in isolation, the caller can swap */
2455                   /* bytes itself afterwards. */
2456                   xlabuf[k++] = (xc >> 8) & 0xff; /* Big Endian */
2457                   xlabuf[k++] = xc & 0xff;
2458                   debug(F001,"xgnbyte->UCS2BE",
2459                         ckitox((int)xlabuf[0]),xlabuf[1]);
2460 #ifdef COMMENT
2461               } else {                  /* Little Endian */
2462                   xlabuf[k++] = xc & 0xff;
2463                   xlabuf[k++] = (xc >> 8) & 0xff;
2464                   debug(F001,"xgnbyte->UCS2LE",
2465                         ckitox((int)xlabuf[0]),xlabuf[1]);
2466               }
2467 #endif /* COMMENT */
2468               c = xlabuf[0];
2469               xlaptr = 1;
2470               xlacount = k-1;
2471               debug(F101,"xgnbyte c","",c);
2472               debug(F101,"xgnbyte xlaptr","",xlaptr);
2473               debug(F011,"xgnbyte xlabuf",xlabuf,xlacount);
2474               return((unsigned int)c);
2475           }
2476       }
2477 #endif /* UNICODE */
2478       case XLA_NONE:
2479         return((fn ? (*fn)() : zminchar()));
2480       case XLA_BYTE:                    /* Byte-for-Byte translation */
2481         rt = x;
2482         if (sx)
2483           rt = (*sx)(rt);
2484 #ifdef UNICODE
2485         if (utferror) {
2486             xlaptr = 0;
2487             xlacount = 1;
2488             xlabuf[0] = rt;
2489             return(UNK);
2490         } else
2491 #endif /* UNICODE */
2492           return((unsigned int)rt);
2493
2494 #ifdef KANJI
2495       case XLA_JAPAN:                   /* Come here with Shift-JIS */
2496         if (tcs == FC_JEUC) {           /* It better be... */
2497             xlaptr = 0;
2498             xlacount = 0;
2499             if (!havesj) {
2500                 printf("BAD BAD\n");
2501                 return(-2);
2502             }
2503             if (!haveeu)                /* We might already have EUC too */
2504               eu.x_short = sj_to_eu(sj.x_short);
2505             if (eu.x_char[byteorder]) {
2506                 xlabuf[xlacount++] = eu.x_char[1-byteorder];
2507                 return(eu.x_char[byteorder]);
2508             } else {
2509                 return(eu.x_char[1-byteorder]);
2510             }
2511             break;
2512         }
2513 #endif /* KANJI */
2514
2515       default:
2516         debug(F101,"xgnbyte bad xlatype","",xlatype);
2517         return(-2);
2518     }
2519 #ifdef COMMENT
2520 /*    
2521   If there is a return() statement here, some compilers complain
2522   about "statement not reached".  If there is no return() statement,
2523   other compilers complain that "Non-void function should return a value".
2524   There is no path through this function that falls through to here.
2525 */
2526     debug(F100,"xgnbyte switch failure","",0);
2527     return(-2);
2528 #endif /* COMMENT */
2529 }
2530 #endif /* NOCSETS */
2531
2532 #ifndef NOXFER
2533
2534 /*  G E T P K T  --  Fill a packet data field from the indicated source.  */
2535
2536 /*
2537   Parameters:
2538     bufmax: Maximum length of entire packet.
2539     xlate:  Flag for whether to translate charsets when in text mode.
2540   Returns:  Number of characters written to packet data field, 0 or more,
2541             Or -1 on failure (internal error),
2542             or -3 on timeout (e.g. when reading from a pipe).
2543
2544   This is the full version allowing for parity and text-mode conversions;
2545   i.e. it works in all cases.   Also see bgetpkt(), a special lean/mean/fast
2546   packet encoder that works only for binary-mode no-parity transfers.
2547 */
2548 static int uflag = 0;
2549
2550 int
2551 getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
2552     register CHAR rt = t, rnext = NUL;    /* Register shadows of the globals */
2553     register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
2554     register int x;                     /* Loop index. */
2555     register int a7;                    /* Low 7 bits of character */
2556
2557     CHAR xxls, xxdl, xxrc, xxss, xxcq;  /* Pieces of prefixed sequence */
2558
2559     if (binary) xlate = 0;              /* We don't translate if binary */
2560
2561     if (!data) {
2562         debug(F100,"SERIOUS ERROR: getpkt data == NULL","",0);
2563         return(-1);
2564     }
2565     dp = data;                          /* Point to packet data buffer */
2566     size = 0;                           /* And initialize its size */
2567 /*
2568   Assume bufmax is the receiver's total receive-packet buffer length.
2569   Our whole packet has to fit into it, so we adjust the data field length.
2570   We also decide optimally whether it is better to use a short-format or
2571   long-format packet when we're near the borderline.
2572 */
2573     bufmax = maxdata();                 /* Get maximum data length */
2574
2575     if (first == 1) {                   /* If first character of this file.. */
2576 #ifdef UNICODE
2577         /* Special end-of-line handling for Unicode */
2578         if (tcharset == TC_UCS2 || tcharset == TC_UTF8)
2579           uflag = 1;
2580 #endif /* UNICODE */
2581         debug(F101,"getpkt first uflag","",uflag);
2582         debug(F101,"getpkt first rt","",rt);
2583         if (!memstr && !funcstr)        /* and real file... */
2584           ffc = (CK_OFF_T)0;            /* reset file character counter */
2585 #ifdef COMMENT
2586         /* Moved to below... */
2587         first = 0;                      /* Next character won't be first */
2588 #endif /* COMMENT */
2589         *leftover = '\0';               /* Discard any interrupted leftovers */
2590         nleft = 0;
2591 #ifndef NOCSETS
2592         setxlatype(tcharset,fcharset);  /* Set up charset translations */
2593 #endif /* NOCSETS */
2594
2595         /* Get first character of file into rt, watching out for null file */
2596
2597 #ifdef CALIBRATE
2598         if (calibrate && !memstr) {
2599 #ifdef NORANDOM
2600             x = rt = 53;
2601 #else
2602             x = rt = cal_a[rand() & 0xff];
2603 #endif /* NORANDOM */
2604             first = 0;
2605             ffc++;
2606         } else
2607 #endif /* CALIBRATE */
2608 #ifdef KANJI
2609         if (xlate && tcharset == TC_JEUC) { /* Kanji text */
2610             x = zkanjf();
2611             if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
2612                 first = -1;
2613                 size = 0;
2614                 if (x == -2) {
2615                     debug(F100,"getpkt zkanji: input error","",0);
2616                     cxseen = 1;
2617                 } else debug(F100,"getpkt zkanji: empty string/file","",0);
2618                 return(0);
2619             }
2620             rt = x;
2621             first = 0;
2622             if (!memstr) {
2623                 ffc++;
2624                 if (docrc && (what & W_SEND)) /* Accumulate file crc */
2625                   dofilcrc((int)rt);
2626             }
2627         } else {                        /* Not Kanji text */
2628 #endif /* KANJI */
2629             if (memstr) {               /* Reading data from memory string */
2630                 /* This will not be Unicode */
2631                 if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
2632                     first = -1;
2633                     size = 0;
2634                     debug(F100,"getpkt: empty string","",0);
2635                     return(0);
2636                 }
2637                 first = 0;
2638             } else if (funcstr) {       /* Reading data from a function */
2639                 /* This will not be Unicode */
2640                 if ((x = (*funcptr)()) < 0) { /* End of input  */
2641                     first = -1;
2642                     size = 0;           /* Empty */
2643                     return(0);
2644                 }
2645                 ffc++;                  /* Count a file character */
2646                 rt = (CHAR) x;          /* Convert int to char */
2647                 first = 0;
2648                 debug(F000,"getpkt funcstr","",rt);
2649
2650             } else {                    /* Reading data from a file */
2651 #ifndef NOCSETS
2652                 if (xlate && !binary) { /* Could be Unicode */
2653                     if (xlatype == XLA_UNICODE) {
2654                         /* Get next translated byte */
2655                         x = xgnbyte(cseqtab[tcharset],fcharset,NULL);
2656                         debug(F101,"getpkt xgnbyte","",x);
2657                     } else {            /* Not Unicode */
2658                         x = zminchar(); /* Get next byte, translate below */
2659                         debug(F101,"getpkt zminchar A","",x);
2660                     }
2661                 } else {                /* Just get next byte */
2662 #endif /* NOCSETS */
2663                     x = zminchar();
2664                     debug(F101,"getpkt zminchar B","",x);
2665 #ifndef NOCSETS
2666                 }
2667 #endif /* NOCSETS */
2668                 if (x < 0) {            /* End of file or input error */
2669                     if (x == -3) {      /* Timeout. */
2670                         size = (dp-data);
2671                         debug(F101,"getpkt timeout size","",size);
2672                         return((size == 0) ? x : size);
2673                     }
2674                     first = -1;
2675                     size = 0;
2676                     if (x == -2) {      /* Error */
2677                         debug(F100,"getpkt: input error","",0);
2678                         cxseen = 1;     /* Interrupt the file transfer */
2679                     } else {
2680                         debug(F100,"getpkt empty file","",0);
2681                     }
2682                     return(0);
2683                 }
2684                 first = 0;              /* Next character won't be first */
2685                 rt = (CHAR) x;          /* Convert int to char */
2686 #ifndef NOCSETS
2687                 if (xlatype != XLA_UNICODE || binary) {
2688                     ffc++;
2689                     if (sx)
2690                       rt = (*sx)(rt);
2691                     if (docrc && (what & W_SEND))
2692                       dofilcrc(x);
2693                 }
2694 #endif /* NOCSETS */
2695 #ifdef DEBUG
2696                 if (deblog)
2697                   debug(F101,"getpkt 1st char","",rt);
2698 #endif /* DEBUG */
2699                 if (/* !haveuc && */ docrc && (what & W_SEND)) /* File CRC */
2700                   dofilcrc(x);
2701             }
2702 #ifdef KANJI
2703         }
2704 #endif /* KANJI */
2705         /* PWP: handling of feol is done later (in the while loop)... */
2706
2707     } else if ((first == -1) && (nleft == 0)) { /* EOF from last time */
2708 #ifdef DEBUG
2709         if (deblog) {
2710             debug(F101,"getpkt eof crc16","",crc16);
2711             debug(F101,"getpkt eof ffc","",ffc);
2712         }
2713 #endif /* DEBUG */
2714         return(size = 0);
2715     }
2716 /*
2717   Here we handle characters that were encoded for the last packet but
2718   did not fit, and so were saved in the "leftover" array.
2719 */
2720     debug(F101,"getpkt nleft","",nleft);
2721     if (nleft) {
2722         for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */
2723           *dp++ = *p1++;
2724         *leftover = '\0';                       /* Delete leftovers */
2725         nleft = 0;
2726     }
2727     if (first == -1)                    /* Handle EOF */
2728       return(size = (dp - data));
2729
2730 /* Now fill up the rest of the packet. */
2731
2732     rpt = 0;                            /* Initialize character repeat count */
2733
2734     while (first > -1) {                /* Until EOF... */
2735 #ifdef CALIBRATE
2736         if (calibrate && !memstr) {     /* We generate our own "file" */
2737             if (ffc >= calibrate) {     /* EOF */
2738                 first = -1;
2739                 ffc--;
2740             } else {                    /* Generate next character */
2741                 if (cal_j > CAL_M * ffc)
2742                   cal_j = cal_a[ffc & 0xff];
2743                 x = (unsigned)cal_a[(cal_j & 0xff)];
2744                 if (x == rt) x ^= 2;
2745             }
2746             cal_j += (unsigned int)(ffc + CAL_O);
2747             ffc++;
2748         } else
2749 #endif /* CALIBRATE */
2750 #ifdef KANJI
2751           if (xlate && tcharset == TC_JEUC) {
2752               if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
2753                   first = -1;
2754                   if (x == -2) cxseen = 1;
2755               } else if (!memstr) ffc++;
2756               rnext = (CHAR) (x & fmask);
2757           } else {
2758 #endif /* KANJI */
2759             if (memstr) {               /* Get next char from memory string */
2760                 if ((x = *memptr++) == '\0') /* End of string means EOF */
2761                   first = -1;           /* Flag EOF for next time. */
2762                 rnext = (CHAR) (x & fmask); /* Apply file mask */
2763             } else if (funcstr) {       /* Get next char from function */
2764                 if ((x = (*funcptr)()) < 0) /* End of string means EOF */
2765                   first = -1;           /* Flag EOF for next time. */
2766                 rnext = (CHAR) (x & fmask); /* Apply file mask */
2767             } else {                    /* From file... */
2768 #ifndef NOCSETS
2769                 if (xlate && !binary) { /* Could be Unicode */
2770                     if (xlatype == XLA_UNICODE) {
2771                         /* Get next translated byte */
2772                         x = xgnbyte(cseqtab[tcharset],fcharset,NULL);
2773                     } else {            /* Not Unicode */
2774                         x = zminchar(); /* Get next byte, translate below */
2775                         /* debug(F101,"xgnbyte B zminchar","",x); */
2776                     }
2777                 } else {                /* Just get next byte */
2778 #endif /* NOCSETS */
2779                     x = zminchar();
2780                     /* debug(F101,"xgnbyte C zminchar","",x); */
2781 #ifndef NOCSETS
2782                 }
2783 #endif /* NOCSETS */
2784                 if (x < 0) {            /* Check for EOF */
2785                     if (x == -3) {      /* Timeout reading from pipe */
2786                         t = rt;
2787                         size = (dp-data);
2788                         debug(F101,"getpkt timeout size","",size);
2789                         return((size == 0) ? x : size);
2790                     }
2791                     first = -1;         /* Flag eof for next time. */
2792                     if (x == -2) cxseen = 1; /* If error, cancel this file. */
2793                 }
2794                 rnext = (CHAR) (x & fmask); /* Apply file mask */
2795 #ifndef NOCSETS
2796                 if (xlatype != XLA_UNICODE) {
2797 #endif /* NOCSETS */
2798                     ffc++;
2799 #ifndef NOCSETS
2800                     if (sx)
2801                       rt = (*sx)(rt);
2802 #endif /* NOCSETS */
2803                     if (docrc && (what & W_SEND))
2804                       dofilcrc(x);
2805
2806 #ifndef NOCSETS
2807                 }
2808 #endif /* NOCSETS */
2809             }
2810 #ifdef KANJI
2811         }
2812 #endif /* KANJI */
2813 /*
2814   At this point, the character we just read is in rnext,
2815   and the character we are about to encode into the packet is in rt.
2816 */
2817         odp = dp;                       /* Remember where we started. */
2818         xxls = xxdl = xxrc = xxss = xxcq = NUL; /* Clear these. */
2819 /*
2820   Now encode the character according to the options that are in effect:
2821     ctlp[]: whether this control character needs prefixing.
2822     binary: text or binary mode.
2823     rptflg: repeat counts enabled.
2824     ebqflg: 8th-bit prefixing enabled.
2825     lscapu: locking shifts enabled.
2826 */
2827         if (rptflg) {                   /* Repeat processing is on? */
2828             if (!uflag &&
2829                 /*
2830                  * If the next char is really CRLF, then we cannot
2831                  * be doing a repeat (unless CR,CR,LF which becomes
2832                  * "~ <n-1> CR CR LF", which is OK but not most efficient).
2833                  * I just plain don't worry about this case.  The actual
2834                  * conversion from NL to CRLF is done after the rptflg if...
2835                  */
2836                 (!feol || binary || (feol && (rnext != feol))) &&
2837                 (rt == rnext) && (first == 0)) { /* Got a run... */
2838                 if (++rpt < 94) {       /* Below max, just count */
2839                     continue;           /* go back and get another */
2840                 } else if (rpt == 94) { /* Reached max, must dump */
2841                     xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
2842                     rptn += rpt;        /* Accumulate it for statistics */
2843                     rpt = 0;            /* And reset it */
2844                 }
2845             } else if (rpt > 1) {       /* More than two */
2846                 xxrc = (CHAR) tochar(++rpt); /* and count. */
2847                 rptn += rpt;
2848                 rpt = 0;                /* Reset repeat counter. */
2849             }
2850             /*
2851               If (rpt == 1) we must encode exactly two characters.
2852               This is done later, after the first character is encoded.
2853             */
2854         }
2855         /* If it's the newline character... */
2856         if (!uflag && !binary && feol && (rt == feol)) {
2857             if (lscapu && lsstate) {    /* If SHIFT-STATE is SHIFTED */
2858                 if (ebqflg) {           /* If single shifts enabled, */
2859                     *dp++ = (CHAR) ebq; /* insert a single shift. */
2860                 } else {                /* Otherwise must shift in. */
2861                     *dp++ = myctlq;     /* Insert shift-out code */
2862                     *dp++ = 'O';
2863                     lsstate = 0;        /* Change shift state */
2864                 }
2865             }
2866 #ifdef CK_SPEED
2867             if (ctlp[CR]) {
2868                 *dp++ = myctlq;         /* Insert carriage return directly */
2869                 *dp++ = 'M';
2870                 ccp++;
2871             } else {
2872                 *dp++ = CR;             /* Perhaps literally */
2873                 ccu++;
2874             }
2875 #else /* !CK_SPEED */
2876             *dp++ = myctlq;             /* Insert carriage return directly */
2877             *dp++ = 'M';
2878             ccp++;
2879 #endif /* CK_SPEED */
2880             rt = LF;                    /* Now make next char be linefeed. */
2881         }
2882 /*
2883   Now handle the 8th bit of the file character.  If we have an 8-bit
2884   connection, we preserve the 8th bit.  If we have a 7-bit connection,
2885   we employ either single or locking shifts (if they are enabled).
2886 */
2887         a7 = rt & 0177;                 /* Get low 7 bits of character */
2888         if (rt & 0200) {                /* 8-bit character? */
2889             if (lscapu) {               /* Locking shifts enabled? */
2890                 if (!lsstate) {         /* Not currently shifted? */
2891                     x = lslook(0200);   /* Look ahead */
2892                     if (x != 0 || ebqflg == 0) { /* Locking shift decision */
2893                         xxls = 'N';        /* Need locking shift-out */
2894                         lsstate = 1;       /* and change to shifted state */
2895                     } else if (ebqflg) {   /* Not worth it */
2896                         xxss = (CHAR) ebq; /* Use single shift */
2897                     }
2898                 }
2899                 rt = (CHAR) a7;         /* Replace character by 7-bit value */
2900             } else if (ebqflg) {        /* 8th bit prefixing is on? */
2901                 xxss = (CHAR) ebq;      /* Insert single shift */
2902                 rt = (CHAR) a7;         /* Replace character by 7-bit value */
2903             }
2904 /*
2905   In case we have a 7-bit connection and this is an 8-bit character, AND
2906   neither locking shifts nor single shifts are enabled, then the character's
2907   8th bit will be destroyed in transmission, and a block check error will
2908   occur.
2909 */
2910         } else if (lscapu) {            /* 7-bit character */
2911
2912             if (lsstate) {              /* Comes while shifted out? */
2913                 x = lslook(0);          /* Yes, look ahead */
2914                 if (x || ebqflg == 0) { /* Time to shift in. */
2915                     xxls = 'O';         /* Set shift-in code */
2916                     lsstate = 0;        /* Exit shifted state */
2917                 } else if (ebqflg) {    /* Not worth it, stay shifted out */
2918                     xxss = (CHAR) ebq;  /* Insert single shift */
2919                 }
2920             }
2921         }
2922         /* If data character is significant to locking shift protocol... */
2923         if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
2924           xxdl = 'P';                   /* Insert datalink escape */
2925
2926         if (
2927 #ifdef CK_SPEED
2928             /*
2929               Thwart YET ANOTHER unwanted, unneeded, and unloved sign
2930               extension.  This one was particularly nasty because it prevented
2931               255 (Telnet IAC) from being prefixed on some platforms -- e.g.
2932               VMS with VAX C -- but not others, thus causing file transfers to
2933               fail on Telnet connections by sending bare IACs.  Not to mention
2934               the stray memory reference.  Signed chars are a BAD idea.
2935             */
2936             ctlp[(unsigned)(rt & 0xff)] /* Lop off any "sign" extension */
2937 #else
2938             (a7 < SP) || (a7 == DEL)
2939 #endif /* CK_SPEED */
2940             ) {                         /* Do control prefixing if necessary */
2941             xxcq = myctlq;              /* The prefix */
2942             ccp++;                      /* Count it */
2943             rt = (CHAR) ctl(rt);        /* Uncontrollify the character */
2944         }
2945 #ifdef CK_SPEED
2946         else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
2947           ccu++;
2948 #endif /* CK_SPEED */
2949
2950         if (a7 == myctlq)               /* Always prefix the control prefix */
2951           xxcq = myctlq;
2952
2953         if ((rptflg) && (a7 == rptq))   /* If it's the repeat prefix, */
2954           xxcq = myctlq;                /* prefix it if doing repeat counts */
2955
2956         if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th-bit prefix */
2957           xxcq = myctlq;                /* if doing 8th-bit prefixes */
2958
2959 /* Now construct the entire sequence */
2960
2961         if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
2962         odp2 = dp;                                  /* (Save this place) */
2963         if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
2964         if (xxrc) { *dp++ = (CHAR) rptq; *dp++ = xxrc; } /* Repeat count */
2965         if (xxss) { *dp++ = (CHAR) ebq; }           /* Single shift */
2966         if (xxcq) { *dp++ = myctlq; }               /* Control prefix */
2967         *dp++ = rt;                     /* Finally, the character itself */
2968
2969         if (rpt == 1) {                 /* Exactly two copies? */
2970             rpt = 0;
2971             p2 = dp;                    /* Save place temporarily */
2972             for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
2973               *dp++ = *p1;
2974             if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
2975             if ((p2-data) < bufmax) odp = p2; /* Check packet bounds */
2976         }
2977         rt = rnext;                     /* Next character is now current. */
2978
2979 /* Done encoding the character.  Now take care of packet buffer overflow. */
2980
2981         if ((dp-data) >= bufmax) {      /* If too big, save some for next. */
2982
2983             debug(F000,"getpkt EOP","",rt);
2984
2985             size = (dp-data);           /* Calculate the size. */
2986             *dp = '\0';                 /* Mark the end. */
2987             if (memstr) {               /* No leftovers for memory strings */
2988                 if (rt)                 /* Char we didn't encode yet */
2989                   memptr--;             /* (for encstr()) */
2990                 return(size);
2991             }
2992             if ((dp-data) > bufmax) {   /* if packet is overfull */
2993                 /* copy the part that doesn't fit into the leftover buffer, */
2994                 /* taking care not to split a prefixed sequence. */
2995                 int i;
2996                 nleft = dp - odp;
2997                 for (i = 0, p1 = leftover, p2 = odp; i < nleft; i++) {
2998                     *p1++ = *p2++;
2999                     if (memstr) memptr--; /* (for encstr) */
3000                 }
3001                 debug(F111,"getpkt leftover",leftover,size);
3002                 debug(F101,"getpkt osize","",(odp-data));
3003                 size = (odp-data);      /* Return truncated packet. */
3004                 *odp = '\0';            /* Mark the new end */
3005             }
3006             t = rt;                     /* Save for next time */
3007             return(size);
3008         }
3009     }                                   /* Otherwise, keep filling. */
3010     size = (dp-data);                   /* End of file */
3011     *dp = '\0';                         /* Mark the end of the data. */
3012     debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
3013     return(size);                    /* return partially filled last packet. */
3014 }
3015
3016 /*  T I N I T  --  Initialize a transaction  */
3017
3018 int epktrcvd = 0, epktsent = 0;
3019
3020 /*
3021   Call with 1 to reset everything before S/I/Y negotiation, or 0 to
3022   reset only the things that are not set in the S/I/Y negotiation.
3023   Returns -1 on failure (e.g. to create packet buffers), 0 on success.
3024 */
3025 int
3026 tinit(flag) int flag; {
3027     int x;
3028 #ifdef CK_TIMERS
3029     extern int rttflg;
3030 #endif /* CK_TIMERS */
3031     extern int rcvtimo;
3032     extern int fatalio;
3033
3034     debug(F101,"tinit flag","",flag);
3035
3036     *epktmsg = NUL;
3037     epktrcvd = 0;
3038     epktsent = 0;
3039     ofperms = "";
3040     diractive = 0;                      /* DIR / REMOTE DIR not active */
3041     interrupted = 0;                    /* Not interrupted */
3042     fatalio = 0;                        /* No fatal i/o error */
3043     if (server) {
3044         moving  = 0;
3045         pipesend = 0; /* This takes care of multiple GETs sent to a server. */
3046     }
3047     bestlen = 0;                        /* For packet length optimization */
3048     maxsend = 0;                        /* Biggest data field we can send */
3049 #ifdef STREAMING
3050     streamok = 0;                       /* Streaming negotiated */
3051     streaming = 0;                      /* Streaming being done now */
3052 #endif /* STREAMING */
3053
3054     binary = b_save;                    /* ... */
3055     gnf_binary = binary;                /* Per-file transfer mode */
3056     retrans = 0;                        /* Packet retransmission count */
3057     sndtyp = 0;                         /* No previous packet */
3058     xflg = 0;                           /* Reset x-packet flag */
3059     memstr = 0;                         /* Reset memory-string flag */
3060     memptr = NULL;                      /*  and buffer pointer */
3061     funcstr = 0;                        /* Reset "read from function" flag */
3062     funcptr = NULL;                     /*  and function pointer */
3063     autopar = 0;                        /* Automatic parity detection flag */
3064
3065     /* This stuff is only for BEFORE S/I/Y negotiation, not after */
3066
3067     if (flag) {
3068         if (bctf) {                   /* Force Block Check 3 on all packets */
3069             bctu = bctl = 3;            /* Set block check type to 3 */
3070         } else {
3071             bctu = bctl = 1;            /* Reset block check type to 1 */
3072         }
3073         myinit[0] = '\0';               /* Haven't sent init string yet */
3074         rqf = -1;                       /* Reset 8th-bit-quote request flag */
3075         ebq = MYEBQ;                    /* Reset 8th-bit quoting stuff */
3076         ebqflg = 0;                     /* 8th bit quoting not enabled */
3077         ebqsent = 0;                    /* No 8th-bit prefix bid sent yet */
3078         sq = 'Y';                       /* 8th-bit prefix bid I usually send */
3079         spsiz = spsizr;                 /* Initial send-packet size */
3080         debug(F101,"tinit spsiz","",spsiz);
3081         wslots = 1;                     /* One window slot */
3082         wslotn = 1;                     /* No window negotiated yet */
3083         justone = 0;                    /* (should this be zero'd here?) */
3084         whoareu[0] = NUL;               /* Partner's system type */
3085         sysindex = -1;
3086         wearealike = 0;
3087         what = W_INIT;                  /* Doing nothing so far... */
3088     }
3089     fncnv = f_save;                     /* Back to what user last said */
3090     pktnum = 0;                         /* Initial packet number to send */
3091     cxseen = czseen = discard = 0;      /* Reset interrupt flags */
3092     *filnam = '\0';                     /* Clear file name */
3093     spktl = 0;                          /* And its length */
3094     nakstate = 0;                       /* Assume we're not in a NAK state */
3095     numerrs = 0;                        /* Transmission error counter */
3096     idletmo = 0;                        /* No idle timeout yet */
3097     if (server) {                       /* If acting as server, */
3098         if (srvidl > 0)                 /* If an idle timeout is given */
3099           timint = srvidl;
3100         else
3101           timint = srvtim;              /* use server timeout interval. */
3102     } else {                            /* Otherwise */
3103         timint = chktimo(rtimo,timef);  /* and use local timeout value */
3104     }
3105     debug(F101,"tinit timint","",timint);
3106
3107 #ifdef CK_TIMERS
3108     if (rttflg && timint > 0)           /* Using round-trip timers? */
3109       rttinit();
3110     else
3111 #endif /* CK_TIMERS */
3112       rcvtimo = timint;
3113
3114     winlo = 0;                          /* Packet 0 is at window-low */
3115     debug(F101,"tinit winlo","",winlo);
3116     x = mksbuf(1);                      /* Make a 1-slot send-packet buffer */
3117     if (x < 0) return(x);
3118     x = getsbuf(0);                     /* Allocate first send-buffer. */
3119     debug(F101,"tinit getsbuf","",x);
3120     if (x < 0) return(x);
3121     dumpsbuf();
3122     x = mkrbuf(wslots);                 /* & a 1-slot receive-packet buffer. */
3123     if (x < 0) return(x);
3124     lsstate = 0;                        /* Initialize locking shift state */
3125     if (autopath) {                     /* SET RECEIVE PATHNAMES AUTO fixup */
3126         fnrpath = PATH_AUTO;
3127         autopath = 0;
3128     }
3129     return(0);
3130 }
3131
3132 VOID
3133 pktinit() {                             /* Initialize packet sequence */
3134     pktnum = 0;                         /* number & window low. */
3135     winlo = 0;
3136     debug(F101,"pktinit winlo","",winlo);
3137 }
3138
3139 /*  R I N I T  --  Respond to S or I packet  */
3140
3141 VOID
3142 rinit(d) CHAR *d; {
3143     char *tp = NULL;
3144     ztime(&tp);
3145     tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
3146     tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
3147     tlog(F110,"Collision action:", fncnam[fncact],0);
3148     tlog(F100,"","",0);
3149     debug(F101,"rinit fncact","",fncact);
3150     filcnt = filrej = 0;                /* Init file counters */
3151     spar(d);
3152     ack1(rpar());
3153 #ifdef datageneral
3154     if ((local) && (!quiet))            /* Only do this if local & not quiet */
3155         consta_mt();                    /* Start the asynch read task */
3156 #endif /* datageneral */
3157 }
3158
3159
3160 /*  R E S E T C  --  Reset per-transaction character counters */
3161
3162 VOID
3163 resetc() {
3164     rptn = 0;                           /* Repeat counts */
3165     fsecs = flci = flco = (CK_OFF_T)0;  /* File chars in and out */
3166 #ifdef GFTIMER
3167     fpfsecs = 0.0;
3168 #endif /* GFTIMER */
3169     tfc = tlci = tlco = (CK_OFF_T)0;    /* Total file, line chars in & out */
3170     ccu = ccp = 0L;                     /* Control-char statistics */
3171 #ifdef COMMENT
3172     fsize = (CK_OFF_T)-1;               /* File size */
3173 #else
3174     if (!(what & W_SEND))
3175       fsize = (CK_OFF_T)-1;
3176     debug(F101,"resetc fsize","",fsize);
3177 #endif /* COMMENT */
3178     timeouts = retrans = 0;             /* Timeouts, retransmissions */
3179     spackets = rpackets = 0;            /* Packet counts out & in */
3180     crunched = 0;                       /* Crunched packets */
3181     wcur = 0;                           /* Current window size */
3182     wmax = 0;                           /* Maximum window size used */
3183     peakcps = 0;                        /* Peak chars per second */
3184 }
3185
3186 /*  S I N I T  --  Get & verify first file name, then send Send-Init packet */
3187 /*
3188  Returns:
3189    1 if send operation begins successfully
3190    0 if send operation fails
3191 */
3192 #ifdef DYNAMIC
3193 char *cmargbuf = NULL;
3194 #else
3195 char cmargbuf[CKMAXPATH+1];
3196 #endif /* DYNAMIC */
3197 char *cmargp[2];
3198
3199 VOID
3200 fnlist() {
3201     if (!calibrate)
3202       sndsrc = (nfils < 0) ? -1 : nfils; /* Source for filenames */
3203 #ifdef DYNAMIC
3204     if (!cmargbuf && !(cmargbuf = malloc(CKMAXPATH+1)))
3205       fatal("fnlist: no memory for cmargbuf");
3206 #endif /* DYNAMIC */
3207     cmargbuf[0] = NUL;                  /* Initialize name buffer */
3208
3209     debug(F101,"fnlist nfils","",nfils);
3210     debug(F110,"fnlist cmarg",cmarg,0);
3211     debug(F110,"fnlist cmarg2",cmarg2,0);
3212     if (!cmarg2) cmarg2 = "";
3213     if (nfils == 0) {                   /* Sending from stdin or memory. */
3214         if ((cmarg2 != NULL) && (*cmarg2)) {
3215             cmarg = cmarg2;             /* If F packet, "as-name" is used */
3216             cmarg2 = "";                /* if provided */
3217         } else
3218           cmarg = "stdin";              /* otherwise just use "stdin" */
3219         ckstrncpy(cmargbuf,cmarg,CKMAXPATH+1);
3220         cmargp[0] = cmargbuf;
3221         cmargp[1] = "";
3222         cmlist = cmargp;
3223         nfils = 1;
3224     }
3225 }
3226
3227 int
3228 sinit() {
3229     int x;                              /* Worker int */
3230     char *tp, *xp, *m;                  /* Worker string pointers */
3231
3232     filcnt = filrej = 0;                /* Initialize file counters */
3233
3234     fnlist();
3235
3236     xp = "";
3237     if (nfils < 0) {
3238 #ifdef PIPESEND
3239         if (usepipes && protocol == PROTO_K && *cmarg == '!') {
3240             pipesend = 1;
3241             cmarg++;
3242         }
3243 #endif /* PIPESEND */
3244         xp = cmarg;
3245     } else {
3246 #ifndef NOMSEND
3247         if (addlist)
3248           xp = filehead->fl_name;
3249         else
3250 #endif /* NOMSEND */
3251           if (filefile)
3252             xp = filefile;
3253           else if (calibrate)
3254             xp = "Calibration";
3255           else
3256             xp = *cmlist;
3257     }
3258     debug(F110,"sinit xp",xp,0);
3259     x = gnfile();                       /* Get first filename. */
3260     debug(F111,"sinit gnfile",ckitoa(gnferror),x);
3261     if (x == 0) x = gnferror;           /* If none, get error reason */
3262     m = NULL;                           /* Error message pointer */
3263     debug(F101,"sinit gnfil","",x);
3264     switch (x) {
3265       case -6: m = "No files meet selection criteria"; break;
3266       case -5: m = "Too many files match wildcard"; break;
3267       case -4: m = "Cancelled"; break;
3268       case -3: m = "Read access denied"; break;
3269       case -2: m = "File is not readable"; break;
3270 #ifdef COMMENT
3271       case -1: m = iswild(filnam) ? "No files match" : "File not found";
3272         break;
3273       case  0: m = "No filespec given!"; break;
3274 #else
3275       case  0:
3276       case -1: m = iswild(filnam) ? "No files match" : "File not found";
3277         break;
3278 #endif /* COMMENT */
3279       default:
3280         break;
3281     }
3282     debug(F101,"sinit nfils","",nfils);
3283     debug(F110,"sinit filnam",filnam,0);
3284     if (x < 1) {                        /* Didn't get a file. */
3285         debug(F111,"sinit msg",m,x);
3286         if (server) {                   /* Doing GET command */
3287             errpkt((CHAR *)m);          /* so send Error packet. */
3288         } else if (!local) {            /* Doing SEND command */
3289             interrupted = 1;            /* (To suppress hint) */
3290             printf("?%s\r\n",m);
3291         } else {
3292             xxscreen(SCR_EM,0,0l,m);    /* so print message. */
3293         }
3294         tlog(F110,xp,m,0L);             /* Make transaction log entry. */
3295         freerbuf(rseqtbl[0]);           /* Free the buffer the GET came in. */
3296         return(0);                      /* Return failure code */
3297     }
3298     if (!local && !server && ckdelay > 0) /* OS-9 sleep(0) == infinite */
3299       sleep(ckdelay);                   /* Delay if requested */
3300 #ifdef datageneral
3301     if ((local) && (!quiet))            /* Only do this if local & not quiet */
3302       consta_mt();                      /* Start the async read task */
3303 #endif /* datageneral */
3304     freerbuf(rseqtbl[0]);               /* Free the buffer the GET came in. */
3305     sipkt('S');                         /* Send the Send-Init packet. */
3306     ztime(&tp);                         /* Get current date/time */
3307     tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
3308     tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
3309     tlog(F100,"","",0);
3310     debug(F111,"sinit ok",filnam,0);
3311     return(1);
3312 }
3313
3314 int
3315 #ifdef CK_ANSIC
3316 sipkt(char c)                           /* Send S or I packet. */
3317 #else
3318 sipkt(c) char c;
3319 #endif
3320 /* sipkt */ {
3321     CHAR *rp; int k, x;
3322     extern int sendipkts;
3323     debug(F101,"sipkt pktnum","",pktnum); /* (better be 0...) */
3324     ttflui();                           /* Flush pending input. */
3325     /*
3326       If this is an I packet and SET SEND I-PACKETS is OFF, don't send it;
3327       set sstate to 'Y' which makes the next input() call return 'Y' as if we
3328       had received an ACK to the I packet we didn't send.  This is to work
3329       around buggy Kermit servers that can't handle I packets.
3330     */
3331     if ((sendipkts == 0) && (c == 'I')) { /* I packet but don't send I pkts? */
3332         sstate = 'Y';                     /* Yikes! */
3333         return(0);                        /* (see input()..)*/
3334     }
3335     k = sseqtbl[pktnum];                /* Find slot for this packet */
3336     if (k < 0) {                        /* No slot? */
3337         k = getsbuf(winlo = pktnum);    /* Make one. */
3338         debug(F101,"sipkt getsbuf","",k);
3339     }
3340     rp = rpar();                        /* Get protocol parameters. */
3341     if (!rp) rp = (CHAR *)"";
3342     x = spack(c,pktnum,(int)strlen((char *)rp),rp); /* Send them. */
3343     return(x);
3344 }
3345
3346 /*  X S I N I T  --  Retransmit S-packet  */
3347 /*
3348   For use in the GET-SEND sequence, when we start to send, but receive another
3349   copy of the GET command because the receiver didn't get our S packet.
3350   This retransmits the S packet and frees the receive buffer for the ACK.
3351   This special case is necessary because packet number zero is being re-used.
3352 */
3353 VOID
3354 xsinit() {
3355     int k;
3356     k = rseqtbl[0];
3357     debug(F101,"xsinit k","",k);
3358     if (k > -1)
3359     freerbuf(k);
3360     resend(0);
3361 }
3362
3363 /*  R C V F I L -- Receive a file  */
3364
3365 /*
3366   Incoming filename is in data field of F packet.
3367   This function decodes it into the srvcmd buffer, substituting an
3368   alternate "as-name", if one was given.
3369   Then it does any requested transformations (like converting to
3370   lowercase), and finally if a file of the same name already exists,
3371   takes the desired collision action.
3372   Returns:
3373     1 on success.
3374     0 on failure.
3375 */
3376 char ofn1[CKMAXPATH+4];                 /* Buffer for output file name */
3377 char * ofn2;                            /* Pointer to backup file name */
3378 int ofn1x;                              /* Flag output file already exists */
3379 CK_OFF_T ofn1len = (CK_OFF_T)0;
3380 int opnerr;                             /* Flag for open error */
3381
3382 int                                     /* Returns success ? 1 : 0 */
3383 rcvfil(n) char *n; {
3384     extern int en_cwd;
3385     int i, skipthis;
3386     char * n2;
3387     char * dispo;
3388 #ifdef OS2ONLY
3389     char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */
3390 #endif /* OS2ONLY */
3391 #ifdef DTILDE
3392     char *dirp;
3393 #endif /* DTILDE */
3394     int dirflg, x, y;
3395 #ifdef PIPESEND
3396     extern char * rcvfilter;
3397 #endif /* PIPESEND */
3398 #ifdef CALIBRATE
3399     extern int dest;
3400     CK_OFF_T csave;
3401     csave = calibrate;                  /* So we can decode filename */
3402     calibrate = (CK_OFF_T)0;
3403 #endif /* CALIBRATE */
3404
3405     ofperms = "";                       /* Reset old-file permissions */
3406     opnerr = 0;                         /* No open error (yet) */
3407     ofn2 = NULL;                        /* No new name (yet) */
3408     lsstate = 0;                        /* Cancel locking-shift state */
3409     srvptr = srvcmd;                    /* Decode file name from packet. */
3410
3411 #ifdef UNICODE
3412     xpnbyte(-1,0,0,NULL);               /* Reset UCS-2 byte counter. */
3413 #endif /* UNICODE */
3414
3415     debug(F110,"rcvfil rdatap",rdatap,0);
3416     decode(rdatap,putsrv,0);            /* Don't xlate charsets. */
3417 #ifdef CALIBRATE
3418     calibrate = csave;
3419     if (dest == DEST_N) {
3420         calibrate = 1;
3421         cmarg2 = "CALIBRATE";
3422     }
3423 #endif /* CALIBRATE */
3424     if (*srvcmd == '\0')                /* Watch out for null F packet. */
3425       ckstrncpy((char *)srvcmd,"NONAME",srvcmdlen);
3426     makestr(&prrfspec,(char *)srvcmd);  /* New preliminary filename */
3427 #ifdef DTILDE
3428     if (*srvcmd == '~') {
3429         dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
3430         if (*dirp != '\0')
3431           ckstrncpy((char *)srvcmd,dirp,srvcmdlen);
3432     }
3433 #else
3434 #ifdef OS2
3435     if (isalpha(*srvcmd) && srvcmd[1] == ':' && srvcmd[2] == '\0')
3436       ckstrncat((char *)srvcmd,"NONAME",srvcmdlen);
3437 #endif /* OS2 */
3438 #endif /* DTILDE */
3439
3440 #ifndef NOICP
3441 #ifndef NOSPL
3442 /* File dialog when downloading...  */
3443     if (
3444 #ifdef CK_APC
3445         (apcactive == APC_LOCAL && adl_ask) || /* Autodownload with ASK */
3446 #endif /* CK_APC */
3447         (clcmds && haveurl)             /* Or "kermit:" or "iksd:" URL */
3448         ) {
3449         int x;
3450         char fnbuf[CKMAXPATH+1];        /* Result buffer */
3451         char * preface;
3452
3453         if (clcmds && haveurl)
3454           preface = "\r\nIncoming file from Kermit server...\r\n\
3455 Please confirm output file specification or supply an alternative:";
3456         else
3457           preface = "\r\nIncoming file from remote Kermit...\r\n\
3458 Please confirm output file specification or supply an alternative:";
3459
3460         x = uq_file(preface,            /* Preface */
3461                     NULL,               /* Prompt (let uq_file() built it) */
3462                     3,                  /* Output file */
3463                     NULL,               /* Help text */
3464                     (char *)srvcmd,     /* Default */
3465                     fnbuf,              /* Result buffer */
3466                     CKMAXPATH+1         /* Size of result buffer */
3467                     );
3468         if (x < 1) {                    /* Refused */
3469             rf_err = "Refused by user";
3470             return(0);
3471         }
3472         ckstrncpy((char *)srvcmd,fnbuf,CKMAXPATH+1);
3473         if (isabsolute((char *)srvcmd)) { /* User gave an absolute path */
3474             g_fnrpath = fnrpath;        /* Save current RECEIVE PATHNAMES */
3475             fnrpath = PATH_ABS;         /* switch to ABSOLUTE */
3476         }
3477     }
3478 #endif /* NOSPL */
3479 #endif /* NOICP */
3480
3481     if (!ENABLED(en_cwd)) {             /* CD is disabled */
3482         zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
3483         if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
3484             rf_err = "Access denied";
3485             return(0);
3486         }
3487     }
3488 #ifdef COMMENT
3489     /* Wrong place for this -- handle cmarg2 first -- see below...  */
3490
3491     if (zchko((char *)srvcmd) < 0) {    /* Precheck for write access */
3492         debug(F110,"rcvfil access denied",srvcmd,0);
3493         rf_err = "Write access denied";
3494         discard = opnerr = 1;
3495         return(0);
3496     }
3497     xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
3498     debug(F110,"rcvfil srvcmd 1",srvcmd,0);
3499     tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
3500 #endif /* COMMENT */
3501
3502     skipthis = 0;                       /* This file in our exception list? */
3503     for (i = 0; i < NSNDEXCEPT; i++) {
3504         if (!rcvexcept[i]) {
3505             break;
3506         }
3507         if (ckmatch(rcvexcept[i],(char *)srvcmd,filecase,1)) {
3508             skipthis = 1;
3509             break;
3510         }
3511     }
3512
3513 #ifdef DEBUG
3514     if (deblog && skipthis) {
3515         debug(F111,"rcvfil rcvexcept",rcvexcept[i],i);
3516         debug(F110,"rcvfil skipping",srvcmd,0);
3517     }
3518 #endif /* DEBUG */
3519
3520     if (skipthis) {                     /* Skipping this file */
3521         discard = 1;
3522         rejection = 1;
3523         rf_err = "Exception list";
3524         debug(F101,"rcvfil discard","",discard);
3525         tlog(F100," refused: exception list","",0);
3526         return(1);
3527     }
3528
3529     /* File is not in exception list */
3530
3531     if (!cmarg2)                        /* No core dumps please */
3532       cmarg2 = "";
3533     debug(F110,"rcvfil cmarg2",cmarg2,0);
3534
3535     if (*cmarg2) {                      /* Check for alternate name */
3536 #ifndef NOSPL
3537         int y; char *s;                 /* Pass it thru the evaluator */
3538         extern int cmd_quoting;
3539         if (cmd_quoting) {
3540             y = MAXRP;
3541             ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* for \v(filename) */
3542             s = (char *)srvcmd;
3543             zzstring(cmarg2,&s,&y);
3544         } else
3545           *srvcmd = NUL;
3546         if (!*srvcmd)                   /* If we got something */
3547 #endif /* NOSPL */
3548           ckstrncpy((char *)srvcmd,cmarg2,srvcmdlen);
3549     }
3550     debug(F110,"rcvfil srvcmd 2",srvcmd,0);
3551
3552 #ifdef PIPESEND
3553     /* If it starts with "bang", it's a pipe, not a file. */
3554     if (usepipes && protocol == PROTO_K && *srvcmd == '!' && !rcvfilter) {
3555         CHAR *s;
3556         s = srvcmd+1;                   /* srvcmd[] is not a pointer. */
3557         while (*s) {                    /* So we have to slide the contents */
3558             *(s-1) = *s;                /* over 1 space to the left. */
3559             s++;
3560         }
3561         *(s-1) = NUL;
3562         pipesend = 1;
3563     }
3564 #endif /* PIPESEND */
3565
3566 #ifdef COMMENT
3567 /*
3568   This is commented out because we need to know whether the name we are
3569   using was specified by the local user as an override, or came from the
3570   incoming packet.  In the former case, we don't do stuff to it (like
3571   strip the pathname) that we might do to it in the latter.
3572 */
3573     cmarg2 = "";                        /* Done with alternate name */
3574 #endif /* COMMENT */
3575
3576     if ((int)strlen((char *)srvcmd) > CKMAXPATH) /* Watch out for overflow */
3577       *(srvcmd + CKMAXPATH - 1) = NUL;
3578
3579     /* At this point, srvcmd[] contains the incoming filename or as-name. */
3580     /* So NOW we check for write access. */
3581
3582     if (zchko((char *)srvcmd) < 0) {    /* Precheck for write access */
3583         debug(F110,"rcvfil access denied",srvcmd,0);
3584         rf_err = "Write access denied";
3585         discard = opnerr = 1;
3586         return(0);
3587     }
3588     xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
3589     debug(F110,"rcvfil srvcmd 1",srvcmd,0);
3590     tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
3591
3592 #ifdef CK_LABELED
3593 #ifdef VMS
3594 /*
3595   If we have an as-name, this overrides the internal name if we are doing
3596   a labeled-mode transfer.
3597 */
3598     if (*cmarg2) {
3599         extern int lf_opts;
3600         lf_opts &= ~LBL_NAM;
3601     }
3602 #endif /* VMS */
3603 #endif /* CK_LABELED */
3604
3605     debug(F111,"rcvfil pipesend",srvcmd,pipesend);
3606
3607 #ifdef PIPESEND
3608     /* Skip all the filename manipulation and collision actions */
3609     if (pipesend) {
3610         dirflg = 0;
3611         ofn1[0] = '!';
3612         ckstrncpy(&ofn1[1],(char *)srvcmd,CKMAXPATH+1);
3613         ckstrncpy(n,ofn1,CKMAXPATH+1);
3614         ckstrncpy(fspec,ofn1,CKMAXPATH+1);
3615         makestr(&prfspec,fspec);        /* New preliminary filename */
3616         debug(F110,"rcvfil pipesend",ofn1,0);
3617         goto rcvfilx;
3618     }
3619 #endif /* PIPESEND */
3620 /*
3621   This is to avoid passing email subjects through nzrtol().
3622   We haven't yet received the A packet so we don't yet know it's e-mail,
3623   so in fact we go ahead and convert it anyway, but later we get the
3624   original back from ofilnam[].
3625 */  
3626     dispos = 0;
3627     ckstrncpy(ofilnam,(char *)srvcmd,CKMAXPATH+1);
3628
3629 #ifdef NZLTOR
3630     if (*cmarg2)
3631       ckstrncpy((char *)ofn1,(char *)srvcmd,CKMAXPATH+1);
3632     else
3633       nzrtol((char *)srvcmd,            /* Filename from packet */
3634              (char *)ofn1,              /* Where to put result */
3635              fncnv,                     /* Filename conversion */
3636              fnrpath,                   /* Pathname handling */
3637              CKMAXPATH                  /* Size of result buffer */
3638              );
3639 #else
3640     debug(F101,"rcvfil fnrpath","",fnrpath); /* Handle pathnames */
3641     if (fnrpath == PATH_OFF && !*cmarg2) { /* RECEIVE PATHNAMES OFF? */
3642         char *t;                        /* Yes. */
3643         zstrip((char *)srvcmd,&t);      /* If there is a pathname, strip it */
3644         debug(F110,"rcvfil PATH_OFF zstrip",t,0);
3645         if (!t)                         /* Be sure we didn't strip too much */
3646           sprintf(ofn1,"FILE%02ld",filcnt);
3647         else if (*t == '\0')
3648           sprintf(ofn1,"FILE%02ld",filcnt);
3649         else
3650           ckstrncpy(ofn1,t,CKMAXPATH+1);
3651         ckstrncpy((char *)srvcmd,ofn1,srvcmdlen); /* Now copy it back. */
3652     }
3653 /*
3654   SET RECEIVE PATHNAMES RELATIVE...
3655   The following doesn't belong here but doing it right would require
3656   defining and implementing a new file routine for all ck?fio.c modules.
3657   So for now...
3658 */
3659 #ifdef UNIXOROSK
3660     else if (fnrpath == PATH_REL && !*cmarg2) {
3661         if (isabsolute((char *)srvcmd)) {
3662             ofn1[0] = '.';
3663             ckstrncpy(&of1n[1],(char *)srvcmd,CKMAXPATH+1);
3664             ckstrncpy((char *)srvcmd,ofn1,srvcmdlen);
3665             debug(F110,"rcvfil PATH_REL",ofn1,0);
3666         }
3667     }
3668 #else
3669 #ifdef OS2
3670     else if (fnrpath == PATH_REL && !*cmarg2) {
3671         if (isabsolute((char *)srvcmd)) {
3672             char *p = (char *)srvcmd;
3673             if (isalpha(*p) && *(p+1) == ':')
3674               p += 2;
3675             if (*p == '\\' || *p == '/')
3676               p++;
3677             ckstrncpy(ofn1,p,CKMAXPATH+1);
3678             ckstrncpy((char *)srvcmd,ofn1,srvcmdlen);
3679             debug(F110,"rcvfil OS2 PATH_REL",ofn1,0);
3680         }
3681     }
3682 #endif /* OS2 */
3683 #endif /* UNIXOROSK */
3684
3685     /* Now srvcmd contains incoming filename with path possibly stripped */
3686
3687     if (fncnv)                          /* FILE NAMES CONVERTED? */
3688       zrtol((char *)srvcmd,(char *)ofn1); /* Yes, convert to local form */
3689     else
3690       ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* No, copy literally. */
3691 #endif /* NZLTOR */
3692
3693 #ifdef PIPESEND
3694     if (rcvfilter) {
3695         char * p = NULL, * q;
3696         int nn = MAXRP;
3697         pipesend = 1;
3698         debug(F110,"rcvfil rcvfilter ",rcvfilter,0);
3699 #ifndef NOSPL
3700         if ((p = (char *) malloc(nn + 1))) {
3701             q = p;
3702 #ifdef COMMENT
3703             /* We have already processed srvcmd and placed it into ofn1 */
3704             ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* For \v(filename) */
3705 #endif /* COMMENT */
3706             debug(F110,"rcvfile pipesend filter",rcvfilter,0);
3707             zzstring(rcvfilter,&p,&nn);
3708             debug(F111,"rcvfil pipename",q,nn);
3709             if (nn <= 0) {
3710                 printf(
3711                        "?Sorry, receive filter + filename too long, %d max.\n",
3712                        CKMAXPATH
3713                        );
3714                 rf_err = "Name too long";
3715                 free(q);
3716                 return(0);
3717             }
3718             ckstrncpy((char *)srvcmd,q,MAXRP);
3719             free(q);
3720         }
3721 #endif /* NOSPL */
3722     }
3723 #endif /* PIPESEND */
3724
3725     /* Now the incoming filename, possibly converted, is in ofn1[]. */
3726
3727 #ifdef OS2
3728     /* Don't refuse the file just because the name is illegal. */
3729     if (!IsFileNameValid(ofn1)) {       /* Name is OK for OS/2? */
3730 #ifdef OS2ONLY
3731         char *zs = NULL;
3732         zstrip(ofn1, &zs);              /* Not valid, strip unconditionally */
3733         if (zs) {
3734             if (iattr.longname.len &&   /* Free previous longname, if any */
3735                 iattr.longname.val)
3736               free(iattr.longname.val);
3737             iattr.longname.len = strlen(zs); /* Store in attribute structure */
3738             iattr.longname.val = (char *) malloc(iattr.longname.len + 1);
3739             if (iattr.longname.val)     /* Remember this (illegal) name */
3740               strcpy(iattr.longname.val, zs); /* safe */
3741         }
3742 #endif /* OS2ONLY */
3743         debug(F110,"rcvfil: invalid file name",ofn1,0);
3744         ChangeNameForFAT(ofn1); /* Change to an acceptable name */
3745         debug(F110,"rcvfil: FAT file name",ofn1,0);
3746
3747     } else {                            /* Name is OK. */
3748
3749         debug(F110,"rcvfil: valid file name",ofn1,0);
3750 #ifdef OS2ONLY
3751         if (iattr.longname.len &&
3752              iattr.longname.val)        /* Free previous longname, if any */
3753           free(iattr.longname.val);
3754         iattr.longname.len = 0;
3755         iattr.longname.val = NULL;      /* This file doesn't need a longname */
3756 #endif /* OS2ONLY */
3757     }
3758 #endif /* OS2 */
3759     debug(F110,"rcvfil as",ofn1,0);
3760
3761 /* Filename collision action section. */
3762
3763     dirflg =                            /* Is it a directory name? */
3764 #ifdef CK_TMPDIR
3765         isdir(ofn1)
3766 #else
3767         0
3768 #endif /* CK_TMPDIR */
3769           ;
3770     debug(F101,"rcvfil dirflg","",dirflg);
3771     ofn1len = zchki(ofn1);              /* File already exists? */
3772     debug(F111,"rcvfil ofn1len",ofn1,ofn1len);
3773     ofn1x = (ofn1len != (CK_OFF_T)-1);
3774
3775     if ( (
3776 #ifdef UNIX
3777         strcmp(ofn1,"/dev/null") &&     /* It's not the null device? */
3778 #else
3779 #ifdef OSK
3780         strcmp(ofn1,"/nil") &&
3781 #endif /* OSK */
3782 #endif /* UNIX */
3783         !stdouf ) &&                    /* Not copying to standard output? */
3784         ofn1x ||                        /* File of same name exists? */
3785         dirflg ) {                      /* Or file is a directory? */
3786         debug(F111,"rcvfil exists",ofn1,fncact);
3787 #ifdef CK_PERMS
3788         ofperms = zgperm((char *)ofn1); /* Get old file's permissions */
3789         debug(F110,"rcvfil perms",ofperms,0);
3790 #endif /* CK_PERMS */
3791
3792         debug(F101,"rcvfil fncact","",fncact);
3793         switch (fncact) {               /* Yes, do what user said. */
3794           case XYFX_A:                  /* Append */
3795             ofperms = "";
3796             debug(F100,"rcvfil append","",0);
3797             if (dirflg) {
3798                 rf_err = "Can't append to a directory";
3799                 tlog(F100," error - can't append to directory","",0);
3800                 discard = opnerr = 1;
3801                 return(0);
3802             }
3803             tlog(F110," appending to",ofn1,0);
3804             break;
3805 #ifdef COMMENT
3806           case XYFX_Q:                  /* Query (Ask) */
3807             break;                      /* not implemented */
3808 #endif /* COMMENT */
3809           case XYFX_B:                  /* Backup (rename old file) */
3810             if (dirflg) {
3811                 rf_err = "Can't rename existing directory";
3812                 tlog(F100," error - can't rename directory","",0);
3813                 discard = opnerr = 1;
3814                 return(0);
3815             }
3816             znewn(ofn1,&ofn2);          /* Get new unique name */
3817             tlog(F110," backup:",ofn2,0);
3818             debug(F110,"rcvfil backup ofn1",ofn1,0);
3819             debug(F110,"rcvfil backup ofn2",ofn2,0);
3820 #ifdef CK_LABELED
3821 #ifdef OS2ONLY
3822 /*
3823   In case this is a FAT file system, we can't change only the FAT name, we
3824   also have to change the longname from the extended attributes block.
3825   Otherwise, we'll have many files with the same longname and if we copy them
3826   to an HPFS volume, only one will survive.
3827 */
3828             if (os2getlongname(ofn1, &longname) > -1) {
3829                 if (strlen(longname)) {
3830                     char tmp[10];
3831                     extern int ck_znewn;
3832                     sprintf(tmp,".~%d~",ck_znewn);
3833                     newlongname =
3834                       (char *) malloc(strlen(longname) + strlen(tmp) + 1);
3835                     if (newlongname) {
3836                         strcpy(newlongname, longname); /* safe (prechecked) */
3837                         strcat(newlongname, tmp); /* safe (prechecked) */
3838                         os2setlongname(ofn1, newlongname);
3839                         free(newlongname);
3840                         newlongname = NULL;
3841                     }
3842                 }
3843             } else debug(F100,"rcvfil os2getlongname failed","",0);
3844 #endif /* OS2ONLY */
3845 #endif /* CK_LABELED */
3846
3847 #ifdef COMMENT
3848             /* Do this later, in opena()... */
3849             if (zrename(ofn1,ofn2) < 0) {
3850                 rf_err = "Can't transform filename";
3851                 debug(F110,"rcvfil rename fails",ofn1,0);
3852                 discard = opnerr = 1;
3853                 return(0);
3854             }
3855 #endif /* COMMENT */
3856             break;
3857
3858           case XYFX_D:                  /* Discard (refuse new file) */
3859             ofperms = "";
3860             discard = 1;
3861             rejection = 1;              /* Horrible hack: reason = name */
3862             debug(F101,"rcvfil discard","",discard);
3863             tlog(F100," refused: name","",0);
3864             break;
3865
3866           case XYFX_R:                  /* Rename incoming file */
3867             znewn(ofn1,&ofn2);          /* Make new name for it */
3868 #ifdef OS2ONLY
3869             if (iattr.longname.len) {
3870                 char tmp[10];
3871                 extern int ck_znewn;
3872                 sprintf(tmp,".~%d~",ck_znewn);
3873                 newlongname =
3874                   (char *) malloc(iattr.longname.len + strlen(tmp) + 1);
3875                 if (newlongname) {
3876                     strcpy(newlongname, iattr.longname.val); /* safe */
3877                     strcat(newlongname, tmp); /* safe */
3878                     debug(F110,
3879                           "Rename Incoming: newlongname",newlongname,0);
3880                     if (iattr.longname.len &&
3881                         iattr.longname.val)
3882                       free(iattr.longname.val);
3883                     iattr.longname.len = strlen(newlongname);
3884                     iattr.longname.val = newlongname;
3885                     /* free(newlongname) here ? */
3886                 }
3887             }
3888 #endif /* OS2ONLY */
3889             break;
3890           case XYFX_X:                  /* Replace old file */
3891             debug(F100,"rcvfil overwrite","",0);
3892             if (dirflg) {
3893                 rf_err = "Can't overwrite existing directory";
3894                 tlog(F100," error - can't overwrite directory","",0);
3895                 discard = opnerr = 1;
3896 #ifdef COMMENT
3897                 return(0);
3898 #else
3899                 break;
3900 #endif /* COMMENT */
3901             }
3902             tlog(F110,"overwriting",ofn1,0);
3903             break;
3904           case XYFX_U:                  /* Refuse if older */
3905             debug(F110,"rcvfil update",ofn1,0);
3906             if (dirflg) {
3907                 rf_err = "File has same name as existing directory";
3908                 tlog(F110," error - directory exists:",ofn1,0);
3909                 discard = opnerr = 1;
3910 #ifdef COMMENT
3911                 /* Don't send an error packet, just refuse the file */
3912                 return(0);
3913 #endif /* COMMENT */
3914             }
3915             break;                      /* Not here, we don't have */
3916                                         /* the attribute packet yet. */
3917           default:
3918             ofperms = "";
3919             debug(F101,"rcvfil bad collision action","",fncact);
3920             break;
3921         }
3922     }
3923     debug(F110,"rcvfil ofn1",ofn1,0);
3924     debug(F110,"rcvfil ofn2",ofn2,0);
3925     debug(F110,"rcvfil ofperms",ofperms,0);
3926     if (fncact == XYFX_R && ofn1x && ofn2) { /* Renaming incoming file? */
3927         xxscreen(SCR_AN,0,0l,ofn2);     /* Display renamed name */
3928         ckstrncpy(n, ofn2, CKMAXPATH+1); /* Return it */
3929     } else {                            /* No */
3930         xxscreen(SCR_AN,0,0l,ofn1);     /* Display regular name */
3931         ckstrncpy(n, ofn1, CKMAXPATH+1); /* and return it. */
3932     }
3933
3934 #ifdef CK_MKDIR
3935 /*  Create directory(s) if necessary.  */
3936     if (!discard && fnrpath != PATH_OFF) { /* RECEIVE PATHAMES ON? */
3937         int x;
3938         debug(F110,"rcvfil calling zmkdir",ofn1,0); /* Yes */
3939         if ((x = zmkdir(ofn1)) < 0) {
3940             debug(F100,"zmkdir fails","",0);
3941             tlog(F110," error - directory creation failure:",ofn1,0);
3942             rf_err = "Directory creation failure.";
3943             discard = 1;
3944             return(0);
3945         }
3946 #ifdef TLOG
3947         else if (x > 0)
3948           tlog(F110," path created:",ofn1,0);
3949 #endif /* TLOG */
3950     }
3951 #else
3952     debug(F110,"rcvfil CK_MKDIR not defined",ofn1,0);
3953 #endif /* CK_MKDIR */
3954
3955     if (calibrate)
3956       ckstrncpy(fspec,ofn1,CKMAXPATH+1);
3957     else
3958       zfnqfp(ofn1,fspeclen,fspec);
3959     debug(F110,"rcvfil fspec",fspec,0);
3960
3961 #ifdef COMMENT
3962     /* See comments with VMS zfnqfp()... */
3963 #ifdef VMS
3964     /* zfnqfp() does not return the version number */
3965     if (!calibrate) {
3966         int x, v;
3967         x = strlen(ofn1);
3968         if (x > 0) {
3969             if (ofn1[x-1] == ';') {
3970                 v = getvnum(ofn1);
3971                 ckstrncpy(&ofn1[x],ckitoa(v),CKMAXPATH-x);
3972             }
3973         }
3974     }
3975 #endif /* VMS */
3976 #endif /* COMMENT */
3977     fspec[fspeclen] = NUL;
3978     makestr(&prfspec,fspec);            /* New preliminary filename */
3979
3980 #ifdef PIPESEND
3981   rcvfilx:
3982 #endif /* PIPESEND */
3983
3984     debug(F110,"rcvfilx: n",n,0);
3985     debug(F110,"rcvfilx: ofn1",ofn1,0);
3986     ffc = (CK_OFF_T)0;                  /* Init per-file counters */
3987     cps = oldcps = 0L;
3988     rs_len = (CK_OFF_T)0;
3989     rejection = -1;
3990     fsecs = gtimer();                   /* Time this file started */
3991 #ifdef GFTIMER
3992     fpfsecs = gftimer();
3993     debug(F101,"rcvfil fpfsecs","",fpfsecs);
3994 #endif /* GFTIMER */
3995     filcnt++;
3996     intmsg(filcnt);
3997     return(1);                          /* Successful return */
3998 }
3999
4000
4001 /*  R E O F  --  Receive End Of File packet for incoming file */
4002
4003 /*
4004   Closes the received file.
4005   Returns:
4006     0 on success.
4007    -1 if file could not be closed.
4008     2 if disposition was mail, mail was sent, but temp file not deleted.
4009     3 if disposition was print, file was printed, but not deleted.
4010    -2 if disposition was mail and mail could not be sent
4011    -3 if disposition was print and file could not be printed
4012    -4 if MOVE-TO: failed
4013    -5 if RENAME-TO: failed
4014 */
4015 int
4016 reof(f,yy) char *f; struct zattr *yy; {
4017     extern char * rcv_move, * rcv_rename;
4018     extern int o_isopen;
4019     int rc = 0;                         /* Return code */
4020     char *p;
4021     char c;
4022
4023     debug(F111,"reof fncact",f,fncact);
4024     debug(F101,"reof discard","",discard);
4025     success = 1;                        /* Assume status is OK */
4026     lsstate = 0;                        /* Cancel locking-shift state */
4027     if (discard) {                      /* Handle attribute refusals, etc. */
4028         debug(F101,"reof discarding","",0);
4029         success = 0;                    /* Status = failed. */
4030         if (rejection == '#' ||         /* Unless rejection reason is */
4031             rejection ==  1  ||         /* date or name (SET FILE COLLISION */
4032             rejection == '?')           /* UPDATE or DISCARD) */
4033           success = 1;
4034         debug(F101,"reof success","",success);
4035         filrej++;                       /* Count this rejection. */
4036         discard = 0;                    /* We never opened the file, */
4037         return(0);                      /* so we don't close it. */
4038     }
4039 #ifdef DEBUG
4040     if (deblog) {
4041         debug(F101,"reof cxseen","",cxseen);
4042         debug(F101,"reof czseen","",czseen);
4043         debug(F110,"reof rdatap",rdatap,0);
4044     }
4045 #endif /* DEBUG */
4046
4047     if (cxseen == 0)                    /* Got cancel directive? */
4048       cxseen = (*rdatap == 'D');
4049     if (cxseen || czseen)               /* (for hints) */
4050       interrupted = 1;
4051     success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */
4052     if (!success)                         /* "Uncount" this file */
4053       filrej++;
4054     debug(F101,"reof o_isopen","",o_isopen);
4055
4056     if (o_isopen) {                     /* If an output file was open... */
4057
4058 #ifdef CK_CTRLZ
4059         if (success) {
4060             debug(F101,"reof lastchar","",lastchar);
4061             if (!binary && eofmethod == XYEOF_Z && lastchar != 26 &&
4062                 (!xflg || (xflg && remfile)))
4063               pnbyte((char)26,putfil);
4064         }
4065 #endif /* CK_CTRLZ */
4066
4067         rc = clsof(cxseen || czseen);   /* Close the file (resets cxseen) */
4068         debug(F101,"reof closf","",rc);
4069         if (rc < 0) {                   /* If failure to close, FAIL */
4070             if (success) filrej++;
4071             success = 0;
4072         }
4073         if (!calibrate) {
4074             /* Set file modification date and/or permissions */
4075             if (success)
4076               zstime(f,yy,0);
4077 #ifdef OS2ONLY
4078 #ifdef CK_LABELED
4079             if (success && yy->longname.len)
4080               os2setlongname(f, yy->longname.val);
4081 #endif /* CK_LABELED */
4082 #endif /* OS2ONLY */
4083         }
4084         if (success == 0) {             /* And program return code */
4085             xitsta |= W_RECV;
4086         } else if (success == 1) {      /* File rec'd successfully */
4087             makestr(&rrfspec,prrfspec); /* Record it for wheremsg */
4088             makestr(&rfspec,prfspec);
4089         }
4090
4091 /* Handle dispositions from attribute packet... */
4092
4093         c = NUL;
4094 #ifndef NOFRILLS
4095         if (!calibrate && yy->disp.len != 0) {
4096             p = yy->disp.val;
4097             c = *p++;
4098 #ifndef UNIX
4099 /*
4100   See ckcpro.w.  In UNIX we don't use temp files any more -- we pipe the
4101   stuff right into mail or lpr.
4102 */
4103             if (c == 'M') {             /* Mail to user. */
4104                 rc = zmail(p,filnam);   /* Do the system's mail command */
4105                 if (rc < 0) success = 0;        /* Remember status */
4106                 tlog(F110,"mailed",filnam,0L);
4107                 tlog(F110," to",p,0L);
4108                 zdelet(filnam);         /* Delete the file */
4109             } else if (c == 'P') {      /* Print the file. */
4110                 rc = zprint(p,filnam);  /* Do the system's print command */
4111                 if (rc < 0) success = 0; /* Remember status */
4112                 tlog(F110,"printed",filnam,0L);
4113                 tlog(F110," with options",p,0L);
4114 #ifndef VMS
4115 #ifndef STRATUS
4116                 /* spooler deletes file after print complete in VOS & VMS */
4117                 if (zdelet(filnam) && rc == 0) rc = 3; /* Delete the file */
4118 #endif /* STRATUS */
4119 #endif /* VMS */
4120             }
4121 #endif /* UNIX */
4122         }
4123 #endif /* NOFRILLS */
4124
4125         if (success &&
4126             !pipesend &&
4127             !calibrate && c != 'M' && c != 'P') {
4128             if (rcv_move) {             /* If /MOVE-TO was given... */
4129                 char * p = rcv_move;
4130 #ifdef COMMENT
4131 /* No need for this - it's a directory name */
4132                 char tmpbuf[CKMAXPATH+1];
4133                 extern int cmd_quoting; /* for \v(filename) */
4134                 if (cmd_quoting) {      /* But only if cmd_quoting is on */
4135                     int n;
4136                     n = CKMAXPATH;
4137                     p = tmpbuf;
4138                     debug(F111,"reof /move-to",rcv_move,0);
4139                     zzstring(rcv_move,&p,&n);
4140                     p = tmpbuf;
4141                 }
4142 #endif /* COMMENT */
4143 /*
4144   Here we could create the directory if it didn't exist (and it was relative)
4145   but there would have to be a user-settable option to say whether to do this.
4146 */
4147                 rc = zrename(filnam,p);
4148                 debug(F111,"reof MOVE zrename",rcv_move,rc);
4149                 if (rc > -1) {
4150                     tlog(F110," moving received file to",rcv_move,0);
4151                 } else {
4152                     rc = -4;
4153                     tlog(F110," FAILED to move received file to",rcv_move,0);
4154                 }
4155             } else if (rcv_rename) {    /* Or /RENAME-TO: */
4156                 char *s = rcv_rename;   /* This is the renaming string */
4157 #ifndef NOSPL
4158                 char tmpnam[CKMAXPATH+16];
4159                 extern int cmd_quoting; /* for \v(filename) */
4160                 if (cmd_quoting) {      /* But only if cmd_quoting is on */
4161                     int n;              /* Pass it thru the evaluator */
4162                     n = CKMAXPATH;
4163                     s = (char *)tmpnam;
4164                     zzstring(rcv_rename,&s,&n);
4165                     s = (char *)tmpnam;
4166                 }
4167 #endif /* NOSPL */
4168                 if (s) if (*s) {
4169                     rc = zrename(filnam,s);
4170                     debug(F111,"reof RENAME zrename",s,rc);
4171                     if (rc > -1) {
4172                         tlog(F110," renaming received file to",s,0);
4173                     } else {
4174                         rc = -5;
4175                         tlog(F110," FAILED to rename received file to",s,0);
4176                     }
4177                 }
4178             }
4179         }
4180     }
4181     debug(F101,"reof success","",success);
4182     debug(F101,"reof returns","",rc);
4183
4184     filnam[0] = NUL;                    /* Erase the filename */
4185     return(rc);
4186 }
4187
4188 /*  R E O T  --  Receive End Of Transaction  */
4189
4190 VOID
4191 reot() {
4192     cxseen = czseen = discard = 0;      /* Reset interruption flags */
4193     tstats();                           /* Finalize transfer statistics */
4194 }
4195
4196 /*  S F I L E -- Send File header or teXt header packet  */
4197
4198 /*
4199   Call with x nonzero for X packet, zero for F packet.
4200   If X == 0, filename to send is in filnam[], and if cmarg2 is not null
4201   or empty, the file should be sent under this name rather than filnam[].
4202   If sndfilter not NULL, it is the name of a send filter.
4203   Returns 1 on success, 0 on failure.
4204 */
4205 int
4206 sfile(x) int x; {
4207 #ifdef pdp11
4208 #define PKTNL 64
4209 #else
4210 #define PKTNL 256
4211 #endif /* pdp11 */
4212     char pktnam[PKTNL+1];               /* Local copy of name */
4213     char *s;
4214     int rc;
4215     int notafile = 0;
4216     extern int filepeek;
4217 #ifdef PIPESEND
4218     extern char * sndfilter;
4219
4220     if (sndfilter) {
4221         pipesend = 1;
4222         debug(F110,"sfile send filter ",sndfilter,0);
4223     }
4224 #endif /* PIPESEND */
4225
4226     notafile = calibrate || sndarray || pipesend || x;
4227     debug(F101,"sfile x","",x);
4228     debug(F101,"sfile notafile","",notafile);
4229
4230 #ifndef NOCSETS
4231     if (tcs_save > -1) {                /* Character sets */
4232         tcharset = tcs_save;
4233         tcs_save = -1;
4234         debug(F101,"sfile restored tcharset","",tcharset);
4235     }
4236     if (fcs_save > -1) {
4237         fcharset = fcs_save;
4238         fcs_save = -1;
4239         debug(F101,"sfile restored fcharset","",fcharset);
4240     }
4241     setxlatype(tcharset,fcharset);      /* Translation type */
4242 #endif /* NOCSETS */
4243
4244     /* cmarg2 or filnam (with that precedence) have the file's name */
4245
4246     lsstate = 0;                        /* Cancel locking-shift state */
4247 #ifdef COMMENT
4248     /* Do this after making sure we can open the file */
4249     if (nxtpkt() < 0) return(0);        /* Bump packet number, get buffer */
4250 #endif /* COMMENT */
4251     pktnam[0] = NUL;                    /* Buffer for name we will send */
4252     if (x == 0) {                       /* F-Packet setup */
4253         if (!cmarg2) cmarg2 = "";
4254 #ifdef DEBUG
4255         if (deblog) {
4256             /* debug(F111,"sfile cmarg2",cmarg2,cmarg2); */
4257             debug(F101,"sfile binary 1","",binary);
4258             debug(F101,"sfile wearealike","",wearealike);
4259             debug(F101,"sfile xfermode","",xfermode);
4260             debug(F101,"sfile filepeek","",filepeek);
4261 #ifndef NOCSETS
4262             debug(F101,"sfile s_cset","",s_cset);
4263             debug(F101,"sfile tcharset","",tcharset);
4264             debug(F101,"sfile xfrxla","",xfrxla);
4265 #endif /* NOCSETS */
4266         }
4267 #endif /* DEBUG */
4268         if (xfermode == XMODE_A         /* TRANSFER MODE AUTOMATIC */
4269 #ifndef NOMSEND
4270             && !addlist                 /* And not working from a SEND-LIST */
4271 #endif /* NOMSEND */
4272             ) {
4273             /* Other Kermit is on a like system and no charset translation */
4274             if (wearealike
4275 #ifndef NOCSETS
4276                 && (tcharset == TC_TRANSP || xfrxla == 0)
4277 #endif /* NOCSETS */
4278                 ) {
4279 #ifdef VMS
4280                 if (binary != XYFT_I)
4281 #endif /* VMS */
4282 #ifdef CK_LABELED
4283                   if (binary != XYFT_L)
4284 #endif /* CK_LABELED */
4285                     binary = XYFT_B;    /* Send all files in binary mode */
4286             }
4287
4288             /* Otherwise select transfer mode based on file info */
4289
4290             else if (!notafile          /* but not if sending from pipe */
4291 #ifdef CK_LABELED
4292                      && binary != XYFT_L /* and not if FILE TYPE LABELED */
4293 #endif /* CK_LABELED */
4294 #ifdef VMS
4295                      && binary != XYFT_I /* or FILE TYPE IMAGE */
4296 #endif /* VMS */
4297                      ) {
4298 #ifdef UNICODE
4299                 fileorder = -1;         /* File byte order */
4300 #endif /* UNICODE */
4301                 if (filepeek && !notafile) { /* Real file, FILE SCAN is ON */
4302                     int k, x;
4303                     k = scanfile(filnam,&x,nscanfile); /* Scan the file */
4304                     debug(F101,"sfile scanfile","",k);
4305                     switch (k) {
4306                       case FT_TEXT:     /* Unspecified text */
4307                         debug(F100,"sfile scanfile text","",0);
4308                         binary = XYFT_T; /* SET FILE TYPE TEXT */
4309                         break;
4310 #ifndef NOCSETS
4311                       case FT_7BIT:             /* 7-bit text */
4312                         binary = XYFT_T;        /* SET FILE TYPE TEXT */
4313                         /* If SEND CHARSET-SELECTION AUTO  */
4314                         /* and SET TRANSFER TRANSLATION is ON */
4315                         debug(F100,"sfile scanfile text7","",0);
4316                         if (s_cset == XMODE_A && xfrxla) {
4317                             if (fcsinfo[fcharset].size != 128) {
4318                                 fcs_save = fcharset; /* Current FCS not 7bit */
4319                                 fcharset = dcset7;   /* Use default 7bit set */
4320                                 debug(F101,"sfile scanfile 7 fcharset",
4321                                       "",fcharset);
4322                             }
4323                             /* And also switch to appropriate TCS */
4324                             if (afcset[fcharset] > -1 &&
4325                                 afcset[fcharset] <= MAXTCSETS) {
4326                                 tcs_save = tcharset;
4327                                 tcharset = afcset[fcharset];
4328                                 debug(F101,"sfile scanfile 7 tcharset","",
4329                                       tcharset);
4330                             }
4331                             setxlatype(tcharset,fcharset);
4332                         }
4333                         break;
4334
4335                       case FT_8BIT:     /* 8-bit text */
4336                         binary = XYFT_T; /* SET FILE TYPE TEXT */
4337                         /* If SEND CHARSET-SELEC AUTO  */
4338                         /* and SET TRANSFER TRANSLATION is ON */
4339                         debug(F100,"sfile scanfile text8","",0);
4340                         if (s_cset == XMODE_A && xfrxla) {
4341                             if (fcsinfo[fcharset].size != 256) {
4342                                 fcs_save = fcharset; /* Current FCS not 8bit */
4343                                 fcharset = dcset8; /* Use default 8bit set */
4344                                 debug(F101,"sfile scanfile 8 fcharset",
4345                                       "",fcharset);
4346                             }
4347                             /* Switch to corresponding transfer charset */
4348                             if (afcset[fcharset] > -1 &&
4349                                 afcset[fcharset] <= MAXTCSETS) {
4350                                 tcs_save = tcharset;
4351                                 tcharset = afcset[fcharset];
4352                                 debug(F101,"sfile scanfile 8 tcharset","",
4353                                       tcharset);
4354                             }
4355                             setxlatype(tcharset,fcharset);
4356                         }
4357                         break;
4358 #ifdef UNICODE
4359                       case FT_UTF8:     /* UTF-8 text */
4360                       case FT_UCS2:     /* UCS-2 text */
4361                         debug(F101,"sfile scanfile Unicode","",k);
4362                         binary = XYFT_T;
4363                         /* If SEND CHARSET-SELEC AUTO  */
4364                         /* and SET TRANSFER TRANSLATION is ON */
4365                         if (s_cset == XMODE_A && xfrxla) {
4366                             fcs_save = fcharset;
4367                             tcs_save = tcharset;
4368                             fcharset = (k == FT_UCS2) ? FC_UCS2 : FC_UTF8;
4369                             if (k == FT_UCS2 && x > -1)
4370                               fileorder = x;
4371                         }
4372                         /* Switch to associated transfer charset if any */
4373                         if (afcset[fcharset] > -1 &&
4374                             afcset[fcharset] <= MAXTCSETS)
4375                           tcharset = afcset[fcharset];
4376                         if (tcharset == TC_TRANSP) /* If none */
4377                           tcharset = TC_UTF8;      /* use UTF-8 */
4378                         setxlatype(tcharset,fcharset);
4379                         debug(F101,"sfile Unicode tcharset","",tcharset);
4380                         break;
4381 #endif /* UNICODE */
4382 #endif /* NOCSETS */
4383                       case FT_BIN:
4384                         debug(F101,"sfile scanfile binary","",k);
4385                         binary = XYFT_B;
4386                         break;
4387                     /* Default: Don't change anything */
4388                     }
4389                 }
4390             }
4391             debug(F101,"sfile binary 2","",binary);
4392             debug(F101,"sfile sendmode","",sendmode);
4393         }
4394         if (*cmarg2) {                  /* If we have a send-as name... */
4395             int y; char *s;
4396 #ifndef NOSPL                           /* and a script programming language */
4397             extern int cmd_quoting;
4398             if (cmd_quoting) {          /* and it's not turned off */
4399                 y = PKTNL;              /* pass as-name thru the evaluator */
4400                 s = pktnam;
4401                 zzstring(cmarg2,&s,&y);
4402 #ifdef COMMENT
4403 /* This ruins macros like BSEND */
4404                 if (!pktnam[0])         /* and make sure result is not empty */
4405                   sprintf(pktnam,"FILE%02ld",filcnt);
4406 #endif /* COMMENT */
4407             } else
4408 #endif /* NOSPL */
4409               ckstrncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */
4410
4411             debug(F110,"sfile pktnam",pktnam,0);
4412 #ifdef COMMENT
4413 /* We don't do this any more because now we have filename templates */
4414             cmarg2 = "";                /* and blank it out for next time. */
4415 #endif /* COMMENT */
4416         }
4417         if (!*pktnam) {                 /* No as-name... */
4418 #ifdef NZLTOR
4419             int xfncnv, xpath;
4420             debug(F101,"sfile fnspath","",fnspath);
4421             debug(F101,"sfile fncnv","",fncnv);
4422             xfncnv = fncnv;
4423             xpath = fnspath;
4424             if (notafile) {             /* If not an actual file */
4425                 xfncnv = 0;             /* Don't convert name */
4426                 xpath = PATH_OFF;       /* Leave path off */
4427             } else if (xfncnv &&
4428                        (!strcmp(whoareu,"U1") || !strcmp(whoareu,"UN"))
4429                        ) {
4430                 /* Less-strict conversion if partner is UNIX or Win32 */
4431                 xfncnv = -1;
4432             }
4433             debug(F101,"sfile xpath","",xpath);
4434             debug(F101,"sfile xfncnv","",xfncnv);
4435             nzltor(filnam,pktnam,xfncnv,xpath,PKTNL);
4436
4437 #else  /* Not NZLTOR */
4438
4439             debug(F101,"sfile fnspath","",fnspath);
4440             if (fnspath == PATH_OFF     /* Stripping path names? */
4441                 && (!notafile)          /* (of actual files) */
4442                 ) {
4443                 char *t;                /* Yes. */
4444                 zstrip(filnam,&t);      /* Strip off the path. */
4445                 debug(F110,"sfile zstrip",t,0);
4446                 if (!t) t = "UNKNOWN";  /* Be cautious... */
4447                 else if (*t == '\0')
4448                   t = "UNKNOWN";
4449                 ckstrncpy(pktnam,t,PKTNL); /* Copy stripped name literally. */
4450             } else if (fnspath == PATH_ABS && !notafile) {
4451                 /* Converting to absolute form */
4452                 zfnqfp(filnam,PKTNL,pktnam);
4453             } else
4454                 ckstrncpy(pktnam,filnam,PKTNL);
4455
4456             /* pktnam[] has the packet name, filnam[] has the original name. */
4457             /* But we still need to convert pktnam if FILE NAMES CONVERTED.  */
4458
4459             debug(F101,"sfile fncnv","",fncnv);
4460             if (fncnv && !notafile) {   /* If converting names of files */
4461                 zltor(pktnam,(char *)srvcmd); /* convert it to common form, */
4462                 ckstrncpy(pktnam,(char *)srvcmd,PKTNL);
4463                 *srvcmd = NUL;
4464             }
4465 #endif /* NZLTOR */
4466         }
4467         if (!*pktnam)                   /* Failsafe... */
4468           sprintf(pktnam,"FILE%02ld",filcnt);
4469         debug(F110,"sfile filnam 1",filnam,0);
4470         debug(F110,"sfile pktnam 1",pktnam,0);
4471 #ifdef PIPESEND
4472 /* If we have a send filter, substitute the current filename into it */
4473
4474         if (sndfilter) {
4475             char * p = NULL, * q;
4476             int n = CKMAXPATH;
4477 #ifndef NOSPL
4478             if ((p = (char *) malloc(n + 1))) {
4479                 q = p;
4480                 debug(F110,"sfile pipesend filter",sndfilter,0);
4481                 zzstring(sndfilter,&p,&n);
4482                 debug(F111,"sfile pipename",q,n);
4483                 if (n <= 0) {
4484                     printf(
4485                           "?Sorry, send filter + filename too long, %d max.\n",
4486                            CKMAXPATH
4487                            );
4488                     free(q);
4489                     return(0);
4490                 }
4491                 ckstrncpy(filnam,q,CKMAXPATH+1);
4492                 free(q);
4493             }
4494 #endif /* NOSPL */
4495         }
4496 #endif /* PIPESEND */
4497
4498         debug(F110,"sfile filnam 2",filnam,0); /* Log debugging info */
4499         debug(F110,"sfile pktnam 2",pktnam,0);
4500         if (openi(filnam) == 0)         /* Try to open the input file */
4501           return(0);
4502
4503 #ifdef CK_RESEND
4504 /*
4505   The following check is done after openi() is called, since openi() itself
4506   can change the transfer mode (as in VMS).
4507 */
4508         if ((binary == XYFT_T
4509 #ifdef VMS
4510              || binary == XYFT_L
4511 #endif /* VMS */
4512              ) && sendmode == SM_RESEND) {
4513             /* Trying to RESEND/REGET a file first sent in TEXT mode. */
4514             debug(F111,"sfile error - Recover vs Text",filnam,binary);
4515             /* Set appropriate error messages and make log entries here */
4516 #ifdef VMS
4517             if (binary == XYFT_L)
4518               ckmakmsg((char *)epktmsg,
4519                        PKTMSGLEN,
4520                        "Recovery attempted in LABELED mode: ",
4521                        filnam,
4522                        NULL,
4523                        NULL
4524                        );
4525             else
4526 #endif /* VMS */
4527               ckmakmsg((char *)epktmsg,
4528                        PKTMSGLEN,
4529                        "Recovery attempted in TEXT mode: ",
4530                        filnam,
4531                        NULL,
4532                        NULL
4533                        );
4534             return(0);
4535         }
4536         if (sendmode == SM_PSEND)       /* PSENDing? */
4537           if (sendstart > (CK_OFF_T)0)  /* Starting position */
4538             if (zfseek(sendstart) < 0)  /* seek to it... */
4539               return(0);
4540 #endif /* CK_RESEND */
4541         s = pktnam;                     /* Name for packet data field */
4542 #ifdef OS2
4543         /* Never send a disk letter. */
4544         if (isalpha(*s) && (*(s+1) == ':'))
4545           s += 2;
4546 #endif /* OS2 */
4547
4548     } else {                            /* X-packet setup, not F-packet. */
4549         binary = XYFT_T;                /* Text always */
4550         debug(F110,"sfile X packet",cmdstr,0); /* Log debugging info */
4551         s = cmdstr;                     /* Name for data field */
4552     }
4553
4554     /* Now s points to the string that goes in the packet data field. */
4555
4556     debug(F101,"sfile binary","",binary); /* Log debugging info */
4557     encstr((CHAR *)s);                  /* Encode the name. */
4558                                         /* Send the F or X packet */
4559     /* If the encoded string did not fit into the packet, it was truncated. */
4560
4561     if (nxtpkt() < 0) return(0);        /* Bump packet number, get buffer */
4562
4563     rc = spack((char) (x ? 'X' : 'F'), pktnum, size, data);
4564     if (rc < 0)
4565       return(rc);
4566
4567 #ifndef NOCSETS
4568     setxlatype(tcharset,fcharset);      /* Set up charset translations */
4569 #endif /* NOCSETS */
4570
4571     if (x == 0) {                       /* Display for F packet */
4572         if (displa) {                   /* Screen */
4573             xxscreen(SCR_FN,'F',(long)pktnum,filnam);
4574             xxscreen(SCR_AN,0,0L,pktnam);
4575             xxscreen(SCR_FS,0,calibrate ? calibrate : fsize,"");
4576         }
4577 #ifdef pdp11
4578         tlog(F110,"Sending",filnam,0L); /* Transaction log entry */
4579         makestr(&psfspec,filnam);       /* New filename */
4580 #else
4581 #ifndef ZFNQFP
4582         tlog(F110,"Sending",filnam,0L);
4583         makestr(&psfspec,filnam);       /* New filename */
4584 #else
4585         if (notafile) {                 /* If not a file log simple name */
4586             tlog(F110,"Sending", filnam, 0L);
4587         } else {                        /* Log fully qualified filename */
4588 #ifdef COMMENT
4589             /* This section generates bad code in SCO 3.2v5.0.5's cc */
4590             char *p = NULL, *q = filnam;
4591             debug(F101,"sfile CKMAXPATH","",CKMAXPATH);
4592             if ((p = malloc(CKMAXPATH+1))) {
4593                 debug(F111,"sfile calling zfnqfp",filnam,strlen(filnam));
4594                 if (zfnqfp(filnam, CKMAXPATH, p)) {
4595                     debug(F111,"sfile zfnqfp ok",p,strlen(p));
4596                     q = p;
4597                 }
4598             }
4599 #else
4600             char tmpbuf[CKMAXPATH+1];
4601             char *p = tmpbuf, *q = filnam;
4602             if (zfnqfp(filnam, CKMAXPATH, p))
4603               q = p;
4604 #endif /* COMMENT */
4605             debug(F111,"sfile q",q,strlen(q));
4606             tlog(F110,"Sending",q,0L);
4607             makestr(&psfspec,q);        /* New preliminary filename */
4608 #ifdef COMMENT
4609             if (p) free(p);
4610 #endif /* COMMENT */
4611         }
4612 #endif /* ZFNQFP */
4613 #endif /* pdp11 */
4614         tlog(F110," as",pktnam,0L);
4615         if (binary) {                   /* Log file mode in transaction log */
4616             tlog(F101," mode: binary","",(long) binary);
4617         } else {                        /* If text mode, check character set */
4618             tlog(F100," mode: text","",0L);
4619 #ifndef NOCSETS
4620             if (tcharset == TC_TRANSP || xfrxla == 0) {
4621                 tlog(F110," character set","transparent",0L);
4622             } else {
4623                 tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
4624                 tlog(F110," file character set",fcsinfo[fcharset].name,0L);
4625             }
4626 #endif /* NOCSETS */
4627         }
4628     } else {                            /* Display for X-packet */
4629
4630         xxscreen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */
4631         tlog(F110,"Sending from:",cmdstr,0L);   /* Transaction log */
4632     }
4633     intmsg(++filcnt);                   /* Count file, give interrupt msg */
4634     first = 1;                          /* Init file character lookahead. */
4635     ffc = (CK_OFF_T)0;                  /* Init file character counter. */
4636     cps = oldcps = 0L;                  /* Init cps statistics */
4637     rejection = -1;
4638     fsecs = gtimer();                   /* Time this file started */
4639 #ifdef GFTIMER
4640     fpfsecs = gftimer();
4641     debug(F101,"SFILE fpfsecs","",fpfsecs);
4642 #endif /* GFTIMER */
4643     debug(F101,"SFILE fsecs","",fsecs);
4644     return(1);
4645 }
4646
4647 /*  S D A T A -- Send a data packet */
4648
4649 /*
4650   Returns -1 if no data to send (end of file), -2 if connection is broken.
4651   If there is data, a data packet is sent, and sdata() returns 1.
4652
4653   In the streaming case, the window is regarded as infinite and we keep
4654   sending data packets until EOF or there appears to be a Kermit packet on the
4655   reverse channel.  When not streaming and the window size is greater than 1,
4656   we keep sending data packets until window is full or characters start to
4657   appear from the other Kermit.
4658
4659   In the windowing or streaming case, when there is no more data left to send
4660   (or when sending has been interrupted), sdata() does nothing and returns 0
4661   each time it is called until the acknowledgement sequence number catches up
4662   to the last data packet that was sent.
4663 */
4664 int
4665 sdata() {
4666     int i, x, len;
4667     char * s;
4668
4669     debug(F101,"sdata entry, first","",first);
4670     debug(F101,"sdata drain","",drain);
4671 /*
4672   The "drain" flag is used with window size > 1.  It means we have sent
4673   our last data packet.  If called and drain is not zero, then we return
4674   0 as if we had sent an empty data packet, until all data packets have
4675   been ACK'd, then then we can finally return -1 indicating EOF, so that
4676   the protocol can switch to seof state.  This is a kludge, but at least
4677   it's localized...
4678 */
4679     if (first == 1) drain = 0;          /* Start of file, init drain flag. */
4680
4681     if (drain) {                        /* If draining... */
4682         debug(F101,"sdata draining, winlo","",winlo);
4683         if (winlo == pktnum)            /* If all data packets are ACK'd */
4684           return(-1);                   /* return EOF indication */
4685         else                            /* otherwise */
4686           return(0);                    /* pretend we sent a data packet. */
4687     }
4688     debug(F101,"sdata sbufnum","",sbufnum);
4689     for (i = sbufnum;
4690          i > 0
4691 #ifdef STREAMING
4692          || streaming
4693 #endif /* STREAMING */
4694          ;
4695          i--) {
4696         if (i < 0)
4697           break;
4698         debug(F101,"sdata countdown","",i);
4699 #ifdef STREAMING
4700         if (streaming) {
4701             pktnum = (pktnum + 1) % 64;
4702             winlo = pktnum;
4703             debug(F101,"sdata streaming pktnum","",pktnum);
4704         } else {
4705 #endif /* STREAMING */
4706             x = nxtpkt();               /* Get next pkt number and buffer */
4707             debug(F101,"sdata nxtpkt pktnum","",pktnum);
4708             if (x < 0) return(0);
4709 #ifdef STREAMING
4710         }
4711 #endif /* STREAMING */
4712         debug(F101,"sdata packet","",pktnum);
4713         if (chkint() < 0)               /* Especially important if streaming */
4714           return(-9);
4715         if (cxseen || czseen) {         /* If interrupted, done. */
4716             if (wslots > 1) {
4717                 drain = 1;
4718                 debug(F100,"sdata cx/zseen windowing","",0);
4719                 return(0);
4720             } else {
4721                 debug(F100,"sdata cx/zseen nonwindowing","",0);
4722                 return(-1);
4723             }
4724         }
4725 #ifdef DEBUG
4726         if (deblog) {
4727             debug(F101,"sdata spsiz","",spsiz);
4728             debug(F101,"sdata binary","",binary);
4729             debug(F101,"sdata parity","",parity);
4730         }
4731 #endif /* DEBUG */
4732 #ifdef CKTUNING
4733         if (binary && !parity && !memstr && !funcstr)
4734           len = bgetpkt(spsiz);
4735         else
4736           len = getpkt(spsiz,1);
4737 #else
4738         len = getpkt(spsiz,1);
4739 #endif /* CKTUNING */
4740         s = (char *)data;
4741         if (len == -3) {                /* Timed out (e.g.reading from pipe) */
4742             s = "";                     /* Send an empty data packet. */
4743             len = 0;
4744         } else if (len == 0) {          /* Done if no data. */
4745             if (pktnum == winlo)
4746               return(-1);
4747             drain = 1;                  /* But can't return -1 until all */
4748             debug(F101,"sdata eof, drain","",drain);
4749             return(0);                  /* ACKs are drained. */
4750         }
4751         debug(F101,"sdata pktnum","",pktnum);
4752         debug(F101,"sdata len","",len);
4753         debug(F011,"sdata data",data,52);
4754
4755         x = spack('D',pktnum,len,(CHAR *)s); /* Send the data packet. */
4756         debug(F101,"sdata spack","",x);
4757         if (x < 0) {                    /* Error */
4758             ttchk();                    /* See if connection is still there */
4759             return(-2);
4760         }
4761 #ifdef STREAMING
4762         if (streaming)                  /* What an ACK would do. */
4763           winlo = pktnum;
4764 #endif /* STREAMING */
4765         x = ttchk();                    /* Peek at input buffer. */
4766         debug(F101,"sdata ttchk","",x); /* ACKs waiting, maybe?  */
4767         if (x < 0)                      /* Or connection broken? */
4768           return(-2);
4769 /*
4770   Here we check to see if any ACKs or NAKs have arrived, in which case we
4771   break out of the D-packet-sending loop and return to the state switcher
4772   to process them.  This is what makes our windows slide instead of lurch.
4773 */
4774         if (
4775 #ifdef GEMDOS
4776 /*
4777   In the Atari ST version, ttchk() can only return 0 or 1.  But note: x will
4778   probably always be > 0, since the as-yet-unread packet terminator from the
4779   last packet is probably still in the buffer, so sliding windows will
4780   probably never happen when the Atari ST is the file sender.  The alternative
4781   is to say "if (0)", in which case the ST will always send a window full of
4782   packets before reading any ACKs or NAKs.
4783 */
4784             x > 0
4785
4786 #else /* !GEMDOS */
4787 /*
4788   In most other versions, ttchk() returns the actual count.
4789   It can't be a Kermit packet if it's less than five bytes long.
4790 */
4791             x > 4 + bctu
4792
4793 #endif /* GEMDOS */
4794             )
4795           return(1);                    /* Yes, stop sending data packets */
4796     }                                   /* and go try to read the ACKs. */
4797     return(1);
4798 }
4799
4800
4801 /*  S E O F -- Send an End-Of-File packet */
4802
4803 /*  Call with a string pointer to character to put in the data field, */
4804 /*  or else a null pointer or "" for no data.  */
4805
4806 /*
4807   There are two "send-eof" functions.  seof() is used to send the normal eof
4808   packet at the end of a file's data (even if the file has no data), or when
4809   a file transfer is interrupted.  sxeof() is used to send an EOF packet that
4810   occurs because of attribute refusal or interruption prior to entering data
4811   state.  The difference is purely a matter of buffer allocation and packet
4812   sequence number management.  Both functions act as "front ends" to the
4813   common send-eof function, szeof().
4814 */
4815
4816 /* Code common to both seof() and sxeof() */
4817
4818 int
4819 szeof(s) CHAR *s; {
4820     int x;
4821     lsstate = 0;                        /* Cancel locking-shift state */
4822     if (!s) s = (CHAR *)"";
4823     debug(F111,"szeof",s,pktnum);
4824     if (*s) {
4825         x = spack('Z',pktnum,1,s);
4826         xitsta |= W_SEND;
4827 #ifdef COMMENT
4828         tlog(F100," *** interrupted, sending discard request","",0L);
4829 #endif /* COMMENT */
4830         filrej++;
4831     } else {
4832         x = spack('Z',pktnum,0,(CHAR *)"");
4833     }
4834     if (x < 0)
4835       return(x);
4836
4837 #ifdef COMMENT
4838     /* No, too soon */
4839     discard = 0;                        /* Turn off per-file discard flag */
4840 #endif /* COMMENT */
4841
4842 /* If we were sending from a pipe, we're not any more... */
4843     pipesend = 0;
4844     return(0);
4845 }
4846
4847 int
4848 seof(x) int x; {
4849     char * s;
4850 /*
4851   ckcpro.w, before calling seof(), sets window size back to 1 and then calls
4852   window(), which clears out the old buffers.  This is OK because the final
4853   data packet for the file has been ACK'd.  However, sdata() has already
4854   called nxtpkt(), which set the new value of pktnum which seof() will use.
4855   So all we need to do here is is allocate a new send-buffer.
4856 */
4857     s = x ? "D" : "";
4858     debug(F111,"seof",s,pktnum);
4859     if (getsbuf(pktnum) < 0) {  /* Get a buffer for packet n */
4860         debug(F101,"seof can't get s-buffer","",pktnum);
4861         return(-1);
4862     }
4863     return(szeof((CHAR *)s));
4864 }
4865
4866 /*
4867   Version of seof() to be called when sdata() has not been called before.  The
4868   difference is that this version calls nxtpkt() to allocate a send-buffer and
4869   get the next packet number.
4870 */
4871 int
4872 sxeof(x) int x; {
4873     char * s;
4874     s = x ? "D" : "";
4875     if (nxtpkt() < 0)                   /* Get next pkt number and buffer */
4876       debug(F101,"sxeof nxtpkt fails","",pktnum);
4877     else
4878       debug(F101,"sxeof packet","",pktnum);
4879     return(szeof((CHAR *)s));
4880 }
4881
4882 /*  S E O T -- Send an End-Of-Transaction packet */
4883
4884 int
4885 seot() {
4886     int x;
4887     x = nxtpkt();
4888     debug(F101,"seot nxtpkt","",x);
4889     if (x < 0) return(-1);              /* Bump packet number, get buffer */
4890     x = spack('B',pktnum,0,(CHAR *)""); /* Send the EOT packet */
4891     if (x < 0)
4892       return(x);
4893     cxseen = czseen = discard = 0;      /* Reset interruption flags */
4894     tstats();                           /* Log timing info */
4895     return(0);
4896 }
4897
4898
4899 /*   R P A R -- Fill the data array with my send-init parameters  */
4900
4901 int q8flag = 0;
4902
4903 CHAR dada[32];                          /* Use this instead of data[]. */
4904                                         /* To avoid some kind of wierd */
4905                                         /* addressing foulup in spack()... */
4906                                         /* (which might be fixed now...) */
4907
4908 CHAR *
4909 rpar() {
4910     char *p;
4911     int i, x, max;
4912     extern int sprmlen;
4913
4914     max = maxdata();                    /* Biggest data field I can send */
4915     debug(F101, "rpar max 1","",max);
4916     debug(F101, "rpar sprmlen","",sprmlen);
4917     if (sprmlen > 1 && sprmlen < max)   /* User override */
4918       max = sprmlen;
4919     debug(F101, "rpar max 2","",max);
4920
4921     if (rpsiz > MAXPACK)                /* Biggest normal packet I want. */
4922       dada[0] = (char) tochar(MAXPACK); /* If > 94, use 94, but specify */
4923     else                                /* extended packet length below... */
4924       dada[0] = (char) tochar(rpsiz);   /* else use what the user said. */
4925     dada[1] = (char) tochar(chktimo(pkttim,0)); /* When to time me out */
4926     dada[2] = (char) tochar(mypadn);    /* How much padding I need (none) */
4927     dada[3] = (char) ctl(mypadc);       /* Padding character I want */
4928     dada[4] = (char) tochar(eol);       /* End-Of-Line character I want */
4929     dada[5] = myctlq;                   /* Control-Quote character I send */
4930
4931     if (max < 6) { dada[6] = NUL; rqf = 0; ebq = sq = NUL; return(dada); }
4932
4933     switch (rqf) {                      /* 8th-bit prefix (single-shift) */
4934       case -1:                          /* I'm opening the bids */
4935       case  1:                          /* Other Kermit already bid 'Y' */
4936         if (parity) ebq = sq = MYEBQ;   /* So I reply with '&' if parity */
4937         break;                          /*  otherwise with 'Y'. */
4938       case  2:                          /* Other Kermit sent a valid prefix */
4939         if (q8flag)
4940           sq = ebq;                     /* Fall through on purpose */
4941       case  0:                          /* Other Kermit bid nothing */
4942         break;                          /* So I reply with 'Y'. */
4943     }
4944     debug(F000,"rpar 8bq sq","",sq);
4945     debug(F000,"rpar 8bq ebq","",ebq);
4946     if (lscapu == 2)                    /* LOCKING-SHIFT FORCED */
4947       dada[6] = 'N';                    /* requires no single-shift */
4948     else                                /* otherwise send prefix or 'Y' */
4949       dada[6] = (char) sq;
4950     ebqsent = dada[6];                  /* And remember what I really sent */
4951
4952     if (max < 7) { dada[7] = NUL; bctr = 1; return(dada); }
4953
4954     dada[7] = (char) (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */
4955
4956     if (max < 8) { dada[8] = NUL; rptflg = 0; return(dada); }
4957
4958     if (rptena) {
4959         if (rptflg)                     /* Run length encoding */
4960           dada[8] = (char) rptq;        /* If receiving, agree */
4961         else                            /* by replying with same character. */
4962           dada[8] = (char) (rptq = myrptq); /* When sending use this. */
4963     } else dada[8] = SP;                /* Not enabled, put a space here. */
4964
4965     /* CAPAS mask */
4966
4967     if (max < 9) {
4968         dada[9] = NUL;
4969         atcapr = 0;
4970         lpcapr = 0;
4971         swcapr = 0;
4972         rscapr = 0;
4973         return(dada);
4974     }
4975     dada[9] = (char) tochar((lscapr ? lscapb : 0) | /* Locking shifts */
4976                      (atcapr ? atcapb : 0) | /* Attribute packets */
4977                      (lpcapr ? lpcapb : 0) | /* Long packets */
4978                      (swcapr ? swcapb : 0) | /* Sliding windows */
4979                      (rscapr ? rscapb : 0)); /* RESEND */
4980     if (max < 10) { wslotr = 1; return(dada); }
4981     dada[10] = (char) tochar(swcapr ? wslotr : 1); /* CAPAS+1 = Window size */
4982
4983     if (max < 12) { rpsiz = 80; return(dada); }
4984     if (urpsiz > 94)
4985       rpsiz = urpsiz - 1;               /* Long packets ... */
4986     dada[11] = (char) tochar(rpsiz / 95); /* Long packet size, big part */
4987     dada[12] = (char) tochar(rpsiz % 95); /* Long packet size, little part */
4988
4989     if (max < 16) return(dada);
4990     dada[13] = '0';                     /* CAPAS+4 = WONT CHKPNT */
4991     dada[14] = '_';                     /* CAPAS+5 = CHKINT (reserved) */
4992     dada[15] = '_';                     /* CAPAS+6 = CHKINT (reserved) */
4993     dada[16] = '_';                     /* CAPAS+7 = CHKINT (reserved) */
4994     if (max < 17) return(dada);
4995 #ifndef WHATAMI
4996     dada[17] = ' ';
4997 #else
4998     x = 0;
4999     if (server) x |= WMI_SERVE;         /* Whether I am a server */
5000     if (binary) x |= WMI_FMODE;         /* My file transfer mode is ... */
5001     if (fncnv)  x |= WMI_FNAME;         /* My filename conversion is ... */
5002 #ifdef STREAMING
5003     if (streamrq == SET_ON)
5004       x |= WMI_STREAM;
5005     else if (streamrq == SET_AUTO && reliable == SET_ON)
5006       x |= WMI_STREAM;
5007     /*
5008       Always offer to stream when in remote mode and STREAMING is AUTO
5009       and RELIABLE is not OFF (i.e. is ON or AUTO).
5010     */
5011     else if (!local && streamrq == SET_AUTO && reliable != SET_OFF)
5012       x |= WMI_STREAM;
5013 #endif /* STREAMING */
5014 #ifdef TCPSOCKET
5015     if (clearrq == SET_ON)
5016       x |= WMI_CLEAR;
5017     else if (clearrq == SET_AUTO &&     /* SET CLEAR-CHANNEL AUTO */
5018              ((network && nettype == NET_TCPB /* TCP/IP */
5019 #ifdef RLOGCODE
5020                 && ttnproto != NP_RLOGIN/* Rlogin is not clear */
5021                 && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN)
5022 #endif /* RLOGCODE */
5023                )
5024 #ifdef SSHBUILTIN
5025               || (network && nettype == NET_SSH)
5026 #endif /* SSHBUILTIN */
5027 #ifdef IKSD
5028               || inserver               /* We are IKSD */
5029 #endif /* IKSD */
5030               ))
5031       x |= WMI_CLEAR;
5032 #endif /* TCPSOCKET */
5033     x |= WMI_FLAG;
5034     dada[17] = (char) tochar(x);
5035 #endif /* WHATAMI */
5036     i = 18;                             /* Position of next field */
5037     p = cksysid;                        /* WHOAMI (my system ID) */
5038     x = strlen(p);
5039     if (max - i < x + 1) return(dada);
5040     if (x > 0) {
5041         dada[i++] = (char) tochar(x);
5042         while (*p)
5043           dada[i++] = *p++;
5044     }
5045
5046     if (max < i+1) return(dada);
5047 #ifndef WHATAMI                         /* WHATAMI2 */
5048     dada[i++] = ' ';
5049 #else
5050     debug(F101,"rpar xfermode","",xfermode);
5051     x = WMI2_FLAG;                      /* Is-Valid flag */
5052     if (xfermode != XMODE_A)            /* If TRANSFER MODE is MANUAL */
5053       x |= WMI2_XMODE;                  /* set the XFERMODE bit */
5054     if (recursive > 0)                  /* If this is a recursive transfer */
5055       x |= WMI2_RECU;                   /* set the RECURSIVE bit */
5056     dada[i++] = tochar(x);
5057     debug(F101,"rpar whatami2","",x);
5058 #endif /* WHATAMI */
5059
5060     dada[i] = '\0';                     /* Terminate the init string */
5061
5062 #ifdef DEBUG
5063     if (deblog) {
5064         debug(F110,"rpar",dada,0);
5065         rdebu(dada,(int)strlen((char *)dada));
5066     }
5067 #endif /* DEBUG */
5068     ckstrncpy((char *)myinit,(char *)dada,MYINITLEN);
5069     return(dada);                       /* Return pointer to string. */
5070 }
5071
5072 int
5073 spar(s) CHAR *s; {                      /* Set parameters */
5074     int x, y, lpsiz, biggest;
5075     extern int rprmlen, lastspmax;
5076     extern struct sysdata sysidlist[];
5077
5078     whatru = 0;
5079     whoareu[0] = NUL;
5080 #ifdef STREAMING
5081     streamok = 0;
5082     streaming = 0;
5083 #endif /* STREAMING */
5084     biggest = rln;
5085
5086     debug(F101, "spar biggest 1","",biggest);
5087     debug(F101, "spar rprmlen","",rprmlen);
5088     if (rprmlen > 1 && rprmlen < biggest)
5089       biggest = rprmlen;
5090     debug(F101, "rpar biggest 2","",biggest);
5091     debug(F110,"spar packet",s,0);
5092
5093     s--;                                /* Line up with field numbers. */
5094
5095 /* Limit on size of outbound packets */
5096     x = (biggest >= 1) ? xunchar(s[1]) : 80;
5097     lpsiz = spsizr;                     /* Remember what they SET. */
5098     if (spsizf) {                       /* SET-command override? */
5099         if (x < spsizr) spsiz = x;      /* Ignore LEN unless smaller */
5100     } else {                            /* otherwise */
5101         spsiz = (x < 10) ? 80 : x;      /* believe them if reasonable */
5102     }
5103     spmax = spsiz;                      /* Remember maximum size */
5104
5105 /* Timeout on inbound packets */
5106     if (timef) {
5107         timint = rtimo;                 /* SET SEND TIMEOUT value overrides */
5108     } else {                            /* Otherwise use requested value, */
5109         x = (biggest >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */
5110         timint = (x < 0) ? rtimo : x;
5111     }
5112     timint = chktimo(timint,timef);     /* Adjust if necessary */
5113
5114 /* Outbound Padding */
5115     npad = 0; padch = '\0';
5116     if (biggest >= 3) {
5117         npad = xunchar(s[3]);
5118         if (biggest >= 4) padch = (CHAR) ctl(s[4]); else padch = 0;
5119     }
5120     if (npad) {
5121         int i;
5122         for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
5123     }
5124
5125 /* Outbound Packet Terminator */
5126     seol = (CHAR) (biggest >= 5) ? xunchar(s[5]) : CR;
5127     if ((seol < 1) || (seol > 31)) seol = CR;
5128
5129 /* Control prefix that the other Kermit is sending */
5130     x = (biggest >= 6) ? s[6] : '#';
5131     ctlq = (CHAR) (((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#');
5132
5133 /* 8th-bit prefix */
5134 /*
5135   NOTE: Maybe this could be simplified using rcvtyp.
5136   If rcvtyp == 'Y' then we're reading the ACK,
5137   otherwise we're reading the other Kermit's initial bid.
5138   But his horrendous code has been working OK for years, so...
5139 */
5140     rq = (biggest >= 7) ? s[7] : 0;
5141     if (rq == 'Y') rqf = 1;
5142       else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
5143         else rqf = 0;
5144     debug(F000,"spar 8bq rq","",rq);
5145     debug(F000,"spar 8bq sq","",sq);
5146     debug(F000,"spar 8bq ebq","",ebq);
5147     debug(F101,"spar 8bq rqf","",rqf);
5148     switch (rqf) {
5149       case 0:                           /* Field is missing from packet. */
5150         ebqflg = 0;                     /* So no 8th-bit prefixing. */
5151         break;
5152       case 1:                           /* Other Kermit sent 'Y' = Will Do. */
5153         /*
5154           When I am the file receiver, ebqsent is 0 because I didn't send a
5155           negotiation yet.  If my parity is set to anything other than NONE,
5156           either because my user SET PARITY or because I detected parity bits
5157           on this packet, I reply with '&', otherwise 'Y'.
5158
5159           When I am the file sender, ebqsent is what I just sent in rpar(),
5160           which can be 'Y', 'N', or '&'.  If I sent '&', then this 'Y' means
5161           the other Kermit agrees to do 8th-bit prefixing.
5162
5163           If I sent 'Y' or 'N', but then detected parity on the ACK packet
5164           that came back, then it's too late: there is no longer any way for
5165           me to tell the other Kermit that I want to do 8th-bit prefixing, so
5166           I must not do it, and in that case, if there is any 8-bit data in
5167           the file to be transferred, the transfer will fail because of block
5168           check errors.
5169
5170           The following clause covers all of these situations:
5171         */
5172         if (parity && (ebqsent == 0 || ebqsent == '&')) {
5173             ebqflg = 1;
5174             ebq = MYEBQ;
5175         }
5176         break;
5177       case 2:                           /* Other Kermit sent a valid prefix */
5178         ebqflg = (ebq == sq || sq == 'Y');
5179         if (ebqflg) {
5180             ebq = rq;
5181             debug(F101,"spar setting parity to space","",ebq);
5182             if (!parity) parity = ttprty = 's';
5183         }
5184     }
5185     if (lscapu == 2) {     /* But no single-shifts if LOCKING-SHIFT FORCED */
5186         ebqflg = 0;
5187         ebq = 'N';
5188     }
5189
5190 /* Block check */
5191     x = 1;
5192     if (biggest >= 8) {
5193         if (s[8] == 'B') x = 4;
5194         else x = s[8] - '0';
5195         if ((x < 1) || (x > 5)) x = 1;  /* "5" 20110605 */
5196     }
5197     bctr = x;
5198
5199 /* Repeat prefix */
5200
5201     rptflg = 0;                         /* Assume no repeat-counts */
5202     if (biggest >= 9) {                 /* Is there a repeat-count field? */
5203         char t;                         /* Yes. */
5204         t = s[9];                       /* Get its contents. */
5205 /*
5206   If I'm sending files, then I'm reading these parameters from an ACK, and so
5207   this character must agree with what I sent.
5208 */
5209         if (rptena) {                   /* If enabled ... */
5210             if ((char) rcvtyp == 'Y') { /* Sending files, reading ACK. */
5211                 if (t == myrptq) rptflg = 1;
5212             } else {                    /* I'm receiving files */
5213                 if ((t > 32 && t < 63) || (t > 95 && t < 127)) {
5214                     rptflg = 1;
5215                     rptq = t;
5216                 }
5217             }
5218         } else rptflg = 0;
5219     }
5220
5221 /* Capabilities */
5222
5223     atcapu = lpcapu = swcapu = rscapu = 0; /* Assume none of these. */
5224     if (lscapu != 2) lscapu = 0;        /* Assume no LS unless forced. */
5225     y = 11;                             /* Position of next field, if any */
5226     if (biggest >= 10) {
5227         x = xunchar(s[10]);
5228         debug(F101,"spar capas","",x);
5229         atcapu = (x & atcapb) && atcapr; /* Attributes */
5230         lpcapu = (x & lpcapb) && lpcapr; /* Long packets */
5231         swcapu = (x & swcapb) && swcapr; /* Sliding windows */
5232         rscapu = (x & rscapb) && rscapr; /* RESEND */
5233         debug(F101,"spar lscapu","",lscapu);
5234         debug(F101,"spar lscapr","",lscapr);
5235         debug(F101,"spar ebqflg","",ebqflg);
5236         if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0;
5237         debug(F101,"spar swcapr","",swcapr);
5238         debug(F101,"spar swcapu","",swcapu);
5239         debug(F101,"spar lscapu","",lscapu);
5240         for (y = 10; (xunchar(s[y]) & 1) && (biggest >= y); y++);
5241         debug(F101,"spar y","",y);
5242     }
5243
5244 /* Long Packets */
5245     debug(F101,"spar lpcapu","",lpcapu);
5246     if (lpcapu) {
5247         if (biggest > y+1) {
5248             x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
5249             debug(F101,"spar lp len","",x);
5250             if (spsizf) {               /* If overriding negotiations */
5251                 spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
5252             } else {                             /* otherwise */
5253                 spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
5254             }
5255             if (spsiz < 10) spsiz = 80; /* Be defensive... */
5256         }
5257     }
5258     /* (PWP) save current send packet size for optimal packet size calcs */
5259     spmax = spsiz;                      /* Maximum negotiated length */
5260     lastspmax = spsiz;                  /* For stats */
5261     if (slostart && spsiz > 499)        /* Slow start length */
5262       spsiz = 244;
5263     debug(F101,"spar slow-start spsiz","",spsiz);
5264     debug(F101,"spar lp spmax","",spmax);
5265     timint = chktimo(timint,timef);     /* Recalculate the packet timeout */
5266
5267 /* Sliding Windows... */
5268
5269     if (swcapr) {                       /* Only if requested... */
5270         if (biggest > y) {              /* See what other Kermit says */
5271             x = xunchar(s[y+1]);
5272             debug(F101,"spar window","",x);
5273             wslotn = (x > MAXWS) ? MAXWS : x;
5274 /*
5275   wslotn = negotiated size (from other Kermit's S or I packet).
5276   wslotr = requested window size (from this Kermit's SET WINDOW command).
5277 */
5278             if (wslotn > wslotr)        /* Use the smaller of the two */
5279               wslotn = wslotr;
5280             if (wslotn < 1)             /* Watch out for bad negotiation */
5281               wslotn = 1;
5282             if (wslotn > 1) {
5283                 swcapu = 1;             /* We do windows... */
5284                 if (wslotn > maxtry)    /* Retry limit must be greater */
5285                   maxtry = wslotn + 1;  /* than window size. */
5286             }
5287             debug(F101,"spar window after adjustment","",x);
5288         } else {                        /* No window size specified. */
5289             wslotn = 1;                 /* We don't do windows... */
5290             debug(F101,"spar window","",x);
5291             swcapu = 0;
5292             debug(F101,"spar no windows","",wslotn);
5293         }
5294     }
5295
5296 /* Now recalculate packet length based on number of windows.   */
5297 /* The nogotiated number of window slots will be allocated,    */
5298 /* and the maximum packet length will be reduced if necessary, */
5299 /* so that a windowful of packets can fit in the big buffer.   */
5300
5301     if (wslotn > 1) {                   /* Shrink to fit... */
5302         x = adjpkl(spmax,wslotn,bigsbsiz);
5303         if (x < spmax) {
5304             spmax = x;
5305             lastspmax = spsiz;
5306             if (slostart && spsiz > 499) spsiz = 244; /* Slow start again */
5307             debug(F101,"spar sending, redefine spmax","",spmax);
5308         }
5309     }
5310 #ifdef WHATAMI
5311     debug(F101,"spar biggest","",biggest);
5312     if (biggest > y+7) {                /* Get WHATAMI info if any */
5313         whatru = xunchar(s[y+8]);
5314         debug(F101,"spar whatru","",whatru);
5315     }
5316     if (whatru & WMI_FLAG) {            /* Only valid if this bit is set */
5317 #ifdef STREAMING
5318         if (whatru & WMI_STREAM) {
5319             if (streamrq == SET_ON ||
5320                 (streamrq == SET_AUTO &&
5321                  (reliable == SET_ON || (reliable == SET_AUTO && !local)
5322 #ifdef TN_COMPORT
5323                   && !istncomport()
5324 #endif /* TN_COMPORT */
5325 #ifdef IKSD
5326                    || inserver
5327 #endif /* IKSD */
5328                    ))) {
5329                 streamok = 1;           /* Streaming negotiated */
5330                 slostart = 0;           /* Undo slow-start machinations */
5331                 spsiz = lastspmax;
5332             }
5333         }
5334         streamed = streamok;
5335         debug(F101,"spar streamok","",streamok);
5336         debug(F101,"spar clearrq","",clearrq);
5337         if (clearrq == SET_ON ||
5338              (clearrq == SET_AUTO &&
5339                ((network && nettype == NET_TCPB
5340 #ifdef RLOGCODE
5341                 && ttnproto != NP_RLOGIN/* Rlogin is not clear */
5342                 && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN)
5343 #endif /* RLOGCODE */
5344 #ifdef TN_COMPORT
5345                 && !istncomport()
5346 #endif /* TN_COMPORT */
5347                   )
5348 #ifdef SSHBUILTIN
5349                  || (network && nettype == NET_SSH)
5350 #endif /* SSHBUILTIN */
5351 #ifdef IKSD
5352                  || inserver
5353 #endif /* IKSD */
5354                  )))
5355           urclear = (whatru & WMI_CLEAR);
5356         debug(F101,"spar urclear","",urclear);
5357 #ifdef CK_SPEED
5358         if (urclear)
5359           setprefix(PX_NON);
5360 #endif /* CK_SPEED */
5361         cleared = urclear;
5362 #endif /* STREAMING */
5363     }
5364 #endif /* WHATAMI */
5365
5366     if (biggest > y+8) {                /* Get WHOAREYOU info if any */
5367         int x, z;
5368         x = xunchar(s[y+9]);            /* Length of it */
5369         z = y;
5370         y += (9 + x);
5371         debug(F101,"spar sysindex x","",x);
5372         debug(F101,"spar sysindex y","",y);
5373         debug(F101,"spar sysindex biggest","",biggest);
5374
5375         if (x > 0 && x < 16 && biggest >= y) {
5376             strncpy(whoareu,(char *)s+z+10,x); /* Other Kermit's system ID */
5377             debug(F111,"spar whoareyou",whoareu,whoareu[0]);
5378             if (whoareu[0]) {           /* Got one? */
5379                 sysindex = getsysix((char *)whoareu);
5380                 debug(F101,"spar sysindex",whoareu,sysindex);
5381             }
5382         }
5383     } else
5384       goto xspar;
5385
5386 #ifdef WHATAMI
5387     y++;                                /* Advance pointer */
5388     if (biggest >= y) {
5389         whatru2 = xunchar(s[y]);        /* Next field is WHATAMI2 */
5390         debug(F101,"spar whatru2","",whatru2);
5391         if (whatru2 & WMI2_FLAG) {      /* Valid only if this bit is set */
5392             if (server) {               /* Server obeys client's xfer mode */
5393                 xfermode = (whatru2 & WMI2_XMODE) ? XMODE_M : XMODE_A;
5394                 debug(F101,"spar whatru2 xfermode","",xfermode);
5395             }
5396             if (whatru2 & WMI2_RECU) {  /* RECURSIVE transfer */
5397                 if (fnrpath == PATH_AUTO) { /* If REC PATH AUTO */
5398                     fnrpath = PATH_REL; /* Set it to RELATIVE */
5399                     autopath = 1;       /* and remember we did this */
5400                 }
5401             }
5402         }
5403     }
5404 #endif /* WHATAMI */
5405
5406   xspar:
5407     if (sysindex > -1) {
5408         char * p;
5409         p = sysidlist[sysindex].sid_name;
5410         tlog(F110,"Remote system type: ",p,0L);
5411         if (sysindex > 0) {             /* If partnet's system type known */
5412             whoarewe();                 /* see if we are a match. */
5413 #ifdef CK_SPEED
5414 /* Never unprefix XON and XOFF when sending to VMS */
5415             debug(F111,"proto whoareu",whoareu,sysindex);
5416             if (!strcmp((char *)whoareu,"D7")) {
5417                 debug(F111,"proto special VMS prefixing","",0);
5418                 ctlp[XON] = ctlp[XOFF] = 1;
5419                 ctlp[XON+128] = ctlp[XOFF+128] = 1;
5420                 ctlp[3] = 1;            /* Ctrl-C might be dangerous too */
5421                 ctlp[14] = ctlp[15] = 1; /* And SO/SI */
5422                 ctlp[24] = ctlp[25] = 1; /* And ^X/^Y */
5423                 ctlp[141] = 1;          /* And CR+128 */
5424             }
5425 #endif /* CK_SPEED */
5426         }
5427     }
5428
5429 /* Record parameters in debug log */
5430 #ifdef DEBUG
5431     if (deblog) sdebu(biggest);
5432 #endif /* DEBUG */
5433     numerrs = 0;                        /* Start counting errors here. */
5434     return(0);
5435 }
5436
5437 /*  G N F I L E  --  Get name of next file to send  */
5438 /*
5439   Expects global sndsrc to be:
5440    -9: if we are generating a file internally for calibration.
5441    -1: next filename to be obtained by calling znext().
5442     0: no next file name
5443     1: (or greater) next filename to be obtained from **cmlist,
5444        or if addlist != 0, from the "filehead" linked list,
5445        or if filefile pointer not null from that file (which is already open).
5446   Returns:
5447     1, with name of next file in filnam.
5448     0, no more files, with filnam set to empty string.
5449    -1, file not found
5450    -2, file is not readable (but then we just skip to the next one if any)
5451    -3, read access denied
5452    -4, cancelled
5453    -5, too many files match wildcard
5454    -6, no files selected
5455   NOTE:
5456     If gnfile() returns 0, then the global variable gnferror should be checked
5457     to find out the most recent gnfile() error, and use that instead of the
5458     return code (for reasons to hard to explain).
5459 */
5460 int
5461 gnfile() {
5462     int i = 0, x = 0;
5463     CK_OFF_T filesize = 0;
5464     int dodirstoo = 0;
5465     int retcode = 0;
5466
5467     char fullname[CKMAXPATH+1];
5468
5469     dodirstoo = ((what & (W_FTP|W_SEND)) == (W_FTP|W_SEND)) && recursive;
5470
5471     debug(F101,"gnfile sndsrc","",sndsrc);
5472     debug(F101,"gnfile filcnt","",filcnt);
5473     debug(F101,"gnfile what","",what);
5474     debug(F101,"gnfile recursive","",recursive);
5475     debug(F101,"gnfile dodirstoo","",dodirstoo);
5476     gnferror = 0;
5477     fsize = (CK_OFF_T)-1;               /* Initialize file size */
5478     fullname[0] = NUL;
5479
5480 #ifdef VMS
5481     /* 
5482       In VMS, zopeni() sets binary 0/1 automatically from the file
5483       attributes.  Don't undo it here.
5484     */
5485     debug(F101,"gnfile VMS binary","",binary);
5486 #else  /* VMS */
5487     if (!(what & W_REMO) && (xfermode == XMODE_A)
5488 #ifndef NOMSEND
5489         && !addlist
5490 #endif /* NOMSEND */
5491         ) {
5492         extern int stdinf;
5493         if (!stdinf)                    /* Not if sending from stdin */
5494 #ifdef WHATAMI
5495           /* We don't do this in server mode because it undoes WHATAMI */
5496           if (!server || (server && ((whatru & WMI_FLAG) == 0)))
5497 #endif /* WHATAMI */
5498             binary = gnf_binary;        /* Restore prevailing transfer mode */
5499         debug(F101,"gnfile binary = gnf_binary","",gnf_binary);
5500     }
5501 #endif  /* VMS */
5502
5503 #ifdef PIPESEND
5504     debug(F101,"gnfile pipesend","",pipesend);
5505     if (pipesend) {                     /* First one */
5506         if (filcnt == 0) {
5507             ckstrncpy(filnam,cmarg,CKMAXPATH+1);
5508             return(1);
5509         } else {                        /* There's only one... */
5510             *filnam = NUL;
5511             pipesend = 0;
5512             return(0);
5513         }
5514     }
5515 #endif /* PIPESEND */
5516
5517 #ifdef CALIBRATE
5518     if (sndsrc == -9) {
5519         debug(F100,"gnfile calibrate","",0);
5520         ckstrncpy(filnam,"CALIBRATION",CKMAXPATH);
5521         nfils = 0;
5522         cal_j = 0;
5523         fsize = calibrate;
5524         sndsrc = 0;                     /* For next time */
5525         nfils = 0;
5526         return(1);
5527     }
5528 #endif /* CALIBRATE */
5529
5530 #ifndef NOSPL
5531     if (sndarray) {                     /* Sending from an array */
5532         extern char sndxnam[];          /* Pseudo filename */
5533         debug(F100,"gnfile array","",0);
5534         nfils = 0;
5535         fsize = (CK_OFF_T)-1;           /* Size unknown */
5536         sndsrc = 0;
5537         ckstrncpy(filnam,sndxnam,CKMAXPATH);
5538         return(1);
5539     }
5540 #endif /* NOSPL */
5541
5542     if (sndsrc == 0) {                  /* It's not really a file */
5543         if (nfils > 0) {                /* It's a pipe, or stdin */
5544             ckstrncpy(filnam,*cmlist,CKMAXPATH+1); /* Copy its "name" */
5545             nfils = 0;                  /* There is no next file */
5546             return(1);                  /* OK this time */
5547         } else return(0);               /* but not next time */
5548     }
5549
5550 /* If file group interruption (C-Z) occurred, fail.  */
5551
5552     if (czseen) {
5553         tlog(F100,"Transaction cancelled","",0L);
5554         debug(F100,"gnfile czseen","",0);
5555         return(-4);
5556     }
5557
5558 /* Loop through file list till we find a readable, sendable file */
5559
5560     filesize = (CK_OFF_T)-1;            /* Loop exit (file size) variable */
5561     while (filesize < 0) {              /* Keep trying till we get one... */
5562         retcode = 0;
5563         if (sndsrc > 0) {               /* File list in cmlist or file */
5564             if (filefile) {             /* Reading list from file... */
5565                 if (zsinl(ZMFILE,filnam,CKMAXPATH) < 0) { /* Read a line */
5566                     zclose(ZMFILE);                       /* Failed */
5567                     debug(F110,"gnfile filefile EOF",filefile,0);
5568                     makestr(&filefile,NULL);
5569                     return(0);
5570                 }
5571                 debug(F110,"gnfile filefile filnam",filnam,0);
5572             }
5573             debug(F101,"gnfile nfils","",nfils);
5574             if (nfils-- > 0 || filefile) { /* Still some left? */
5575 #ifndef NOMSEND
5576                 if (addlist) {
5577                     if (filenext && filenext->fl_name) {
5578                         ckstrncpy(filnam,filenext->fl_name,CKMAXPATH+1);
5579                         cmarg2 =
5580                           filenext->fl_alias ?
5581                             filenext->fl_alias :
5582                               "";
5583                         binary = filenext->fl_mode;
5584                     } else {
5585                         printf("?Internal error expanding ADD list\n");
5586                         return(-5);
5587                     }
5588                     filenext = filenext->fl_next;
5589                     debug(F111,"gnfile addlist filnam",filnam,nfils);
5590                 } else if (sndsrc > 0 && !filefile) {
5591 #endif /* NOMSEND */
5592                     ckstrncpy(filnam,*cmlist++,CKMAXPATH+1);
5593                     debug(F111,"gnfile cmlist filnam",filnam,nfils);
5594 #ifndef NOMSEND
5595                 }
5596 #endif /* NOMSEND */
5597                 i = 0;
5598 #ifndef NOSERVER
5599                 debug(F101,"gnfile ngetpath","",ngetpath);
5600 #endif /* NOSERVER */
5601 nextinpath:
5602 #ifndef NOSERVER
5603                 fromgetpath = 0;
5604                 if (server && !isabsolute(filnam) && (ngetpath > i)) {
5605                     ckstrncpy(fullname,getpath[i],CKMAXPATH+1);
5606                     ckstrncat(fullname,filnam,CKMAXPATH);
5607                     debug(F111,"gnfile getpath",fullname,i);
5608                     fromgetpath = 1;
5609                     i++;
5610                 } else {
5611                     i = ngetpath + 1;
5612 #else
5613                     i = 1;              /* ? */
5614 #endif /* NOSERVER */
5615                     ckstrncpy(fullname,filnam,CKMAXPATH+1);
5616                     debug(F110,"gnfile absolute",fullname,0);
5617 #ifndef NOSERVER
5618                 }
5619 #endif /* NOSERVER */
5620                 if (iswild(fullname)
5621 #ifdef RECURSIVE
5622                     || recursive > 0 || !strcmp(fullname,".")
5623 #endif /* RECURSIVE */
5624                     ) { /* It looks wild... */
5625                     /* First check if a file with this name exists */
5626                     debug(F110,"gnfile wild",fullname,0);
5627                     if (zchki(fullname) >= 0) {
5628                         /*
5629                            Here we have a file whose name actually
5630                            contains wildcard characters.
5631                         */
5632                         goto gotnam;
5633                     }
5634 #ifdef COMMENT
5635                     nzxopts = ZX_FILONLY; /* (was 0: 25 Jul 2001 fdc) */
5636 #else
5637                     nzxopts = recursive ? 0 : ZX_FILONLY; /* 30 Jul 2001 */
5638 #endif /* COMMENT */
5639                     if (nolinks) nzxopts |= ZX_NOLINKS; /* (26 Jul 2001 fdc) */
5640 #ifdef UNIXOROSK
5641                     if (matchdot) nzxopts |= ZX_MATCHDOT;
5642 #endif /* UNIXOROSK */
5643                     if (recursive) nzxopts |= ZX_RECURSE;
5644                     x = nzxpand(fullname,nzxopts); /* Expand wildcards */
5645                     debug(F101,"gnfile nzxpand","",x);
5646                     if (x == 1) {
5647                         int xx;
5648                         xx = znext(fullname);
5649                         debug(F111,"gnfile znext A",fullname,xx);
5650                         goto gotnam;
5651                     }
5652                     if (x == 0) {       /* None match */
5653 #ifndef NOSERVER
5654                         if (server && ngetpath > i)
5655                           goto nextinpath;
5656 #endif /* NOSERVER */
5657                         retcode = -1;
5658                         debug(F101,"gnfile gnferror A","",gnferror);
5659                         gnferror = -1;
5660                         continue;
5661                     }
5662                     if (x < 0) {        /* Too many to expand */
5663                         debug(F101,"gnfile gnferror B","",gnferror);
5664                         gnferror = -5;
5665                         return(-5);
5666                     }
5667                     sndsrc = -1;        /* Change send-source to znext() */
5668                 }
5669             } else {                    /* We're out of files. */
5670                 debug(F111,"gnfile done",ckitoa(gnferror),nfils);
5671                 *filnam = '\0';
5672                 return(0);
5673             }
5674         }
5675
5676 /* Otherwise, step to next element of internal wildcard expansion list. */
5677
5678         if (sndsrc == -1) {
5679             int xx = 0;
5680             while (1) {
5681                 debug(F111,"gnfile znext X",filnam,xx);
5682                 xx = znext(filnam);
5683                 debug(F111,"gnfile znext B",filnam,xx);
5684                 if (!filnam[0])
5685                   break;
5686                 if (dodirstoo) {
5687                     debug(F111,"gnfile FTP MPUT /RECURSIVE",filnam,xx);
5688                     break;
5689                 }
5690                 if (!isdir(filnam))
5691                   break;
5692             }
5693             debug(F111,"gnfile znext C",filnam,x);
5694             if (!filnam[0]) {           /* If no more, */
5695                 sndsrc = 1;             /* go back to previous list */
5696                 debug(F101,"gnfile setting sndsrc back","",sndsrc);
5697                 continue;
5698             } else
5699               ckstrncpy(fullname,filnam,CKMAXPATH+1);
5700         }
5701
5702 /* Get here with a filename. */
5703
5704 gotnam:
5705         debug(F110,"gnfile fullname",fullname,0);
5706         if (fullname[0]) {
5707 #ifdef DTILDE
5708             char * dirp = "";
5709             if (fullname[0] == '~') {
5710                 dirp = tilde_expand((char *)fullname);
5711                 if (*dirp) ckstrncpy(fullname,dirp,CKMAXPATH+1);
5712             }
5713 #endif /* DTILDE */
5714             filesize = zchki(fullname); /* Check if file readable */
5715             debug(F111,"gnfile zchki",fullname,filesize);
5716             retcode = filesize;         /* Possible return code */
5717             if (filesize == (CK_OFF_T)-2 && dodirstoo) {
5718                 filesize = 0;
5719             }
5720             if (filesize < 0) {
5721                 gnferror = (int)filesize;
5722                 debug(F101,"gnfile gnferror C","",gnferror);
5723             }
5724             if (filesize == (CK_OFF_T)-1) { /* If not found */
5725                 debug(F100,"gnfile -1","",0);
5726 #ifndef NOSERVER
5727                 if (server && ngetpath > i)
5728                   goto nextinpath;
5729 #endif /* NOSERVER */
5730                 debug(F110,"gnfile skipping:",fullname,0);
5731                 tlog(F110,fullname,": open failure - skipped",0);
5732                 xxscreen(SCR_FN,0,0l,fullname);
5733                 xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname);
5734 #ifdef TLOG
5735                 if (tralog && !tlogfmt)
5736                   doxlog(what,fullname,fsize,binary,1,"Skipped");
5737 #endif /* TLOG */
5738                 continue;
5739             } else if (filesize < 0) {
5740                 if (filesize == (CK_OFF_T)-3) { /* Exists but not readable */
5741                     debug(F100,"gnfile -3","",0);
5742                     filrej++;           /* Count this one as not sent */
5743                     tlog(F110,"Read access denied",fullname,0); /* Log this */
5744                     xxscreen(SCR_FN,0,0l,fullname);
5745                     xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname); /* Display it */
5746 #ifdef TLOG
5747                     if (tralog && !tlogfmt)
5748                       doxlog(what,fullname,fsize,binary,1,"Skipped");
5749 #endif /* TLOG */
5750                 }
5751                 continue;
5752             } else {
5753                 int xx;
5754                 fsize = filesize;
5755 /* +++ */
5756     debug(F111,"gnfile sndsmaller",ckfstoa(sndsmaller),sndsmaller);
5757     debug(F111,"gnfile sndlarger",ckfstoa(sndlarger),sndlarger);
5758     debug(F111,"gnfile (CK_OFF_T)-1",ckfstoa((CK_OFF_T)-1),(CK_OFF_T)-1);
5759
5760                 xx = fileselect(fullname,
5761                                 sndafter, sndbefore,
5762                                 sndnafter,sndnbefore,
5763                                 sndsmaller,sndlarger,
5764                                 skipbup,
5765                                 NSNDEXCEPT,sndexcept);
5766                 debug(F111,"gnfile fileselect",fullname,xx);
5767                 if (!xx) {
5768                     filesize = (CK_OFF_T)-1;
5769                     gnferror = -6;
5770                     debug(F101,"gnfile gnferror D","",gnferror);
5771                     continue;
5772                 }
5773                 ckstrncpy(filnam,fullname,CKMAXPATH+1);
5774                 return(1);
5775             }
5776 #ifdef COMMENT
5777         /* This can't be right! */
5778         } else {                        /* sndsrc is 0... */
5779             if (!fileselect(fullname,
5780                             sndafter, sndbefore,
5781                             sndnafter,sndnbefore,
5782                             sndsmaller,sndlarger,
5783                             skipbup,
5784                             NSNDEXCEPT,sndexcept)) {
5785                 gnferror = -6;
5786                 debug(F111,"gnfile fileselect",fullname,gnferror);
5787                 filesize = (CK_OFF_T)-1;
5788                 continue;
5789             }
5790             ckstrncpy(filnam,fullname,CKMAXPATH+1);
5791             return(1);
5792 #endif /* COMMENT */
5793         }
5794     }
5795     debug(F101,"gnfile result","",retcode);
5796     *filnam = '\0';
5797     return(0);
5798 }
5799
5800 /*
5801   The following bunch of routines feed internally generated data to the server
5802   to send to the client in response to REMOTE commands like DIRECTORY, DELETE,
5803   and so on.  We have to write these lines in the format appropriate to our
5804   platform, so they can be converted to generic (CRLF) text format by the
5805   packetizer.
5806 */
5807 #ifdef UNIX
5808 char * endline = "\12";
5809 #else
5810 #ifdef datageneral
5811 char * endline = "\12";
5812 #else
5813 #ifdef MAC
5814 char * endline = "\15";
5815 #else
5816 #ifdef OSK
5817 char * endline = "\15";
5818 #else
5819 char * endline = "\15\12";
5820 #endif /* OSK */
5821 #endif /* MAC */
5822 #endif /* datageneral */
5823 #endif /* UNIX */
5824
5825 #ifdef MAC
5826 #define FNCBUFL 256
5827 #else
5828 #ifdef CKSYMLINK
5829 #define FNCBUFL (CKMAXPATH + CKMAXPATH + 64)
5830 #else
5831 #define FNCBUFL (CKMAXPATH + 64)
5832 #endif /* CKSYMLINK */
5833 #endif /* MAC */
5834
5835 /* NB: The minimum FNCBUFL is 255 */
5836
5837 static CHAR funcbuf[FNCBUFL];
5838 static int  funcnxt =  0;
5839 static int  funclen =  0;
5840 static int  nxpnd   = -1;
5841 static long ndirs   =  0;
5842 static long nfiles  =  0;
5843 static CK_OFF_T nbytes  =  0;
5844
5845 int
5846 sndstring(p) char * p; {
5847 #ifndef NOSERVER
5848     nfils = 0;                          /* No files, no lists. */
5849     xflg = 1;                           /* Flag we must send X packet. */
5850     ckstrncpy(cmdstr,versio,CMDSTRL);   /* Data for X packet. */
5851     first = 1;                          /* Init getchx lookahead */
5852     memstr = 1;                         /* Just set the flag. */
5853     memptr = p;                         /* And the pointer. */
5854     binary = XYFT_T;                    /* Text mode for this. */
5855     return(sinit());
5856 #else
5857     return(0);
5858 #endif /* NOSERVER */
5859 }
5860
5861 /*  S N D H L P  --  Routine to send builtin help  */
5862
5863 static int srvhlpnum = 0;
5864
5865 #ifdef IKSD
5866 static char *nmx[] =  { "Disabled", "Disabled", "Enabled", "Enabled" };
5867 #endif /* IKSD */
5868
5869 static char *
5870 xnm(x) int x; {
5871 #ifdef IKSD
5872     if (inserver)
5873       return(nmx[x]);
5874     else
5875 #endif /* IKSD */
5876       return(nm[x]);
5877 }
5878
5879 static int
5880 nxthlp(
5881 #ifdef CK_ANSIC
5882        void
5883 #endif /* CK_ANSIC */
5884        ) {
5885     int x = 0;
5886     extern int
5887       en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai,
5888       en_pri, en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who,
5889       /* en_ret, */ en_mkd, en_rmd, en_asg, en_que, en_xit, x_login, x_logged,
5890       xfinish;
5891     extern char * ckxsys;
5892
5893     if (funcnxt < funclen)
5894       return (funcbuf[funcnxt++]);
5895
5896     switch (srvhlpnum++) {
5897       case 0:
5898         x = ckstrncpy((char *)funcbuf,
5899                       "Client Command     Status        Description\n",
5900                       FNCBUFL
5901                       );
5902         if (x_login && !x_logged) {
5903             x += ckstrncat((char *)funcbuf,
5904                            " REMOTE LOGIN       required\n",
5905                            FNCBUFL
5906                            );
5907         }
5908         if (FNCBUFL - x > 74)
5909         sprintf((char *)(funcbuf+x)," GET                %-14s%s\n",
5910                 xnm(en_get),
5911                 "Transfer file(s) from server to client."
5912                 );
5913         break;
5914
5915 /* NOTE: The minimum funcbuf[] size is 255; all of the following are safe. */
5916
5917       case 1:
5918         sprintf((char *)funcbuf," SEND               %-14s%s\n",
5919                 xnm(en_sen),
5920                 "Transfer file(s) from client to server."
5921                 );
5922         break;
5923
5924       case 2:
5925         sprintf((char *)funcbuf," MAIL               %-14s%s\n",
5926                 xnm(inserver ? 0 : en_mai),
5927                 "Send file(s) as e-mail."
5928                 );
5929         break;
5930
5931       case 3:
5932 #ifndef NOSPL
5933         sprintf((char *)funcbuf," REMOTE ASSIGN      %-14s%s\n",
5934                 xnm(en_asg),
5935                 "Assign value to server variable or macro."
5936                 );
5937 #else
5938         sprintf((char *)funcbuf," REMOTE ASSIGN      not configured\n");
5939 #endif /* NOSPL */
5940
5941         break;
5942       case 4:
5943         sprintf((char *)funcbuf," REMOTE CD          %-14s%s\n",
5944                 xnm(en_cwd),
5945                 "Change server's directory."
5946                 );
5947         break;
5948
5949       case 5:
5950 #ifdef ZCOPY
5951         sprintf((char *)funcbuf," REMOTE COPY        %-14s%s\n",
5952                 xnm(en_cpy),
5953                 "Copy a file on the server."
5954                 );
5955 #else
5956         sprintf((char *)funcbuf," REMOTE COPY        not configured\n");
5957 #endif /* ZCOPY */
5958
5959         break;
5960       case 6:
5961         sprintf((char *)funcbuf," REMOTE DELETE      %-14s%s\n",
5962                 xnm(en_del),
5963                 "Delete a file on the server."
5964                 );
5965         break;
5966
5967       case 7:
5968         sprintf((char *)funcbuf," REMOTE DIRECTORY   %-14s%s\n",
5969                 xnm(en_dir),
5970                 "List files on the server."
5971                 );
5972         break;
5973
5974       case 8:
5975         sprintf((char *)funcbuf," REMOTE EXIT        %-14s%s\n",
5976                 xnm(en_xit),
5977                 "Exit from Kermit server program."
5978                 );
5979         break;
5980
5981       case 9:
5982         sprintf((char *)funcbuf," REMOTE HOST        %-14s%s\n",
5983                 xnm(inserver ? 0 : en_hos),
5984 #ifdef datageneral
5985                 "Execute a CLI command on the server."
5986 #else
5987 #ifdef VMS
5988                 "Execute a DCL command on the server."
5989 #else
5990                 "Execute a shell command on the server."
5991 #endif /* VMS */
5992 #endif /* datageneral */
5993                 );
5994         break;
5995
5996       case 10:
5997         sprintf((char *)funcbuf," REMOTE PRINT       %-14s%s\n",
5998                 xnm(inserver ? 0 : en_pri),
5999                 "Send a file to the server for printing."
6000                 );
6001         break;
6002
6003       case 11:
6004 #ifndef NOSPL
6005         sprintf((char *)funcbuf," REMOTE QUERY       %-14s%s\n",
6006                 xnm(en_que),
6007                 "Get value of server variable or macro."
6008                 );
6009
6010 #else
6011         sprintf((char *)funcbuf," REMOTE QUERY       not configured\n");
6012 #endif /* NOSPL */
6013
6014         break;
6015       case 12:
6016         sprintf((char *)funcbuf," REMOTE MKDIR       %-14s%s\n",
6017                 xnm(en_mkd),
6018                 "Create a directory on the server."
6019                 );
6020         break;
6021
6022       case 13:
6023         sprintf((char *)funcbuf," REMOTE RMDIR       %-14s%s\n",
6024                 xnm(en_rmd),
6025                 "Remove a directory on the server."
6026                 );
6027         break;
6028
6029       case 14:
6030         sprintf((char *)funcbuf," REMOTE RENAME      %-14s%s\n",
6031                 xnm(en_ren),
6032                 "Rename a file on the server."
6033                 );
6034         break;
6035
6036       case 15:
6037         sprintf((char *)funcbuf," REMOTE SET         %-14s%s\n",
6038                 xnm(en_set),
6039                 "Set a parameter on the server"
6040                 );
6041         break;
6042
6043       case 16:
6044         sprintf((char *)funcbuf," REMOTE SPACE       %-14s%s\n",
6045                 xnm(en_spa),
6046                 "Inquire about disk space on the server."
6047                 );
6048         break;
6049
6050       case 17:
6051         sprintf((char *)funcbuf," REMOTE TYPE        %-14s%s\n",
6052                 xnm(en_typ),
6053                 "Display a server file on your screen."
6054                 );
6055         break;
6056
6057       case 18:
6058         sprintf((char *)funcbuf," REMOTE WHO         %-14s%s\n",
6059                 xnm(inserver ? 0 : en_who),
6060                 "List who is logged in to the server."
6061                 );
6062         break;
6063
6064       case 19:
6065         sprintf((char *)funcbuf," FINISH             %-14s%s\n",
6066                 xnm(en_fin),
6067                 xfinish ?
6068                 "Exit from Kermit server program." :
6069                 "Return the server to its command prompt."
6070                 );
6071         break;
6072
6073       case 20:
6074         sprintf((char *)funcbuf," BYE                %-14s%s\n\n",
6075                 xnm(en_bye),
6076                 "Log the server out and disconnect."
6077                 );
6078         break;
6079
6080       default:
6081         return(-1);
6082     }
6083     funcnxt = 0;
6084     funclen = strlen((char *)funcbuf);
6085     return(funcbuf[funcnxt++]);
6086 }
6087
6088 int
6089 sndhlp() {
6090 #ifndef NOSERVER
6091     extern char * ckxsys;
6092
6093     first = 1;                          /* Init getchx lookahead */
6094     nfils = 0;                          /* No files, no lists. */
6095     xflg = 1;                           /* Flag we must send X packet. */
6096     ckstrncpy(cmdstr,"REMOTE HELP",CMDSTRL); /* Data for X packet. */
6097     sprintf((char *)funcbuf, "C-Kermit %s,%s\n\n", versio, ckxsys);
6098     funclen = strlen((char *)funcbuf);
6099 #ifdef IKSD
6100     if (inserver) {
6101         sprintf((char *)(funcbuf+funclen),
6102                 "Internet Kermit Service (EXPERIMENTAL)\n\n");
6103         funclen = strlen((char *)funcbuf);
6104     }
6105 #endif /* IKSD */
6106     funcnxt = 0;
6107     funcptr = nxthlp;
6108     funcstr = 1;
6109     srvhlpnum = 0;
6110     binary = XYFT_T;                    /* Text mode for this. */
6111     return(sinit());
6112 #else
6113     return(0);
6114 #endif /* NOSERVER */
6115 }
6116
6117 /*
6118    Returns the next available character,
6119   -1 if no more data.
6120 */
6121 static int
6122 nxttype(
6123 #ifdef CK_ANSIC
6124        void
6125 #endif /* CK_ANSIC */
6126         ) {
6127     int c;
6128     if (zchin(ZIFILE,&c) < 0) {
6129         zclose(ZIFILE);
6130         return(-1);
6131     } else {
6132         return((unsigned)c);
6133     }
6134 }
6135
6136 /*  S N D T Y P -- TYPE a file to remote client */
6137
6138 int
6139 sndtype(file) char * file; {
6140 #ifndef NOSERVER
6141     char name[CKMAXPATH+1];
6142
6143 #ifdef OS2
6144     char * p = NULL;
6145
6146     if (*file) {
6147         ckstrncpy(name, file, CKMAXPATH+1);
6148         /* change / to \. */
6149         p = name;
6150         while (*p) {                    /* Change them back to \ */
6151             if (*p == '/') *p = '\\';
6152             p++;
6153         }
6154     } else
6155       return(0);
6156 #else
6157     ckstrncpy(name, file, CKMAXPATH+1);
6158 #endif /* OS2 */
6159
6160     funcnxt = 0;
6161     funclen = strlen((char *)funcbuf);
6162     if (zchki(name) == -2) {
6163         /* Found a directory */
6164         return(0);
6165     }
6166     if (!zopeni(ZIFILE,name))
6167       return(0);
6168
6169     nfils = 0;                          /* No files, no lists. */
6170     xflg = 1;                           /* Flag we must send X packet. */
6171     ckstrncpy(cmdstr,"type",CMDSTRL);   /* Data for X packet. */
6172     first = 1;                          /* Init getchx lookahead */
6173     funcstr = 1;                        /* Just set the flag. */
6174     funcptr = nxttype;                  /* And the pointer. */
6175     binary = XYFT_T;                    /* Text mode for this */
6176     return(sinit());
6177 #else
6178     return(0);
6179 #endif /* NOSERVER */
6180 }
6181
6182 /*
6183    N X T D I R  --  Provide data for senddir()
6184
6185    Returns the next available character or -1 if no more data.
6186 */
6187 #ifndef NOICP
6188 /* Directory listing parameters set by the user interface, if any. */
6189 extern int dir_head, dir_dots, dir_back;
6190 #endif /* NOICP */
6191 static int sd_hdg, sd_bkp, sd_dot;      /* Local listing parameters */
6192
6193 static int
6194 nxtdir(
6195 #ifdef CK_ANSIC
6196        void
6197 #endif /* CK_ANSIC */
6198        ) {
6199     char name[CKMAXPATH+1], dbuf[24], *p = NULL;
6200     char *dstr = NULL, * lnk = "";
6201     CHAR c, * linebuf = funcbuf;
6202 #ifdef OSK
6203     /* Work around bugs in OSK compiler */
6204     char *dirtag = "directories";
6205     char *filetag = "files";
6206     char *bytetag = "bytes";
6207 #endif /* OSK */
6208     CK_OFF_T len = 0;
6209     int x, itsadir = 0, gotone = 0;
6210
6211 #ifdef DEBUG
6212     if (deblog) {
6213         debug(F101,"nxtdir funcnxt","",funcnxt);
6214         debug(F101,"nxtdir funclen","",funclen);
6215         debug(F110,"nxtdir funcbuf",funcbuf+funcnxt,0);
6216     }
6217 #endif /* DEBUG */
6218     if (funcnxt < funclen) {            /* Return next character from buffer */
6219         c = funcbuf[funcnxt++];
6220         debug(F000,"nxtdir return 1","",(unsigned)(c & 0xff));
6221         return((unsigned)(c & 0xff));
6222     }
6223     while (nxpnd > 0) {                 /* Buffer needs refill */
6224         nxpnd--;
6225         znext(name);                    /* Get next filename */
6226         if (!name[0]) {                 /* None left - done */
6227             nxpnd = 0;
6228             return(nxtdir());
6229         }
6230         if (sd_bkp) {                   /* Showing backup files? */
6231             gotone = 1;                 /* Yes, no need to check. */
6232             break;
6233         }
6234         x = ckmatch(                    /* No - see if this is one */
6235 #ifdef CKREGEX
6236                     "*.~[0-9]*~"        /* Not perfect but close enough. */
6237 #else
6238                     "*.~*~"             /* Less close. */
6239 #endif /* CKREGEX */
6240                     ,name,filecase,1);
6241         debug(F111,"nxtdir ckmatch",name,x);
6242         if (x) {
6243             continue;                   /* It's a backup file - skip it */
6244         } else {
6245             gotone = 1;                 /* It's not, break from loop. */
6246             break;
6247         }
6248     }
6249     if (gotone) {
6250         len = zgetfs(name);             /* Get file size */
6251         debug(F111,"nxtdir zgetfs",name,len);
6252 #ifdef VMSORUNIX
6253         itsadir = zgfs_dir;             /* See if it's a directory */
6254 #else
6255         itsadir = (len == -2 || isdir(name));
6256 #endif /* VMSORUNIX */
6257         dstr = zfcdat(name);
6258         debug(F111,"nxtdir zcfdat",dstr,0);
6259         if (!dstr)
6260           dstr = "0000-00-00 00:00:00";
6261         if (!*dstr) {
6262           dstr = "0000-00-00 00:00:00";
6263         } else {
6264             dbuf[0] = dstr[0];
6265             dbuf[1] = dstr[1];
6266             dbuf[2] = dstr[2];
6267             dbuf[3] = dstr[3];
6268             dbuf[4] = '-';
6269             dbuf[5] = dstr[4];
6270             dbuf[6] = dstr[5];
6271             dbuf[7] = '-';
6272             dbuf[8] = dstr[6];
6273             dbuf[9] = dstr[7];
6274             strcpy(dbuf+10,dstr+8);
6275             dstr = dbuf;
6276         }
6277 #ifdef CK_PERMS
6278 #ifdef VMSORUNIX
6279         p = ziperm(name);               /* Get permissions */
6280 #else
6281         p = zgperm(name);
6282 #endif /* VMSORUNIX */
6283 #else
6284         p = NULL;
6285 #endif /* CK_PERMS */
6286         debug(F110,"domydir perms",p,0);
6287
6288 #ifdef VMS
6289         /* Make name relative */
6290         ckstrncpy(name,zrelname(name,zgtdir()),CKMAXPATH+1);
6291 #endif /* VMS */
6292
6293         if (itsadir) {
6294             ndirs++;
6295         } else {
6296             nfiles++;
6297             nbytes += len;
6298         }
6299         lnk = "";
6300 #ifdef UNIX
6301 #ifdef CKSYMLINK
6302         if (zgfs_link) {
6303             extern char linkname[];
6304             lnk = linkname;
6305         }
6306         debug(F111,"nxtdir linkname",lnk,zgfs_link);
6307 #endif /* CKSYMLINK */
6308 #endif /* UNIX */
6309
6310 /*
6311   The following sprintf's are safe; linebuf is a pointer to funcbuf,
6312   which is 64 bytes larger than CKMAXPATH (or double CKMAXPATH when
6313   symlinks are possible).  64 allows for the fixed-field portions of
6314   the file listing line: permissions, size, and date.  CKMAXPATH allows
6315   for the longest possible pathname.
6316 */
6317         if (itsadir && len < 0) {       /* Directory */
6318 #ifdef VMS
6319             sprintf((char *)linebuf,
6320                     "%-22s%-10s  %s  %s\n",p,"<DIR>",dstr,name);
6321 #else
6322             if (p)
6323               sprintf((char *)linebuf,
6324                       "%10s%-10s  %s  %s\n",p,"<DIR>",dstr,name);
6325             else
6326               sprintf((char *)linebuf,
6327                       "%-10s  %s  %s\n", "<DIR>", dstr, name);
6328 #endif /* VMS */
6329         } else {                        /* Regular file */
6330 #ifdef VMS
6331             sprintf((char *)linebuf,
6332                     "%-22s%10s  %s  %s\n", p, ckfstoa(len), dstr, name);
6333 #else
6334             if (p)
6335               sprintf((char *)linebuf,
6336                       "%10s%10s  %s  %s%s%s\n",
6337                       p, ckfstoa(len), dstr, name,
6338                       *lnk ? " -> " : "",
6339                       lnk
6340                       );
6341             else
6342               sprintf((char *)linebuf,
6343                       "%10s  %s  %s%s%s\n",
6344                       ckfstoa(len), dstr, name,
6345                       *lnk ? " -> " : "",
6346                       lnk
6347                       );
6348 #endif /* VMS */
6349         }
6350         funcnxt = 0;
6351         funclen = strlen((char *)funcbuf);
6352     } else if (sd_hdg && nxpnd == 0) {  /* Done, send summary */
6353         char *blankline = "";           /* At beginning of summary */
6354 /*
6355   The idea is to prevent (a) unnecessary multiple blanklines, and (b)
6356   prompt-stomping.  Preventing (b) is practically impossible, because it
6357   depends on the client so for now always include that final CRLF.
6358 */
6359         if (!ndirs || !nbytes || !nfiles)
6360           blankline = endline;
6361 #ifdef OSK
6362 /* Workaround bugs in OS-9 compiler... */
6363         if (ndirs == 1)
6364            dirtag = "directory";
6365         if (nfiles == 1)
6366            filetag = "file";
6367         if (nbytes == (CK_OFF_T)1)
6368            bytetag = "byte";
6369         sprintf((char *)funcbuf,
6370                 "%sSummary: %ld %s, %ld %s, %s %s%s",
6371                 blankline,
6372                 ndirs,
6373                 dirtag,
6374                 nfiles,
6375                 filetag,
6376                 ckfstoa(nbytes),
6377                 bytetag,
6378                 endline);
6379 #else
6380         sprintf((char *)funcbuf,
6381                 "%sSummary: %ld director%s, %ld file%s, %s byte%s%s",
6382                 blankline,
6383                 ndirs,
6384                 (ndirs == 1) ? "y" : "ies",
6385                 nfiles,
6386                 (nfiles == 1) ? "" : "s",
6387                 ckfstoa(nbytes),
6388                 (nbytes == (CK_OFF_T)1) ? "" : "s",
6389                 endline
6390                 );
6391 #endif /* OSK */
6392         nxpnd--;
6393         funcnxt = 0;
6394         funclen = strlen((char *)funcbuf);
6395     } else {
6396         funcbuf[0] = '\0';
6397         funcnxt = 0;
6398         funclen = 0;
6399     }
6400     debug(F101,"nxtdir funclen","",funclen);
6401
6402     if (funcnxt < funclen) {            /* If we have data to send... */
6403         c = funcbuf[funcnxt++];
6404         debug(F000,"nxtdir return 2","",(unsigned)(c & 0xff));
6405         return((unsigned)(c & 0xff));
6406     } else
6407       return(-1);                       /* Nothing left, done. */
6408 }
6409
6410 /*  S N D D I R -- send directory listing  */
6411
6412 int
6413 snddir(spec) char * spec; {
6414 #ifndef NOSERVER
6415     char * p = NULL, name[CKMAXPATH+1];
6416     int t = 0, rc = 0;
6417     char fnbuf[CKMAXPATH+1];
6418
6419     debug(F111,"snddir matchdot",spec,matchdot);
6420
6421 #ifndef NOICP
6422     debug(F111,"snddir dir_dots",spec,dir_dots);
6423     sd_hdg = dir_head > 0;              /* Import listing parameters if any */
6424     sd_bkp = dir_back > 0;
6425     if (dir_dots > -1)
6426       sd_dot = dir_dots;
6427     else
6428       sd_dot = matchdot;
6429 #else
6430     sd_hdg = 1;                         /* Or use hardwired defaults */
6431     sd_bkp = 1;
6432     sd_dot = matchdot;
6433 #endif /* NOICP */
6434
6435     if (!spec) spec = "";
6436     debug(F111,"snddir sd_dot",spec,sd_dot);
6437     if (*spec) {
6438 #ifdef COMMENT
6439         zfnqfp(spec,CKMAXPATH,name);
6440         debug(F110,"snddir zfnqfp",name,0);
6441 #else
6442         ckstrncpy(name,spec,CKMAXPATH+1);
6443         debug(F110,"snddir name",name,0);
6444 #endif /* COMMENT */
6445     } else {
6446 #ifdef OS2
6447         strcpy(name, "*");
6448 #else
6449 #ifdef UNIXOROSK
6450         strcpy(name, "./*");
6451 #else
6452 #ifdef VMS
6453         strcpy(name, "*.*");
6454 #else
6455 #ifdef datageneral
6456         strcpy(name, "+");
6457 #else
6458         debug(F101,"snddir quit (no filespec)","",0);
6459         return(0);
6460 #endif /* datageneral */
6461 #endif /* VMS */
6462 #endif /* UNIX */
6463 #endif /* OS2 */
6464     }
6465     debug(F110,"snddir name 1",name,0);
6466     ndirs = 0L;
6467     nfiles = 0L;
6468     nbytes = (CK_OFF_T)0;
6469
6470     if (zfnqfp(name,CKMAXPATH,fnbuf))
6471
6472     debug(F110,"snddir name 2",name,0);
6473     p = name + strlen(name);            /* Move it to end of list */
6474
6475     /* sprintf safe because funcbuf size >= max path len + 64 */
6476
6477     if (sd_hdg) {
6478         sprintf((char *)funcbuf,"Listing files: %s%s%s",fnbuf,endline,endline);
6479         funcnxt = 0;
6480         funclen = strlen((char *)funcbuf);
6481     }
6482     diractive = 1;
6483
6484 #ifdef OS2
6485     if (zchki(name) == -2) {            /* Found a directory */
6486         p--;
6487         if (*p == '\\' || *p == '/')
6488           ckstrncat(name, "*", CKMAXPATH);
6489         else if (*p == ':')
6490           ckstrncat(name, ".", CKMAXPATH);
6491         else
6492           ckstrncat(name, "\\*", CKMAXPATH);
6493         debug(F110,"snddir directory",name,0);
6494     }
6495 #else
6496     if (!iswild(name) && isdir(name)) {
6497         char * s = name;
6498         p--;
6499 #ifdef UNIXOROSK
6500         if (*p == '/')                  /* So append wildcard to it */
6501           ckstrncat(s, "*", CKMAXPATH);
6502         else
6503           ckstrncat(s, "/*", CKMAXPATH);
6504 #else
6505 #ifdef VMS
6506         if (*p == ']' || *p == '>' || *p == ':')
6507           ckstrncat(s, "*.*", CKMAXPATH);
6508 #else
6509 #ifdef datageneral
6510         if (*p == ':')
6511           ckstrncat(s, "+", CKMAXPATH);
6512         else
6513           ckstrncat(s, ":+", CKMAXPATH);
6514 #else
6515 #ifdef VOS
6516         if (*p == '>')
6517           ckstrncat(s, "*", CKMAXPATH);
6518         else
6519           ckstrncat(s, ">*", CKMAXPATH);
6520 #endif /* VOS */
6521 #endif /* datageneral */
6522 #endif /* VMS */
6523 #endif /* UNIXOROSK */
6524         debug(F110,"snddir directory",name,0);
6525     }
6526 #endif /* OS2 */
6527
6528     nzxopts = 0;
6529 #ifdef UNIX
6530     {
6531         extern char ** mtchs;
6532         debug(F111,"snddir sd_dot",spec,sd_dot);
6533         if (sd_dot > 0)
6534           nzxopts |= ZX_MATCHDOT;
6535         if (recursive)
6536           nzxopts |= ZX_RECURSE;
6537         debug(F111,"snddir nzxopts",spec,nzxopts);
6538         nxpnd = nzxpand(name,nzxopts);  /* Get the array of names */
6539         sh_sort(mtchs,NULL,nxpnd,0,0,1); /* Sort the array */
6540     }
6541 #else
6542     if (recursive) nzxopts |= ZX_RECURSE;
6543     nxpnd = nzxpand(name,nzxopts);
6544 #endif /* UNIX */
6545
6546     debug(F101,"snddir nzxpand nxpnd","",nxpnd);
6547     if (nxpnd < 1)
6548       return(-1);
6549     nfils = 0;                          /* No files, no lists. */
6550     xflg = 1;                           /* Flag we must send X packet. */
6551     if ((int)strlen(name) < CMDSTRL - 11) /* Data for X packet. */
6552       sprintf(cmdstr,"DIRECTORY %s",name); /* safe */
6553     else
6554       ckstrncpy(cmdstr,"DIRECTORY",CMDSTRL);
6555     first = 1;                          /* Init getchx lookahead */
6556     funcstr = 1;                        /* Just set the flag. */
6557     funcptr = nxtdir;                   /* And the pointer. */
6558     binary = XYFT_T;                    /* Text mode for this */
6559     rc = sinit();                       /* 26 Aug 2005 */
6560     debug(F111,"snddir","sinit()",rc);
6561     return(rc);
6562 #else
6563     return(0);
6564 #endif /* NOSERVER */
6565 }
6566
6567 /*  N X T D E L -- provide data for delete   */
6568
6569 /*  Returns the next available character or -1 if no more data  */
6570
6571 static int
6572 nxtdel(
6573 #ifdef CK_ANSIC
6574        void
6575 #endif /* CK_ANSIC */
6576        ) {
6577     char name[257], *p = NULL;
6578     int len = 0;
6579
6580     if (funcnxt < funclen)
6581       return ((unsigned)funcbuf[funcnxt++]);
6582
6583     if (nxpnd > 0) {
6584         nxpnd--;
6585         znext(name);
6586         if (!name[0]) {
6587             nxpnd = 0;
6588             return(nxtdel());
6589         }
6590         len = zchki(name);
6591
6592         /* Find just the name of the file */
6593
6594         for (p = name + strlen(name); p != name && *p != '/' ; p--) ;
6595         if (*p == '/') p++;
6596
6597         /* sprintf's safe because size of funcbuf >= 64 + maxpathlen */
6598
6599         if (len > -1L) {
6600             if (zdelet(name)) {
6601                 sprintf((char *)funcbuf," %10s: %s%s","skipping",p,endline);
6602             } else {
6603                 nfiles++;
6604                 nbytes += len;
6605                 sprintf((char *)funcbuf," %10s: %s%s","deleted",p,endline);
6606             }
6607         } else
6608           sprintf((char *)funcbuf," directory: %s%s", p, endline);
6609         funcnxt = 0;
6610         funclen = strlen((char *)funcbuf);
6611     } else
6612
6613     /* If done processing the expanded entries send a summary statement */
6614
6615       if (nxpnd == 0) {
6616           sprintf((char *)funcbuf,
6617                   "%s%ld file%s deleted, %s byte%s freed%s",
6618                   endline,
6619                   nfiles,
6620                   (nfiles == 1) ? "" : "s",
6621                   ckfstoa(nbytes),
6622                   (nbytes == (CK_OFF_T)1) ? "" : "s",
6623                   endline
6624                   );
6625           nxpnd--;
6626           funcnxt = 0;
6627           funclen = strlen((char *)funcbuf);
6628       } else {
6629           funcbuf[0] = '\0';
6630           funcnxt = 0;
6631           funclen = 0;
6632       }
6633
6634     /* If we have data to send */
6635
6636     if (funcnxt < funclen)
6637       return ((unsigned)funcbuf[funcnxt++]); /* Return a character */
6638     else
6639       return(-1);                       /* No more input */
6640 }
6641
6642 /*  S N D D E L  --  Send delete message  */
6643
6644 int
6645 snddel(spec) char * spec; {
6646 #ifndef NOSERVER
6647     char name[CKMAXPATH+1];
6648 #ifdef OS2
6649     char * p = NULL;
6650 #endif /* #ifdef OS2 */
6651
6652     if (!*spec)
6653       return(0);
6654
6655     ckstrncpy(name, spec, CKMAXPATH+1);
6656
6657 #ifdef OS2
6658     /* change / to \. */
6659     p = name;
6660     while (*p) {                        /* Change them back to \ */
6661         if (*p == '/') *p = '\\';
6662         p++;
6663     }
6664 #endif /* OS2 */
6665
6666     nfiles = 0L;
6667     nbytes = (CK_OFF_T)0;
6668     sprintf((char *)funcbuf,"Deleting \"%s\"%s",name,endline);
6669     funcnxt = 0;
6670     funclen = strlen((char *)funcbuf);
6671
6672     nzxopts = ZX_FILONLY;               /* Files only */
6673 #ifdef UNIXOROSK
6674     if (matchdot) nzxopts |= ZX_MATCHDOT;
6675 #endif /* UNIXOROSK */
6676 #ifdef COMMENT
6677     /* Recursive deleting not supported yet */
6678     if (recursive) nzxopts |= ZX_RECURSE;
6679 #endif /* COMMENT */
6680     nxpnd = nzxpand(name,nzxopts);
6681     if (nxpnd < 1)
6682       return(-1);
6683     nfils = 0;                          /* No files, no lists. */
6684     xflg = 1;                           /* Flag we must send X packet. */
6685     ckstrncpy(cmdstr,"REMOTE DELETE",CMDSTRL); /* Data for X packet. */
6686     first = 1;                          /* Init getchx lookahead */
6687     funcstr = 1;                        /* Just set the flag. */
6688     funcptr = nxtdel;                   /* And the pointer. */
6689     binary = XYFT_T;                    /* Use text mode for this, */
6690     return(sinit());
6691 #else
6692     return(0);
6693 #endif /* NOSERVER */
6694 }
6695
6696 #ifdef OS2
6697 /*  S N D S P A C E -- send disk space message  */
6698 int
6699 sndspace(drive) int drive; {
6700 #ifndef NOSERVER
6701     static char spctext[64];
6702     unsigned long space;
6703
6704     if (drive) {
6705         space = zdskspace(drive - 'A' + 1);
6706         if (space > 0 && space < 1024)
6707           sprintf(spctext,
6708                   " Drive %c: unknown%s",
6709                   drive,
6710                   endline
6711                   );
6712         else
6713           sprintf(spctext,
6714                   " Drive %c: %ldK free%s",
6715                   drive,
6716                   space / 1024L,
6717                   endline
6718                   );
6719     } else {
6720         space = zdskspace(0);
6721         if (space > 0 && space < 1024)
6722           sprintf(spctext, " Free space: unknown%s", endline);
6723         else
6724           sprintf(spctext, " Free space: %ldK%s", space / 1024L, endline);
6725     }
6726     nfils = 0;                          /* No files, no lists. */
6727     xflg = 1;                           /* Flag we must send X packet. */
6728     ckstrncpy(cmdstr,"free space",CMDSTRL); /* Data for X packet. */
6729     first = 1;                          /* Init getchx lookahead */
6730     memstr = 1;                         /* Just set the flag. */
6731     memptr = spctext;                   /* And the pointer. */
6732     binary = XYFT_T;                    /* Text mode for this. */
6733     return(sinit());
6734 #else
6735     return(0);
6736 #endif /* NOSERVER */
6737 }
6738
6739 /*  S N D W H O -- send who message  */
6740 int
6741 sndwho(who) char * who; {
6742 #ifndef NOSERVER
6743     nfils = 0;                          /* No files, no lists. */
6744     xflg = 1;                           /* Flag we must send X packet. */
6745     ckstrncpy(cmdstr,"who",CMDSTRL);    /* Data for X packet. */
6746     first = 1;                          /* Init getchx lookahead */
6747     memstr = 1;                         /* Just set the flag. */
6748 #ifdef NT
6749     memptr = "\15\12K95 SERVER\15\12";  /* And the pointer. */
6750 #else
6751     memptr = "\15\12K/2 SERVER\15\12";
6752 #endif /* NT */
6753     binary = XYFT_T;                    /* Use text mode */
6754     return(sinit());
6755 #else
6756     return(0);
6757 #endif /* NOSERVER */
6758 }
6759 #endif /* OS2 */
6760
6761 /*  C W D  --  Change server's working directory  */
6762
6763 /*
6764  String passed has first byte as length of directory name, rest of string
6765  is name.  Returns:
6766   0 on failure.
6767   1 on success after sending short-form response (ACK with name).
6768   2 on success if a CD Message file is to be sent.
6769 */
6770 int
6771 cwd(vdir) char *vdir; {
6772     char *cdd, *dirp;
6773
6774     vdir[xunchar(*vdir) + 1] = '\0';    /* Terminate string with a null */
6775     dirp = vdir+1;
6776     tlog(F110,"Directory requested: ",dirp,0L);
6777     if (zchdir(dirp)) {                 /* Try to change */
6778         cdd = zgtdir();                 /* Get new working directory. */
6779         debug(F110,"cwd",cdd,0);
6780         if (srvcdmsg) {                 /* Send orientation file? */
6781             int i;
6782             for (i = 0; i < 8; i++) {
6783                 if (zchki(cdmsgfile[i]) > -1) {
6784                     xxscreen(SCR_CD,0,0l,cdd);
6785                     tlog(F110,"Changed directory to",cdd,0L);
6786                     return(2);
6787                 }
6788             }
6789         }
6790         encstr((CHAR *)cdd);            /* Send short-form reply */
6791         ack1(data);                     /* containing directory name. */
6792         xxscreen(SCR_CD,0,0l,cdd);
6793         tlog(F110,"Changed directory to",cdd,0L);
6794         return(1);
6795     } else {
6796         debug(F110,"cwd failed",dirp,0);
6797         tlog(F110,"Failed to change directory to",dirp,0L);
6798         return(0);
6799     }
6800 }
6801
6802
6803 /*  S Y S C M D  --  Do a system command  */
6804
6805 /*  Command string is formed by concatenating the two arguments.  */
6806
6807 int
6808 syscmd(prefix,suffix) char *prefix, *suffix; {
6809     extern int i_isopen;
6810 #ifndef NOPUSH
6811     char *cp;
6812
6813     i_isopen = 0;
6814     if (!prefix)
6815       return(0);
6816     if (!*prefix)
6817       return(0);
6818     for (cp = cmdstr; *prefix != '\0'; (*cp++ = *prefix++));
6819     while ((*cp++ = *suffix++))
6820 #ifdef OS2
6821         /* This takes away more than we gain in convenience
6822         if (*(cp-1) == '/') *(cp-1) = '\\' */
6823 #endif /* OS2 */
6824       ;                                 /* Copy suffix */
6825
6826     debug(F110,"syscmd",cmdstr,0);
6827
6828     if (zxcmd(ZIFILE,cmdstr) > 0) {
6829         debug(F110,"syscmd zxcmd ok",cmdstr,0);
6830         nfils = sndsrc = 0;             /* Flag that input is from stdin */
6831         xflg = hcflg = 1;               /* And special flags for pipe */
6832         binary = XYFT_T;                /* Go to text mode */
6833         i_isopen = 1;
6834         return (sinit());               /* Send S packet */
6835     } else {
6836         debug(F100,"syscmd zxcmd failed",cmdstr,0);
6837         i_isopen = 0;
6838         return(0);
6839     }
6840 #else
6841     debug(F100,"syscmd zxcmd NOPUSH",cmdstr,0);
6842     i_isopen = 0;
6843     return(0);
6844 #endif /* NOPUSH */
6845 }
6846
6847 /*  R E M S E T  --  Remote Set  */
6848 /*  Called by server to set variables as commanded in REMOTE SET packets.  */
6849 /*  Returns 1 on success, 0 on failure.  */
6850
6851 int
6852 remset(s) char *s; {
6853     extern int c_save, en_del;
6854     int len, i, x, y;
6855     char *p;
6856
6857     len = xunchar(*s++);                /* Length of first field */
6858     p = s + len;                        /* Pointer to second length field */
6859     *p++ = '\0';                        /* Zero out second length field */
6860     x = atoi(s);                        /* Value of first field */
6861     debug(F111,"remset",s,x);
6862     debug(F110,"remset",p,0);
6863     switch (x) {                        /* Do the right thing */
6864       case 132:                         /* Attributes (all, in) */
6865         atcapr = atoi(p);
6866         return(1);
6867       case 133:                         /* File length attributes */
6868       case 233:                         /* IN/OUT combined */
6869       case 148:                         /* Both kinds of lengths */
6870       case 248:
6871         atleni = atleno = atoi(p);
6872         return(1);
6873       case 134:                         /* File Type (text/binary) */
6874       case 234:
6875         attypi = attypo = atoi(p);
6876         return(1);
6877       case 135:                         /* File creation date */
6878       case 235:
6879         atdati = atdato = atoi(p);
6880         return(1);
6881       case 139:                         /* File Blocksize */
6882       case 239:
6883         atblki = atblko = atoi(p);
6884         return(1);
6885       case 141:                         /* Encoding / Character Set */
6886       case 241:
6887         atenci = atenco = atoi(p);
6888         return(1);
6889       case 142:                         /* Disposition */
6890       case 242:
6891         atdisi = atdiso = atoi(p);
6892         return(1);
6893       case 145:                         /* System ID */
6894       case 245:
6895         atsidi = atsido = atoi(p);
6896         return(1);
6897       case 147:                         /* System-Dependent Info */
6898       case 247:
6899         atsysi = atsyso = atoi(p);
6900         return(1);
6901       case 232:                         /* Attributes (all, out) */
6902         atcapr = atoi(p);
6903         return(1);
6904       case 300:                         /* File type (text, binary) */
6905         binary = atoi(p);
6906         b_save = binary;
6907 #ifndef NOICP
6908         g_binary = -1;
6909 #endif /* NOICP */
6910         return(1);
6911       case 301:                         /* File name conversion */
6912         fncnv = 1 - atoi(p);            /* (oops) */
6913         f_save = fncnv;
6914 #ifndef NOICP
6915         g_fncnv = -1;
6916 #endif /* NOICP */
6917         return(1);
6918       case 302:                         /* File name collision */
6919 #ifdef IKSD
6920 #ifdef CK_LOGIN
6921         if (inserver && isguest)        /* May not be changed by guest */
6922           return(0);
6923 #endif /* CK_LOGIN */
6924 #endif /* IKSD */
6925         x = atoi(p);
6926         if (!ENABLED(en_del) && (x == XYFX_X || x == XYFX_U))
6927           return(0);
6928         if (x == XYFX_R) ckwarn = 1;    /* Rename */
6929         if (x == XYFX_X) ckwarn = 0;    /* Replace */
6930         fncact = x;
6931         return(1);
6932       case 310:                         /* Incomplete File Disposition */
6933         keep = atoi(p);                 /* Keep, Discard, Auto */
6934         return(1);
6935       case 311:                         /* Blocksize */
6936         fblksiz = atoi(p);
6937         return(1);
6938       case 312:                         /* Record Length */
6939         frecl = atoi(p);
6940         return(1);
6941       case 313:                         /* Record format */
6942         frecfm = atoi(p);
6943         return(1);
6944       case 314:                         /* File organization */
6945         forg = atoi(p);
6946         return(1);
6947       case 315:                         /* File carriage control */
6948         fcctrl = atoi(p);
6949         return(1);
6950       case 330:                         /* Match dotfiles */
6951 #ifndef NOICP
6952         dir_dots = -1;                  /* This undoes DIR /DOT option */
6953 #endif /* NOICP */
6954         matchdot = atoi(p);
6955         return(1);
6956       case 331:                         /* Match FIFOs */
6957         matchfifo = atoi(p);
6958         return(1);
6959       case 400:                         /* Block check */
6960         y = atoi(p);
6961         if (y < 5 && y > 0) {
6962             bctr = y;
6963             c_save = -1;
6964             return(1);
6965         } else if (*p == 'B') {
6966             bctr = 4;
6967             c_save = -1;
6968             return(1);
6969         } else if (*p == '5') {
6970             bctr = 3;
6971             c_save = -1;
6972             return(1);
6973         }
6974         return(0);
6975       case 401:                         /* Receive packet-length */
6976         rpsiz = urpsiz = atoi(p);
6977         if (urpsiz > MAXRP) urpsiz = MAXRP; /* Max long-packet length */
6978         if (rpsiz > 94) rpsiz = 94;         /* Max short-packet length */
6979         urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
6980         return(1);
6981       case 402:                         /* Receive timeout */
6982         y = atoi(p);                    /* Client is telling us */
6983         if (y > -1 && y < 999) {        /* the timeout that it wants */
6984             pkttim = chktimo(y,timef);  /* us to tell it to use. */
6985             return(1);
6986         } else return(0);
6987       case 403:                         /* Retry limit */
6988         y = atoi(p);
6989         if (y > -1 && y < 95) {
6990             maxtry = y;
6991             return(1);
6992         } else return(0);
6993       case 404:                         /* Server timeout */
6994         y = atoi(p);
6995         if (y < 0) return(0);
6996         srvtim = y;
6997         return(1);
6998
6999 #ifndef NOCSETS
7000       case 405: {                               /* Transfer character set */
7001           extern int s_cset, axcset[];
7002           int i;
7003           for (i = 0; i < ntcsets; i++) {
7004               if (!strcmp(tcsinfo[i].designator,p)) break;
7005           }
7006           debug(F101,"remset tcharset lookup","",i);
7007           if (i == ntcsets) return(0);
7008           tcharset = tcsinfo[i].code;   /* If known, use it */
7009           debug(F101,"remset tcharset","",tcharset);
7010           if (s_cset == XMODE_A)
7011             if (axcset[tcharset] > -1 && axcset[tcharset] > MAXFCSETS)
7012               fcharset = axcset[tcharset]; /* Auto-pick file charset */
7013           debug(F101,"remset tcharset fcharset","",fcharset);
7014           setxlatype(tcharset,fcharset); /* Set up charset translations */
7015           debug(F101,"remset xlatype","",xlatype);
7016           debug(F101,"remset tcharset after setxlatype","",tcharset);
7017           tcs_save = -1;
7018           return(1);
7019       }
7020       case 320: {                       /* File character set */
7021           extern struct keytab fcstab[];
7022           extern int nfilc, s_cset, r_cset;
7023           x = lookup(fcstab,p,nfilc,&y);
7024           debug(F111,"RSET FILE CHAR name",p,x);
7025           if (x < 0)
7026             return(0);
7027           s_cset = XMODE_M;             /* No automatic charset switching */
7028           r_cset = XMODE_M;
7029           fcharset = x;                 /* Set file charset */
7030           setxlatype(tcharset,fcharset); /* and translation type */
7031           fcs_save = -1;
7032           return(1);
7033       }
7034 #endif /* NOCSETS */
7035
7036       case 406:                         /* Window slots */
7037         y = atoi(p);
7038         if (y == 0) y = 1;
7039         if (y < 1 || y > MAXWS) return(0);
7040         wslotr = y;
7041         swcapr = 1;
7042         urpsiz = adjpkl(urpsiz,wslotr,bigrbsiz);
7043         return(1);
7044
7045       case 410:                         /* Transfer mode */
7046         y = atoi(p);                    /* 0 = automatic, nonzero = manual */
7047         if (y != 0) y = 1;
7048         xfermode = y;
7049         debug(F101,"REMOTE SET xfermode","",xfermode);
7050         return(1);
7051
7052       case 420:                         /* SERVER CD-MESSAGE { ON, OFF } */
7053         y = atoi(p);                    /* 0 = automatic, nonzero = manual */
7054         srvcdmsg = y;
7055         return(1);
7056
7057       default:                          /* Anything else... */
7058         return(0);
7059     }
7060 }
7061
7062 /* Adjust packet length based on number of window slots and buffer size */
7063
7064 int
7065 adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
7066     if (protocol != PROTO_K) return(pktlen);
7067     debug(F101,"adjpkl len","",pktlen);
7068     debug(F101,"adjpkl slots","",slots);
7069     debug(F101,"adjpkl bufsiz","",bufsiz);
7070     if (((pktlen + 6) * slots) > bufsiz)
7071       pktlen = (bufsiz / slots) - 6;
7072     debug(F101,"adjpkl new len","",pktlen);
7073     return(pktlen);
7074 }
7075
7076 /* Set transfer mode and file naming based on comparison of system types */
7077
7078
7079 VOID
7080 whoarewe() {
7081 #ifndef NOICP
7082     extern int g_xfermode;
7083 #endif /* NOICP */
7084
7085     wearealike = 0;
7086
7087     debug(F101,"whoarewe xfermode","",xfermode);
7088 #ifndef NOICP
7089     debug(F101,"whoarewe g_xfermode","",g_xfermode);
7090 #endif /* NOICP */
7091     if (whoareu[0]) {                   /* If we know partner's system type */
7092         char * p = (char *)whoareu;
7093         debug(F110,"whoarewe remote sysid",whoareu,0);
7094         if (!strcmp(p,cksysid))         /* Other system same as us */
7095           wearealike = 1;
7096
7097 #ifdef UNIX
7098         else if (!strcmp(p,"L3"))       /* UNIX is sort of like AmigaDOS */
7099           wearealike = 1;               /* (same directory separator) */
7100         else if (!strcmp(p,"N3"))       /* UNIX like Aegis */
7101           wearealike = 1;
7102 #else
7103 #ifdef AMIGA
7104 /* Like UNIX, but case distinctions are ignored and can begin with device:. */
7105         else if (!strcmp(p,"U1"))       /* Amiga is sort of like UNIX */
7106           wearealike = 1;
7107         else if (!strcmp(p,"N3"))       /* Amiga is sort of like Aegis */
7108           wearealike = 1;
7109 #else
7110 #ifdef OS2                              /* (Includes Windows 95/NT) */
7111
7112         /* DOS, GEMDOS, Windows 3.x, Windows 95, Windows NT */
7113         /* All "the same" for FAT partitions but all bets off otherwise */
7114         /* so this part needs some refinement ...  */
7115
7116         else if (!strcmp(p,"U8"))       /* MS-DOS */
7117           wearealike = 1;
7118         else if (!strcmp(p,"UO"))       /* OS/2 */
7119           wearealike = 1;
7120         else if (!strcmp(p,"UN"))       /* Windows NT or 95 */
7121           wearealike = 1;
7122         else if (!strcmp(p,"K2"))       /* GEMDOS */
7123           wearealike = 1;
7124 #else
7125 #ifdef GEMDOS
7126         else if (!strcmp(p,"U8"))
7127           wearealike = 1;
7128         else if (!strcmp(p,"UO"))
7129           wearealike = 1;
7130         else if (!strcmp(p,"UN"))
7131           wearealike = 1;
7132         else if (!strcmp(p,"K2"))
7133           wearealike = 1;
7134 #endif /* GEMDOS */
7135 #endif /* OS2 */
7136 #endif /* AMIGA */
7137 #endif /* UNIX */
7138
7139         /* Get here with wearealike == 1 if system types match */
7140
7141         debug(F101,"whoarewe wearealike","",wearealike);
7142         if (!wearealike)                /* Not alike */
7143           return;
7144
7145         fncnv = XYFN_L;                 /* Alike, so literal filenames */
7146         debug(F101,"whoarewe setting fncnv","",fncnv);
7147
7148         if (xfermode == XMODE_A) {      /* Current xfer mode is auto */
7149 #ifdef VMS
7150             binary = XYFT_L;            /* For VMS-to-VMS, use labeled */
7151 #else
7152 #ifdef OS2
7153             /* OS/2 but not Windows */
7154             if (!strcmp(cksysid,"UO") && !strcmp((char *)whoareu,"UO"))
7155               binary = XYFT_L;          /* For OS/2-to-OS/2, use labeled */
7156 #else
7157             binary = XYFT_B;            /* For all others use binary */
7158 #endif /* OS2 */
7159 #endif /* VMS */
7160             gnf_binary = binary;        /* Prevailing type for gnfile() */
7161             debug(F101,"whoarewe setting binary","",binary);
7162         }
7163     }
7164 }
7165 #endif /* NOXFER */