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