1 | char *fnsv = "C-Kermit functions, 6.0.133, 6 Sep 96"; |
---|
2 | |
---|
3 | /* C K C F N S -- System-independent Kermit protocol support functions. */ |
---|
4 | |
---|
5 | /* ...Part 1 (others moved to ckcfn2,3 to make this module smaller) */ |
---|
6 | |
---|
7 | /* |
---|
8 | Author: Frank da Cruz <fdc@columbia.edu>, |
---|
9 | Columbia University Academic Information Systems, New York City. |
---|
10 | |
---|
11 | Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New |
---|
12 | York. The C-Kermit software may not be, in whole or in part, licensed or |
---|
13 | sold for profit as a software product itself, nor may it be included in or |
---|
14 | distributed with commercial products or otherwise distributed by commercial |
---|
15 | concerns to their clients or customers without written permission of the |
---|
16 | Office of Kermit Development and Distribution, Columbia University. This |
---|
17 | copyright notice must not be removed, altered, or obscured. |
---|
18 | */ |
---|
19 | /* |
---|
20 | System-dependent primitives defined in: |
---|
21 | |
---|
22 | ck?tio.c -- terminal 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 | |
---|
31 | #ifdef OS2 |
---|
32 | #include <io.h> |
---|
33 | #endif /* OS2 */ |
---|
34 | |
---|
35 | #ifdef VMS |
---|
36 | #include <errno.h> |
---|
37 | #endif /* VMS */ |
---|
38 | |
---|
39 | /* Externals from ckcmai.c */ |
---|
40 | extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg, |
---|
41 | rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr, xitsta; |
---|
42 | extern int pktnum, bctr, bctu, bctl, fmask, clfils, sbufnum, protocol, |
---|
43 | size, osize, spktl, nfils, warn, timef, spsizf, sndtyp, rcvtyp, success; |
---|
44 | extern int parity, turn, network, what, whatru, fsecs, justone, slostart, |
---|
45 | delay, displa, xflg, mypadn, remfile, moving; |
---|
46 | extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize, sendstart, rs_len; |
---|
47 | extern long filrej, oldcps, cps, ccu, ccp; |
---|
48 | extern int fblksiz, frecl, frecfm, forg, fcctrl; |
---|
49 | extern int spackets, rpackets, timeouts, retrans, crunched, wmax, wcur; |
---|
50 | extern int hcflg, binary, fncnv, b_save, f_save, server, cxseen, czseen; |
---|
51 | extern int nakstate, discard, rejection, local; |
---|
52 | extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln; |
---|
53 | extern int fnspath, fnrpath; |
---|
54 | extern int atcapr, atcapb, atcapu; |
---|
55 | extern int lpcapr, lpcapb, lpcapu; |
---|
56 | extern int swcapr, swcapb, swcapu; |
---|
57 | extern int lscapr, lscapb, lscapu; |
---|
58 | extern int rscapr, rscapb, rscapu; |
---|
59 | extern int rptena, rptmin; |
---|
60 | extern int sseqtbl[]; |
---|
61 | extern int numerrs; |
---|
62 | extern long rptn; |
---|
63 | extern int maxtry; |
---|
64 | extern int stdouf; |
---|
65 | extern int sendmode; |
---|
66 | #ifdef OS2 |
---|
67 | extern struct zattr iattr; |
---|
68 | #endif /* OS2 */ |
---|
69 | |
---|
70 | #ifndef NOCSETS |
---|
71 | extern int tcharset, fcharset; |
---|
72 | extern int ntcsets; |
---|
73 | extern struct csinfo tcsinfo[], fcsinfo[]; |
---|
74 | #endif /* NOCSETS */ |
---|
75 | |
---|
76 | extern int |
---|
77 | atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko, |
---|
78 | attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; |
---|
79 | |
---|
80 | extern int bigsbsiz, bigrbsiz; |
---|
81 | extern char *versio; |
---|
82 | extern char whoareu[], * cksysid; |
---|
83 | |
---|
84 | #ifndef NOSERVER |
---|
85 | extern int ngetpath; |
---|
86 | extern char * getpath[]; |
---|
87 | #endif /* NOSERVER */ |
---|
88 | |
---|
89 | #ifdef DYNAMIC |
---|
90 | extern CHAR *srvcmd; |
---|
91 | #else |
---|
92 | extern CHAR srvcmd[]; |
---|
93 | #endif /* DYNAMIC */ |
---|
94 | extern CHAR padch, mypadc, eol, seol, feol, ctlq, myctlq, sstate, myrptq; |
---|
95 | extern CHAR *data, padbuf[], stchr, mystch; |
---|
96 | extern CHAR *srvptr; |
---|
97 | extern CHAR *rdatap; |
---|
98 | extern char *cmarg, *cmarg2, *hlptxt, **cmlist, filnam[], fspec[]; |
---|
99 | |
---|
100 | #ifndef NOMSEND |
---|
101 | extern struct filelist * filehead, * filenext; |
---|
102 | extern int addlist; |
---|
103 | #endif /* NOMSEND */ |
---|
104 | |
---|
105 | _PROTOTYP( CHAR *rpar, (void) ); |
---|
106 | _PROTOTYP( int lslook, (unsigned int b) ); /* Locking Shift Lookahead */ |
---|
107 | _PROTOTYP( int szeof, (CHAR *s) ); |
---|
108 | _PROTOTYP( VOID fnlist, (void) ); |
---|
109 | _PROTOTYP( static int nxtdir, (void) ); |
---|
110 | _PROTOTYP( static int nxtdel, (void) ); |
---|
111 | |
---|
112 | /* International character sets */ |
---|
113 | |
---|
114 | #ifndef NOCSETS |
---|
115 | /* Pointers to translation functions */ |
---|
116 | #ifdef CK_ANSIC |
---|
117 | extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */ |
---|
118 | extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */ |
---|
119 | #else |
---|
120 | extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */ |
---|
121 | extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */ |
---|
122 | #endif /* CK_ANSIC */ |
---|
123 | _PROTOTYP( CHAR (*rx), (CHAR) ); /* Input translation function */ |
---|
124 | _PROTOTYP( CHAR (*sx), (CHAR) ); /* Output translation function */ |
---|
125 | _PROTOTYP( CHAR ident, (CHAR) ); /* Identity translation function */ |
---|
126 | #endif /* NOCSETS */ |
---|
127 | |
---|
128 | /* Windowing things */ |
---|
129 | |
---|
130 | extern int rseqtbl[]; /* Rec'd-packet sequence # table */ |
---|
131 | |
---|
132 | /* (PWP) external def. of things used in buffered file input and output */ |
---|
133 | |
---|
134 | #ifdef DYNAMIC |
---|
135 | extern char *zinbuffer, *zoutbuffer; |
---|
136 | #else |
---|
137 | extern char zinbuffer[], zoutbuffer[]; |
---|
138 | #endif |
---|
139 | extern char *zinptr, *zoutptr; |
---|
140 | extern int zincnt, zoutcnt; |
---|
141 | |
---|
142 | extern long crcta[], crctb[]; /* CRC-16 generation tables */ |
---|
143 | |
---|
144 | /* |
---|
145 | Variables defined in this module but shared by other modules. |
---|
146 | */ |
---|
147 | |
---|
148 | long crc16 = 0L; /* File CRC = \v(crc16) */ |
---|
149 | int docrc = 1; |
---|
150 | int xfrbel = 1; |
---|
151 | |
---|
152 | char * rf_err = "Error receiving file"; /* rcvfil() error message */ |
---|
153 | |
---|
154 | #ifdef CK_SPEED |
---|
155 | short ctlp[256] = { /* Control-Prefix table */ |
---|
156 | 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 */ |
---|
157 | 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 */ |
---|
158 | 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, |
---|
159 | 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 */ |
---|
160 | 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 */ |
---|
161 | 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 */ |
---|
162 | 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, |
---|
163 | 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 */ |
---|
164 | }; |
---|
165 | #endif /* CK_SPEED */ |
---|
166 | |
---|
167 | int sndsrc; /* Flag for where to get names of files to send: */ |
---|
168 | /* -1: znext() function */ |
---|
169 | /* 0: stdin */ |
---|
170 | /* >0: list in cmlist */ |
---|
171 | |
---|
172 | int memstr; /* Flag for input from memory string */ |
---|
173 | int funcstr; /* Flag for input from function */ |
---|
174 | int bestlen = 0; |
---|
175 | int maxsend = 0; |
---|
176 | |
---|
177 | #ifdef pdp11 |
---|
178 | CHAR myinit[32]; /* Copy of my Send-Init data */ |
---|
179 | #else |
---|
180 | CHAR myinit[100]; /* Copy of my Send-Init data */ |
---|
181 | #endif /* pdp11 */ |
---|
182 | |
---|
183 | /* Variables local to this module */ |
---|
184 | |
---|
185 | #ifdef TLOG |
---|
186 | #ifndef XYZ_INTERNAL |
---|
187 | static |
---|
188 | #endif /* XYZ_INTERNAL */ |
---|
189 | char *fncnam[] = { |
---|
190 | "rename", "replace", "backup", "append", "discard", "ask", "update", "" |
---|
191 | }; |
---|
192 | #endif /* TLOG */ |
---|
193 | |
---|
194 | static char *memptr; /* Pointer for memory strings */ |
---|
195 | |
---|
196 | #ifdef CK_ANSI |
---|
197 | static int (*funcptr)(char *); /* Pointer for function strings */ |
---|
198 | #else |
---|
199 | static int (*funcptr)(); |
---|
200 | #endif /* CK_ANSI */ |
---|
201 | |
---|
202 | #ifdef pdp11 |
---|
203 | static char cmdstr[50]; /* System command string. */ |
---|
204 | #else |
---|
205 | static char cmdstr[256]; |
---|
206 | #endif /* pdp11 */ |
---|
207 | |
---|
208 | static int drain; /* For draining stacked-up ACKs. */ |
---|
209 | |
---|
210 | static int first; /* Flag for first char from input */ |
---|
211 | static CHAR t; /* Current character */ |
---|
212 | #ifdef COMMENT |
---|
213 | static CHAR next; /* Next character */ |
---|
214 | #endif /* COMMENT */ |
---|
215 | |
---|
216 | static int ebqsent = 0; /* 8th-bit prefix bid that I sent */ |
---|
217 | static int lsstate = 0; /* Locking shift state */ |
---|
218 | static int lsquote = 0; /* Locking shift quote */ |
---|
219 | |
---|
220 | #ifdef datageneral |
---|
221 | extern int quiet; |
---|
222 | #endif |
---|
223 | |
---|
224 | /* E N C S T R -- Encode a string from memory. */ |
---|
225 | |
---|
226 | /* |
---|
227 | Call this instead of getpkt() if source is a string, rather than a file. |
---|
228 | Note: Character set translation is never done in this case. |
---|
229 | */ |
---|
230 | |
---|
231 | #ifdef COMMENT |
---|
232 | #define ENCBUFL 200 |
---|
233 | #ifndef pdp11 |
---|
234 | CHAR encbuf[ENCBUFL]; |
---|
235 | #else |
---|
236 | /* This is gross, but the pdp11 root segment is out of space */ |
---|
237 | /* Will allocate it in ckuusr.c. */ |
---|
238 | extern CHAR encbuf[]; |
---|
239 | #endif /* pdp11 */ |
---|
240 | #endif /* COMMENT */ |
---|
241 | |
---|
242 | /* |
---|
243 | Encode packet data from a string in memory rather than from a file. |
---|
244 | Returns 0 on success, -1 if the string could not be completely encoded |
---|
245 | into the currently negotiated data field length. |
---|
246 | */ |
---|
247 | int |
---|
248 | encstr(s) CHAR* s; { |
---|
249 | #ifdef COMMENT |
---|
250 | int m; char *p; |
---|
251 | CHAR *dsave; |
---|
252 | |
---|
253 | if (!s) s = (CHAR *)""; |
---|
254 | if ((m = (int)strlen((char *)s)) > ENCBUFL) { |
---|
255 | debug(F111,"encstr string too long for buffer",s,ENCBUFL); |
---|
256 | s[ENCBUFL] = '\0'; |
---|
257 | } |
---|
258 | if (m > spsiz-bctl-3) { |
---|
259 | debug(F111,"encstr string too long for packet",s,spsiz-bctl-3); |
---|
260 | s[spsiz-bctl-3] = '\0'; |
---|
261 | } |
---|
262 | m = memstr; p = memptr; /* Save these. */ |
---|
263 | |
---|
264 | memptr = (char *)s; /* Point to the string. */ |
---|
265 | memstr = 1; /* Flag memory string as source. */ |
---|
266 | first = 1; /* Initialize character lookahead. */ |
---|
267 | dsave = data; /* Boy is this ugly... */ |
---|
268 | data = encbuf + 7; /* Why + 7? See spack()... */ |
---|
269 | *data = NUL; /* In case s is empty */ |
---|
270 | getpkt(spsiz,0); /* Fill a packet from the string. */ |
---|
271 | data = dsave; /* (sorry...) */ |
---|
272 | memstr = m; /* Restore memory string flag */ |
---|
273 | memptr = p; /* and pointer */ |
---|
274 | first = 1; /* Put this back as we found it. */ |
---|
275 | return(0); |
---|
276 | #else |
---|
277 | /* |
---|
278 | Recoded 30 Jul 94 to use the regular data buffer and the negotiated |
---|
279 | maximum packet size. Previously we were limited to the length of encbuf[]. |
---|
280 | Also, to return a failure code if the entire encoded string would not fit. |
---|
281 | */ |
---|
282 | int m, rc, slen; char *p; |
---|
283 | if (!s) s = (CHAR *)""; /* Watch out for null pointers. */ |
---|
284 | slen = strlen((char *)s); /* Length of source string. */ |
---|
285 | rc = 0; /* Return code. */ |
---|
286 | m = memstr; p = memptr; /* Save these. */ |
---|
287 | memptr = (char *)s; /* Point to the string. */ |
---|
288 | memstr = 1; /* Flag memory string as source. */ |
---|
289 | first = 1; /* Initialize character lookahead. */ |
---|
290 | *data = NUL; /* In case s is empty */ |
---|
291 | getpkt(spsiz,0); /* Fill a packet from the string. */ |
---|
292 | |
---|
293 | if ( |
---|
294 | #ifdef COMMENT |
---|
295 | *memptr |
---|
296 | #else |
---|
297 | memptr < (char *)(s + slen) |
---|
298 | #endif /* COMMENT */ |
---|
299 | ) { /* This means we didn't encode */ |
---|
300 | rc = -1; /* the whole string. */ |
---|
301 | debug(F101,"encstr string too big","",size); |
---|
302 | } else |
---|
303 | debug(F101,"encstr fits OK, size","",size); |
---|
304 | memstr = m; /* Restore memory string flag */ |
---|
305 | memptr = p; /* and pointer */ |
---|
306 | first = 1; /* Put this back as we found it. */ |
---|
307 | return(rc); |
---|
308 | #endif /* COMMENT */ |
---|
309 | } |
---|
310 | |
---|
311 | #ifdef COMMENT |
---|
312 | /* |
---|
313 | We don't use this routine any more -- the code has been incorporated |
---|
314 | directly into getpkt() to reduce per-character function call overhead. |
---|
315 | Also, watch out: this routine hasn't been updated since it was commented |
---|
316 | out a long time ago. |
---|
317 | */ |
---|
318 | /* E N C O D E - Kermit packet encoding procedure */ |
---|
319 | |
---|
320 | VOID |
---|
321 | encode(a) CHAR a; { /* The current character */ |
---|
322 | int a7; /* Low order 7 bits of character */ |
---|
323 | int b8; /* 8th bit of character */ |
---|
324 | |
---|
325 | #ifndef NOCSETS |
---|
326 | if (!binary && sx) a = (*sx)(a); /* Translate. */ |
---|
327 | #endif /* NOCSETS */ |
---|
328 | |
---|
329 | if (rptflg) { /* Repeat processing? */ |
---|
330 | if (a == next && (first == 0)) { /* Got a run... */ |
---|
331 | if (++rpt < 94) /* Below max, just count */ |
---|
332 | return; |
---|
333 | else if (rpt == 94) { /* Reached max, must dump */ |
---|
334 | data[size++] = rptq; |
---|
335 | data[size++] = tochar(rpt); |
---|
336 | rptn += rpt; /* Count, for stats */ |
---|
337 | rpt = 0; |
---|
338 | } |
---|
339 | } else if (rpt == 1) { /* Run broken, only 2? */ |
---|
340 | rpt = 0; /* Yes, reset repeat flag & count. */ |
---|
341 | encode(a); /* Do the character twice. */ |
---|
342 | if (size <= maxsize) osize = size; |
---|
343 | rpt = 0; |
---|
344 | encode(a); |
---|
345 | return; |
---|
346 | } else if (rpt > 1) { /* More than two */ |
---|
347 | data[size++] = rptq; /* Insert the repeat prefix */ |
---|
348 | data[size++] = tochar(++rpt); /* and count. */ |
---|
349 | rptn += rpt; |
---|
350 | rpt = 0; /* Reset repeat counter. */ |
---|
351 | } |
---|
352 | } |
---|
353 | a7 = a & 0177; /* Isolate ASCII part */ |
---|
354 | b8 = a & 0200; /* and 8th (parity) bit. */ |
---|
355 | |
---|
356 | if (ebqflg && b8) { /* Do 8th bit prefix if necessary. */ |
---|
357 | data[size++] = ebq; |
---|
358 | a = a7; |
---|
359 | } |
---|
360 | if ((a7 < SP) || (a7==DEL)) { /* Do control prefix if necessary */ |
---|
361 | data[size++] = myctlq; |
---|
362 | a = ctl(a); |
---|
363 | } |
---|
364 | if (a7 == myctlq) /* Prefix the control prefix */ |
---|
365 | data[size++] = myctlq; |
---|
366 | |
---|
367 | if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */ |
---|
368 | data[size++] = myctlq; /* quote it if doing repeat counts. */ |
---|
369 | |
---|
370 | if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */ |
---|
371 | data[size++] = myctlq; /* if doing 8th-bit prefixes */ |
---|
372 | |
---|
373 | data[size++] = a; /* Finally, insert the character */ |
---|
374 | data[size] = '\0'; /* itself, and mark the end. */ |
---|
375 | } |
---|
376 | #endif /* COMMENT */ |
---|
377 | |
---|
378 | /* Output functions passed to 'decode': */ |
---|
379 | |
---|
380 | int /* Put character in server command buffer */ |
---|
381 | #ifdef CK_ANSIC |
---|
382 | putsrv(char c) |
---|
383 | #else |
---|
384 | putsrv(c) register char c; |
---|
385 | #endif /* CK_ANSIC */ |
---|
386 | /* putsrv */ { |
---|
387 | *srvptr++ = c; |
---|
388 | *srvptr = '\0'; /* Make sure buffer is null-terminated */ |
---|
389 | return(0); |
---|
390 | } |
---|
391 | |
---|
392 | int /* Output character to console. */ |
---|
393 | #ifdef CK_ANSIC |
---|
394 | puttrm(char c) |
---|
395 | #else |
---|
396 | puttrm(c) register char c; |
---|
397 | #endif /* CK_ANSIC */ |
---|
398 | /* puttrm */ { |
---|
399 | #ifndef NOSPL |
---|
400 | extern char * qbufp; /* If REMOTE QUERY active, */ |
---|
401 | extern int query, qbufn; /* also store response in */ |
---|
402 | if (query && qbufn++ < 1024) { /* query buffer. */ |
---|
403 | *qbufp++ = c; |
---|
404 | *qbufp = NUL; |
---|
405 | } /* else */ /* else means don't display */ |
---|
406 | #endif /* NOSPL */ |
---|
407 | conoc(c); |
---|
408 | return(0); |
---|
409 | } |
---|
410 | |
---|
411 | int /* Output char to file. */ |
---|
412 | #ifdef CK_ANSIC |
---|
413 | putfil(char c) |
---|
414 | #else |
---|
415 | putfil(c) register char c; |
---|
416 | #endif /* CK_ANSIC */ |
---|
417 | /* putfil */ { |
---|
418 | if (zchout(ZOFILE, (char) (c & fmask)) < 0) { |
---|
419 | czseen = 1; /* If write error... */ |
---|
420 | debug(F101,"putfil zchout write error, setting czseen","",1); |
---|
421 | return(-1); |
---|
422 | } |
---|
423 | return(0); |
---|
424 | } |
---|
425 | |
---|
426 | /* D E C O D E -- Kermit packet decoding procedure */ |
---|
427 | |
---|
428 | /* |
---|
429 | Call with string to be decoded and an output function. |
---|
430 | Returns 0 on success, -1 on failure (e.g. disk full). |
---|
431 | |
---|
432 | This is the "inner loop" when receiving files, and must be coded as |
---|
433 | efficiently as possible. Note some potential problems: if a packet |
---|
434 | is badly formed, having a prefixed sequence ending prematurely, this |
---|
435 | function, as coded, could read past the end of the packet. This has |
---|
436 | never happened, thus the additional (time-consuming) tests have not |
---|
437 | been added. |
---|
438 | */ |
---|
439 | |
---|
440 | static CHAR *xdbuf; /* Global version of decode()'s buffer pointer */ |
---|
441 | /* for use by translation functions. */ |
---|
442 | |
---|
443 | /* Function for pushing a character onto decode()'s input stream. */ |
---|
444 | |
---|
445 | VOID |
---|
446 | #ifdef CK_ANSIC |
---|
447 | zdstuff(CHAR c) |
---|
448 | #else |
---|
449 | zdstuff(c) CHAR c; |
---|
450 | #endif /* CK_ANSIC */ |
---|
451 | /* zdstuff */ { |
---|
452 | xdbuf--; /* Back up the pointer. */ |
---|
453 | *xdbuf = c; /* Stuff the character. */ |
---|
454 | } |
---|
455 | |
---|
456 | int |
---|
457 | #ifdef CK_ANSIC |
---|
458 | decode(CHAR *buf, int (*fn)(char), int xlate) |
---|
459 | #else |
---|
460 | decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate; |
---|
461 | #endif /* CK_ANSIC */ |
---|
462 | /* decode */ { |
---|
463 | register unsigned int a, a7, a8, b8; /* Various copies of current char */ |
---|
464 | int t; /* Int version of character */ |
---|
465 | int ssflg; /* Character was single-shifted */ |
---|
466 | int ccpflg; /* For Ctrl-unprefixing stats */ |
---|
467 | long z; |
---|
468 | CHAR c; |
---|
469 | /* |
---|
470 | Catch the case in which we are asked to decode into a file that is not open, |
---|
471 | for example, if the user interrupted the transfer, but the other Kermit |
---|
472 | keeps sending. |
---|
473 | */ |
---|
474 | if ((cxseen || czseen || discard) && (fn == putfil)) |
---|
475 | return(0); |
---|
476 | |
---|
477 | xdbuf = buf; /* Make global copy of pointer. */ |
---|
478 | rpt = 0; /* Initialize repeat count. */ |
---|
479 | |
---|
480 | while ((a = *xdbuf++ & 0xFF) != '\0') { /* Get next character. */ |
---|
481 | if (a == rptq && rptflg) { /* Got a repeat prefix? */ |
---|
482 | rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */ |
---|
483 | rptn += rpt; |
---|
484 | a = *xdbuf++ & 0xFF; /* and get the prefixed character. */ |
---|
485 | } |
---|
486 | b8 = lsstate ? 0200 : 0; /* 8th-bit value from SHIFT-STATE */ |
---|
487 | if (ebqflg && a == ebq) { /* Have 8th-bit prefix? */ |
---|
488 | b8 ^= 0200; /* Yes, invert the 8th bit's value, */ |
---|
489 | ssflg = 1; /* remember we did this, */ |
---|
490 | a = *xdbuf++ & 0xFF; /* and get the prefixed character. */ |
---|
491 | } else ssflg = 0; |
---|
492 | |
---|
493 | ccpflg = 0; |
---|
494 | if (a == ctlq) { /* If control prefix, */ |
---|
495 | a = *xdbuf++ & 0xFF; /* get its operand */ |
---|
496 | a7 = a & 0x7F; /* and its low 7 bits. */ |
---|
497 | if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */ |
---|
498 | a = ctl(a); /* if in control range. */ |
---|
499 | a7 = a & 0x7F; |
---|
500 | ccpflg = 1; /* Note that we did this */ |
---|
501 | ccp++; /* Count for stats */ |
---|
502 | } |
---|
503 | } else a7 = a & 0x7f; /* Not control quote */ |
---|
504 | |
---|
505 | if (a7 < 32 || a7 == 127) { /* Control character? */ |
---|
506 | if (!ccpflg) ccu++; /* A bare one, count it */ |
---|
507 | if (lscapu) { /* If doing locking shifts... */ |
---|
508 | if (lsstate) /* If SHIFTED */ |
---|
509 | a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */ |
---|
510 | else /* otherwise */ |
---|
511 | a8 = a | b8; /* OR in 8th bit */ |
---|
512 | /* If we're not in a quoted sequence */ |
---|
513 | if (!lsquote && (!lsstate || !ssflg)) { |
---|
514 | if (a8 == DLE) { /* Check for DLE quote */ |
---|
515 | lsquote = 1; /* prefixed by single shift! */ |
---|
516 | continue; |
---|
517 | } else if (a8 == SO) { /* Check for Shift-Out */ |
---|
518 | lsstate = 1; /* SHIFT-STATE = SHIFTED */ |
---|
519 | continue; |
---|
520 | } else if (a8 == SI) { /* or Shift-In */ |
---|
521 | lsstate = 0; /* SHIFT-STATE = UNSHIFTED */ |
---|
522 | continue; |
---|
523 | } |
---|
524 | } else lsquote = 0; |
---|
525 | } |
---|
526 | } |
---|
527 | a |= b8; /* OR in the 8th bit */ |
---|
528 | if (rpt == 0) rpt = 1; /* If no repeats, then one */ |
---|
529 | if (!binary) { /* If in text mode, */ |
---|
530 | if (feol && a == CR) continue; /* Convert CRLF to newline char */ |
---|
531 | if (feol && a == LF) a = feol; |
---|
532 | |
---|
533 | #ifndef NOCSETS /* Character-set translation */ |
---|
534 | #ifdef KANJI /* For Kanji transfers, */ |
---|
535 | if (tcharset != TC_JEUC) /* postpone translation. */ |
---|
536 | #endif /* KANJI */ |
---|
537 | if (xlate && rx) a = (*rx)((CHAR) a); /* Translate charset */ |
---|
538 | #endif /* NOCSETS */ |
---|
539 | } |
---|
540 | if (fn == putfil) { /* (PWP) speedup via buffered output and a macro */ |
---|
541 | for (; rpt > 0; rpt--) { /* Output the char RPT times */ |
---|
542 | #ifndef NOCSETS |
---|
543 | #ifdef KANJI |
---|
544 | if (!binary && tcharset == TC_JEUC && |
---|
545 | fcharset != FC_JEUC) { /* Translating from J-EUC */ |
---|
546 | if (ffc == 0L) xkanjf(); |
---|
547 | if (xkanji(a,fn) < 0) /* to something else? */ |
---|
548 | return(-1); |
---|
549 | else t = 1; |
---|
550 | } else |
---|
551 | #endif /* KANJI */ |
---|
552 | #endif /* NOCSETS */ |
---|
553 | #ifdef OS2 |
---|
554 | if (xflg && !remfile) { /* Write to virtual screen */ |
---|
555 | char _a; |
---|
556 | _a = a & fmask; |
---|
557 | t = conoc(_a); |
---|
558 | if (t < 1) t = -1; |
---|
559 | } else |
---|
560 | #endif /* OS2 */ |
---|
561 | t = zmchout(a & fmask); /* zmchout is a macro */ |
---|
562 | if (t < 0) { |
---|
563 | debug(F101,"decode _write error - errno","",errno); |
---|
564 | return(-1); |
---|
565 | } |
---|
566 | #ifdef COMMENT |
---|
567 | if (ffc == 0 && filcnt <= 1) { |
---|
568 | debug(F101,"decode new file, filcnt","",filcnt); |
---|
569 | debug(F101,"decode crc16","",crc16); |
---|
570 | crc16 = 0L; /* Should already have been done */ |
---|
571 | } |
---|
572 | #endif /* COMMENT */ |
---|
573 | ffc++; /* Count the character */ |
---|
574 | if (docrc && !xflg && !remfile) { /* Update file CRC */ |
---|
575 | c = a; /* Force conversion to unsigned char */ |
---|
576 | z = crc16 ^ (long)c; |
---|
577 | crc16 = (crc16 >> 8) ^ |
---|
578 | (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]); |
---|
579 | } |
---|
580 | } |
---|
581 | } else { /* Output to something else. */ |
---|
582 | a &= fmask; /* Apply file mask */ |
---|
583 | for (; rpt > 0; rpt--) { /* Output the char RPT times */ |
---|
584 | if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */ |
---|
585 | #ifdef COMMENT |
---|
586 | /* |
---|
587 | This was causing the server to count extra bytes that were part of |
---|
588 | server command packets, like FINISH. |
---|
589 | */ |
---|
590 | ffc++; |
---|
591 | #endif /* COMMENT */ |
---|
592 | } |
---|
593 | } |
---|
594 | } |
---|
595 | return(0); |
---|
596 | } |
---|
597 | |
---|
598 | /* G E T P K T -- Fill a packet data field */ |
---|
599 | |
---|
600 | /* |
---|
601 | Gets characters from the current source -- file or memory string. |
---|
602 | Encodes the data into the packet, filling the packet optimally. |
---|
603 | Set first = 1 when calling for the first time on a given input stream |
---|
604 | (string or file). |
---|
605 | |
---|
606 | Call with: |
---|
607 | bufmax -- current send-packet size |
---|
608 | xlate -- flag: 0 to skip character-set translation, 1 to translate |
---|
609 | |
---|
610 | Uses global variables: |
---|
611 | t -- current character. |
---|
612 | first -- flag: 1 to start up, 0 for input in progress, -1 for EOF. |
---|
613 | next -- next character (not used any more). |
---|
614 | data -- pointer to the packet data buffer. |
---|
615 | size -- number of characters in the data buffer. |
---|
616 | memstr - flag that input is coming from a memory string instead of a file. |
---|
617 | memptr - pointer to string in memory. |
---|
618 | (*sx)() character set translation function |
---|
619 | |
---|
620 | Returns the size as value of the function, and also sets global "size", |
---|
621 | and fills (and null-terminates) the global data array. Returns 0 upon eof. |
---|
622 | |
---|
623 | Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989. |
---|
624 | Incorporates old getchx() and encode() inline to reduce function calls, |
---|
625 | uses buffered input for much-improved efficiency, and clears up some |
---|
626 | confusion with line termination (CRLF vs LF vs CR). |
---|
627 | |
---|
628 | Rewritten again by Frank da Cruz to incorporate locking shift mechanism, |
---|
629 | May 1991. |
---|
630 | */ |
---|
631 | |
---|
632 | /* |
---|
633 | Lookahead function to decide whether locking shift is worth it. Looks at |
---|
634 | the next four input characters to see if all of their 8th bits match the |
---|
635 | argument. Call with 0 or 0200. Returns 1 if so, 0 if not. If we don't |
---|
636 | happen to have at least 4 more characters waiting in the input buffer, |
---|
637 | returns 1. Note that zinptr points two characters ahead of the current |
---|
638 | character because of repeat-count lookahead. |
---|
639 | */ |
---|
640 | |
---|
641 | #ifdef KANJI |
---|
642 | int |
---|
643 | kgetf( |
---|
644 | #ifdef CK_ANSIC |
---|
645 | VOID |
---|
646 | #endif /* CK_ANSIC */ |
---|
647 | ) { |
---|
648 | if (funcstr) |
---|
649 | return((*funcptr)()); |
---|
650 | else |
---|
651 | return(zminchar()); |
---|
652 | } |
---|
653 | |
---|
654 | int |
---|
655 | kgetm( |
---|
656 | #ifdef CK_ANSIC |
---|
657 | VOID |
---|
658 | #endif /* CK_ANSIC */ |
---|
659 | ) { |
---|
660 | int x; |
---|
661 | if (x = *memptr++) return(x); |
---|
662 | else return(-1); |
---|
663 | } |
---|
664 | #endif /* KANJI */ |
---|
665 | |
---|
666 | int |
---|
667 | lslook(b) unsigned int b; { /* Locking Shift Lookahead */ |
---|
668 | int i; |
---|
669 | if (zincnt < 3) /* If not enough chars in buffer, */ |
---|
670 | return(1); /* force shift-state switch. */ |
---|
671 | b &= 0200; /* Force argument to proper form. */ |
---|
672 | for (i = -1; i < 3; i++) /* Look at next 5 characters to */ |
---|
673 | if (((*(zinptr+i)) & 0200) != b) /* see if all their 8th bits match. */ |
---|
674 | return(0); /* They don't. */ |
---|
675 | return(1); /* They do. */ |
---|
676 | } |
---|
677 | |
---|
678 | int |
---|
679 | getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */ |
---|
680 | register CHAR rt = t, rnext; /* Register shadows of the globals */ |
---|
681 | register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */ |
---|
682 | register int x; /* Loop index. */ |
---|
683 | register int a7; /* Low 7 bits of character */ |
---|
684 | |
---|
685 | static CHAR leftover[9] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0' }; |
---|
686 | |
---|
687 | CHAR xxls, xxdl, xxrc, xxss, xxcq; /* Pieces of prefixed sequence */ |
---|
688 | int n; /* worker */ |
---|
689 | |
---|
690 | long z; /* A long worker (for CRC) */ |
---|
691 | /* |
---|
692 | Assume bufmax is the receiver's total receive-packet buffer length. |
---|
693 | Our whole packet has to fit into it, so we adjust the data field length. |
---|
694 | We also decide optimally whether it is better to use a short-format or |
---|
695 | long-format packet when we're near the borderline. |
---|
696 | */ |
---|
697 | n = bufmax - 5; /* Space for Data and Checksum */ |
---|
698 | if (n > 92 && n < 96) n = 92; /* "Short" Long packets don't pay */ |
---|
699 | if (n > 92 && lpcapu == 0) /* If long packets needed, */ |
---|
700 | n = 92; /* make sure they've been negotiated */ |
---|
701 | bufmax = n - bctl; /* Space for data */ |
---|
702 | if (n > 92) bufmax -= 3; /* Long packet needs header chksum */ |
---|
703 | |
---|
704 | if (first == 1) { /* If first character of this file... */ |
---|
705 | if (!memstr && ! funcstr) /* and real file... */ |
---|
706 | ffc = 0L; /* reset file character counter */ |
---|
707 | first = 0; /* Next character won't be first */ |
---|
708 | *leftover = '\0'; /* Discard any interrupted leftovers */ |
---|
709 | |
---|
710 | /* get first character of file into rt, watching out for null file */ |
---|
711 | |
---|
712 | #ifndef NOCSETS |
---|
713 | #ifdef KANJI |
---|
714 | if (!binary && tcharset == TC_JEUC && xlate) { |
---|
715 | x = zkanjf(); |
---|
716 | if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) { |
---|
717 | first = -1; |
---|
718 | size = 0; |
---|
719 | if (x == -2) { |
---|
720 | debug(F100,"getpkt(zkanji): input error","",0); |
---|
721 | cxseen = 1; |
---|
722 | } else debug(F100,"getpkt(zkanji): empty string/file","",0); |
---|
723 | return (0); |
---|
724 | } |
---|
725 | rt = x; |
---|
726 | if (!memstr) { |
---|
727 | ffc++; |
---|
728 | if (docrc && what == W_SEND) { /* Accumulate file crc */ |
---|
729 | z = crc16 ^ (long)rt; |
---|
730 | crc16 = (crc16 >> 8) ^ |
---|
731 | (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]); |
---|
732 | } |
---|
733 | } |
---|
734 | } else { |
---|
735 | #endif /* KANJI */ |
---|
736 | #endif /* not NOCSETS */ |
---|
737 | if (memstr) { /* Reading data from memory string */ |
---|
738 | if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */ |
---|
739 | first = -1; |
---|
740 | size = 0; |
---|
741 | debug(F100,"getpkt: empty string","",0); |
---|
742 | return (0); |
---|
743 | } |
---|
744 | |
---|
745 | } else if (funcstr) { /* Reading data from a function */ |
---|
746 | |
---|
747 | if ((x = (*funcptr)()) < 0) { /* End of input */ |
---|
748 | first = -1; |
---|
749 | size = 0; |
---|
750 | debug(F100,"getpkt: empty input function","",0); /* Empty */ |
---|
751 | return(0); |
---|
752 | } |
---|
753 | ffc++; /* Count a file character */ |
---|
754 | rt = (CHAR) x; /* Convert int to char */ |
---|
755 | debug(F101,"getpkt funcstr","",rt); |
---|
756 | |
---|
757 | } else { /* Reading data from a file */ |
---|
758 | |
---|
759 | if ((x = zminchar()) < 0) { /* End of file or input error */ |
---|
760 | first = -1; |
---|
761 | size = 0; |
---|
762 | if (x == -2) { /* Error */ |
---|
763 | debug(F100,"getpkt: input error","",0); |
---|
764 | cxseen = 1; /* Interrupt the file transfer */ |
---|
765 | } else { |
---|
766 | debug(F100,"getpkt empty file","",0); |
---|
767 | } |
---|
768 | return(0); |
---|
769 | } |
---|
770 | ffc++; /* Count a file character */ |
---|
771 | rt = (CHAR) x; /* Convert int to char */ |
---|
772 | debug(F101,"getpkt 1st char","",rt); |
---|
773 | if (docrc && what == W_SEND) { /* Accumulate file crc */ |
---|
774 | z = crc16 ^ (long)rt; |
---|
775 | crc16 = (crc16 >> 8) ^ |
---|
776 | (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]); |
---|
777 | } |
---|
778 | } |
---|
779 | #ifndef NOCSETS |
---|
780 | #ifdef KANJI |
---|
781 | } |
---|
782 | #endif /* KANJI */ |
---|
783 | #endif /* not NOCSETS */ |
---|
784 | |
---|
785 | rt &= fmask; /* Apply SET FILE BYTESIZE mask */ |
---|
786 | debug(F101,"getpkt fmask","",fmask); |
---|
787 | debug(F101,"getpkt new rt","",rt); |
---|
788 | |
---|
789 | #ifndef NOCSETS |
---|
790 | if (xlate) { |
---|
791 | debug(F101,"getpkt about to call translate function","",rt); |
---|
792 | debug(F101,"tcharset","",tcharset); |
---|
793 | debug(F101,"fcharset","",fcharset); |
---|
794 | } |
---|
795 | #ifdef KANJI |
---|
796 | if (tcharset != TC_JEUC) |
---|
797 | #endif /* KANJI */ |
---|
798 | if (!binary && sx && xlate) { |
---|
799 | rt = (*sx)(rt); /* Translate */ |
---|
800 | debug(F101," translate function returns","",rt); |
---|
801 | } |
---|
802 | #endif /* not NOCSETS */ |
---|
803 | |
---|
804 | /* PWP: handling of feol is done later (in the while loop)... */ |
---|
805 | |
---|
806 | } else if ((first == -1) && (*leftover == '\0')) { /* EOF from last time */ |
---|
807 | debug(F101,"getpkt eof crc16","",crc16); |
---|
808 | debug(F101,"getpkt eof ffc","",ffc); |
---|
809 | return(size = 0); |
---|
810 | } |
---|
811 | /* |
---|
812 | Here we handle characters that were encoded for the last packet but |
---|
813 | did not fit, and so were saved in the "leftover" array. |
---|
814 | */ |
---|
815 | dp = data; /* Point to packet data buffer */ |
---|
816 | for (p1 = leftover; (*dp = *p1) != '\0'; p1++, dp++) /* Copy leftovers */ |
---|
817 | ; |
---|
818 | *leftover = '\0'; /* Delete leftovers */ |
---|
819 | if (first == -1) /* Handle EOF */ |
---|
820 | return(size = (dp - data)); |
---|
821 | |
---|
822 | /* Now fill up the rest of the packet. */ |
---|
823 | |
---|
824 | rpt = 0; /* Initialize character repeat count */ |
---|
825 | |
---|
826 | while (first > -1) { /* Until EOF... */ |
---|
827 | #ifndef NOCSETS |
---|
828 | #ifdef KANJI |
---|
829 | if (!binary && xlate && tcharset == TC_JEUC) { |
---|
830 | if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) { |
---|
831 | first = -1; |
---|
832 | if (x == -2) cxseen = 1; |
---|
833 | } else if (!memstr) ffc++; |
---|
834 | rnext = (CHAR) (x & fmask); |
---|
835 | } else { |
---|
836 | #endif /* KANJI */ |
---|
837 | #endif /* not NOCSETS */ |
---|
838 | if (memstr) { /* Get next char from memory string */ |
---|
839 | if ((x = *memptr++) == '\0') /* End of string means EOF */ |
---|
840 | first = -1; /* Flag EOF for next time. */ |
---|
841 | rnext = (CHAR) (x & fmask); /* Apply file mask */ |
---|
842 | } else if (funcstr) { /* Get next char from function */ |
---|
843 | if ((x = (*funcptr)()) < 0) /* End of string means EOF */ |
---|
844 | first = -1; /* Flag EOF for next time. */ |
---|
845 | rnext = (CHAR) (x & fmask); /* Apply file mask */ |
---|
846 | } else { |
---|
847 | if ((x = zminchar()) < 0) { /* Real file, check for EOF */ |
---|
848 | first = -1; /* Flag eof for next time. */ |
---|
849 | if (x == -2) cxseen = 1; /* If error, cancel this file. */ |
---|
850 | } else { |
---|
851 | ffc++; /* Count the character */ |
---|
852 | if (docrc && what == W_SEND) { /* Accumulate file crc */ |
---|
853 | z = crc16 ^ (long)((CHAR)x & 0xff); |
---|
854 | crc16 = (crc16 >> 8) ^ |
---|
855 | (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]); |
---|
856 | } |
---|
857 | } |
---|
858 | rnext = (CHAR) (x & fmask); /* Apply file mask */ |
---|
859 | } |
---|
860 | #ifndef NOCSETS |
---|
861 | #ifdef KANJI |
---|
862 | } |
---|
863 | #endif /* KANJI */ |
---|
864 | #endif /* not NOCSETS */ |
---|
865 | |
---|
866 | #ifndef NOCSETS |
---|
867 | #ifdef KANJI |
---|
868 | if (tcharset != TC_JEUC) |
---|
869 | #endif /* KANJI */ |
---|
870 | if (!binary && sx && xlate) { |
---|
871 | rnext = (*sx)(rnext); /* Translate */ |
---|
872 | debug(F101,"getpkt xlated rnext to","",rnext); |
---|
873 | } |
---|
874 | #endif /* not NOCSETS */ |
---|
875 | |
---|
876 | odp = dp; /* Remember where we started. */ |
---|
877 | xxls = xxdl = xxrc = xxss = xxcq = NUL; /* Clear these. */ |
---|
878 | |
---|
879 | /* |
---|
880 | Now encode the character according to the options that are in effect: |
---|
881 | ctlp[]: whether this control character needs prefixing. |
---|
882 | binary: text or binary mode. |
---|
883 | rptflg: repeat counts enabled. |
---|
884 | ebqflg: 8th-bit prefixing enabled. |
---|
885 | lscapu: locking shifts enabled. |
---|
886 | */ |
---|
887 | if (rptflg) { /* Repeat processing is on? */ |
---|
888 | if ( |
---|
889 | /* |
---|
890 | * If the next char is really CRLF, then we cannot |
---|
891 | * be doing a repeat (unless CR,CR,LF which becomes |
---|
892 | * "~ <n-1> CR CR LF", which is OK but not most efficient). |
---|
893 | * I just plain don't worry about this case. The actual |
---|
894 | * conversion from NL to CRLF is done after the rptflg if... |
---|
895 | */ |
---|
896 | (binary || (feol && (rnext != feol))) && |
---|
897 | |
---|
898 | (rt == rnext) && (first == 0)) { /* Got a run... */ |
---|
899 | if (++rpt < 94) { /* Below max, just count */ |
---|
900 | continue; /* go back and get another */ |
---|
901 | } |
---|
902 | else if (rpt == 94) { /* Reached max, must dump */ |
---|
903 | xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */ |
---|
904 | rptn += rpt; /* Accumulate it for statistics */ |
---|
905 | rpt = 0; /* And reset it */ |
---|
906 | } |
---|
907 | } else if (rpt > 1) { /* More than two */ |
---|
908 | xxrc = (CHAR) tochar(++rpt); /* and count. */ |
---|
909 | rptn += rpt; |
---|
910 | rpt = 0; /* Reset repeat counter. */ |
---|
911 | } |
---|
912 | /* |
---|
913 | If (rpt == 1) we must encode exactly two characters. |
---|
914 | This is done later, after the first character is encoded. |
---|
915 | */ |
---|
916 | } |
---|
917 | |
---|
918 | if (!binary && feol && (rt == feol)) { /* It's the newline character */ |
---|
919 | if (lscapu && lsstate) { /* If SHIFT-STATE is SHIFTED */ |
---|
920 | if (ebqflg) { /* If single shifts enabled, */ |
---|
921 | *dp++ = (CHAR) ebq; /* insert a single shift. */ |
---|
922 | } else { /* Otherwise must shift in. */ |
---|
923 | *dp++ = myctlq; /* Insert shift-out code */ |
---|
924 | *dp++ = 'O'; |
---|
925 | lsstate = 0; /* Change shift state */ |
---|
926 | } |
---|
927 | } |
---|
928 | #ifdef CK_SPEED |
---|
929 | if (ctlp[CR]) { |
---|
930 | *dp++ = myctlq; /* Insert carriage return directly */ |
---|
931 | *dp++ = 'M'; |
---|
932 | ccp++; |
---|
933 | } else { |
---|
934 | *dp++ = CR; /* Perhaps literally */ |
---|
935 | ccu++; |
---|
936 | } |
---|
937 | #else /* !CK_SPEED */ |
---|
938 | *dp++ = myctlq; /* Insert carriage return directly */ |
---|
939 | *dp++ = 'M'; |
---|
940 | ccp++; |
---|
941 | #endif /* CK_SPEED */ |
---|
942 | rt = LF; /* Now make next char be linefeed. */ |
---|
943 | } |
---|
944 | /* |
---|
945 | Now handle the 8th bit of the file character. If we have an 8-bit |
---|
946 | connection, we preserve the 8th bit. If we have a 7-bit connection, |
---|
947 | we employ either single or locking shifts (if they are enabled). |
---|
948 | */ |
---|
949 | a7 = rt & 0177; /* Get low 7 bits of character */ |
---|
950 | if (rt & 0200) { /* 8-bit character? */ |
---|
951 | if (lscapu) { /* Locking shifts enabled? */ |
---|
952 | if (!lsstate) { /* Not currently shifted? */ |
---|
953 | x = lslook(0200); /* Look ahead */ |
---|
954 | if (x != 0 || ebqflg == 0) { /* Locking shift decision */ |
---|
955 | xxls = 'N'; /* Need locking shift-out */ |
---|
956 | lsstate = 1; /* and change to shifted state */ |
---|
957 | } else if (ebqflg) { /* Not worth it */ |
---|
958 | xxss = (CHAR) ebq; /* Use single shift */ |
---|
959 | } |
---|
960 | } |
---|
961 | rt = (CHAR) a7; /* Replace character by 7-bit value */ |
---|
962 | } else if (ebqflg) { /* 8th bit prefixing is on? */ |
---|
963 | xxss = (CHAR) ebq; /* Insert single shift */ |
---|
964 | rt = (CHAR) a7; /* Replace character by 7-bit value */ |
---|
965 | } |
---|
966 | /* |
---|
967 | In case we have a 7-bit connection and this is an 8-bit character, AND |
---|
968 | neither locking shifts nor single shifts are enabled, then the character's |
---|
969 | 8th bit will be destroyed in transmission, and a block check error will |
---|
970 | occur. |
---|
971 | */ |
---|
972 | } else if (lscapu) { /* 7-bit character */ |
---|
973 | |
---|
974 | if (lsstate) { /* Comes while shifted out? */ |
---|
975 | x = lslook(0); /* Yes, look ahead */ |
---|
976 | if (x || ebqflg == 0) { /* Time to shift in. */ |
---|
977 | xxls = 'O'; /* Set shift-in code */ |
---|
978 | lsstate = 0; /* Exit shifted state */ |
---|
979 | } else if (ebqflg) { /* Not worth it, stay shifted out */ |
---|
980 | xxss = (CHAR) ebq; /* Insert single shift */ |
---|
981 | } |
---|
982 | } |
---|
983 | } |
---|
984 | /* If data character is significant to locking shift protocol... */ |
---|
985 | if (lscapu && (a7 == SO || a7 == SI || a7 == DLE)) |
---|
986 | xxdl = 'P'; /* Insert datalink escape */ |
---|
987 | |
---|
988 | if ( |
---|
989 | #ifdef CK_SPEED |
---|
990 | /* |
---|
991 | Thwart YET ANOTHER unwanted, unneeded, and unloved sign |
---|
992 | extension. This one was particularly nasty because it prevented |
---|
993 | 255 (Telnet IAC) from being prefixed on some platforms -- e.g. |
---|
994 | VMS with VAX C -- but not others, thus causing file transfers to |
---|
995 | fail on Telnet connections by sending bare IACs. Not to mention |
---|
996 | the stray memory reference. Whoever thought it was a good idea |
---|
997 | for characters to be signed (by default or at all) should have |
---|
998 | thunk again. (Sep 96) |
---|
999 | */ |
---|
1000 | ctlp[(rt & 0xff)] /* Lop off any "sign" extension */ |
---|
1001 | #else |
---|
1002 | (a7 < SP) || (a7 == DEL) |
---|
1003 | #endif /* CK_SPEED */ |
---|
1004 | ) { /* Do control prefixing if necessary */ |
---|
1005 | xxcq = myctlq; /* The prefix */ |
---|
1006 | ccp++; /* Count it */ |
---|
1007 | rt = (CHAR) ctl(rt); /* Uncontrollify the character */ |
---|
1008 | } |
---|
1009 | #ifdef CK_SPEED |
---|
1010 | else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */ |
---|
1011 | ccu++; |
---|
1012 | #endif /* CK_SPEED */ |
---|
1013 | |
---|
1014 | if (a7 == myctlq) /* Always prefix the control prefix */ |
---|
1015 | xxcq = myctlq; |
---|
1016 | |
---|
1017 | if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */ |
---|
1018 | xxcq = myctlq; /* prefix it if doing repeat counts */ |
---|
1019 | |
---|
1020 | if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th-bit prefix */ |
---|
1021 | xxcq = myctlq; /* if doing 8th-bit prefixes */ |
---|
1022 | |
---|
1023 | /* Now construct the entire sequence */ |
---|
1024 | |
---|
1025 | if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */ |
---|
1026 | odp2 = dp; /* (Save this place) */ |
---|
1027 | if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */ |
---|
1028 | if (xxrc) { *dp++ = (CHAR) rptq; *dp++ = xxrc; } /* Repeat count */ |
---|
1029 | if (xxss) { *dp++ = (CHAR) ebq; } /* Single shift */ |
---|
1030 | if (xxcq) { *dp++ = myctlq; } /* Control prefix */ |
---|
1031 | *dp++ = rt; /* Finally, the character itself */ |
---|
1032 | |
---|
1033 | if (rpt == 1) { /* Exactly two copies? */ |
---|
1034 | rpt = 0; |
---|
1035 | p2 = dp; /* Save place temporarily */ |
---|
1036 | for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */ |
---|
1037 | *dp++ = *p1; |
---|
1038 | if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */ |
---|
1039 | } |
---|
1040 | rt = rnext; /* Next character is now current. */ |
---|
1041 | |
---|
1042 | /* Done encoding the character. Now take care of packet buffer overflow. */ |
---|
1043 | |
---|
1044 | if ((dp-data) >= bufmax) { /* If too big, save some for next. */ |
---|
1045 | size = (dp-data); /* Calculate the size. */ |
---|
1046 | *dp = '\0'; /* Mark the end. */ |
---|
1047 | if ((dp-data) > bufmax) { /* if packet is overfull */ |
---|
1048 | /* copy the part that doesn't fit into the leftover buffer, */ |
---|
1049 | /* taking care not to split a prefixed sequence. */ |
---|
1050 | for (p1 = leftover, p2=odp; (*p1 = *p2) != '\0'; p1++,p2++) |
---|
1051 | ; |
---|
1052 | debug(F111,"getpkt leftover",leftover,size); |
---|
1053 | debug(F101,"getpkt osize","",(odp-data)); |
---|
1054 | size = (odp-data); /* Return truncated packet. */ |
---|
1055 | *odp = '\0'; /* Mark the new end */ |
---|
1056 | } |
---|
1057 | t = rt; /* save for next time */ |
---|
1058 | #ifdef COMMENT |
---|
1059 | next = rnext; |
---|
1060 | #endif /* COMMENT */ |
---|
1061 | return(size); |
---|
1062 | } |
---|
1063 | } /* Otherwise, keep filling. */ |
---|
1064 | |
---|
1065 | size = (dp-data); /* End of file */ |
---|
1066 | *dp = '\0'; /* Mark the end of the data. */ |
---|
1067 | debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */ |
---|
1068 | return(size); /* return partially filled last packet. */ |
---|
1069 | } |
---|
1070 | |
---|
1071 | /* T I N I T -- Initialize a transaction */ |
---|
1072 | |
---|
1073 | int |
---|
1074 | tinit() { |
---|
1075 | int x; |
---|
1076 | |
---|
1077 | #ifdef CK_TIMERS |
---|
1078 | extern int rttflg; |
---|
1079 | #endif /* CK_TIMERS */ |
---|
1080 | extern int rcvtimo; |
---|
1081 | extern char whoareu[]; |
---|
1082 | |
---|
1083 | if (server) |
---|
1084 | moving = 0; |
---|
1085 | bestlen = 0; |
---|
1086 | maxsend = 0; |
---|
1087 | debug(F101,"tinit bestlen","",bestlen); |
---|
1088 | whoareu[0] = NUL; |
---|
1089 | debug(F100,"tinit setting justone=0","",0); |
---|
1090 | justone = 0; |
---|
1091 | |
---|
1092 | #ifndef NOCSETS |
---|
1093 | if (tcharset == TC_TRANSP) { /* Character set translation */ |
---|
1094 | rx = sx = NULL; /* Transparent, no translation */ |
---|
1095 | #ifdef KANJI |
---|
1096 | } else if (tcharset == TC_JEUC) { |
---|
1097 | rx = sx = NULL; /* Transparent, no translation */ |
---|
1098 | #endif /* KANJI */ |
---|
1099 | } else { /* otherwise */ |
---|
1100 | rx = xlr[tcharset][fcharset]; /* Input translation function */ |
---|
1101 | sx = xls[tcharset][fcharset]; /* Output translation function */ |
---|
1102 | } |
---|
1103 | debug(F101,"tinit tcharset","",tcharset); |
---|
1104 | debug(F101,"tinit fcharset","",fcharset); |
---|
1105 | #ifdef COMMENT |
---|
1106 | debug(F101,"tinit sx ","",sx); |
---|
1107 | debug(F101,"tinit rx ","",rx); |
---|
1108 | #endif /* COMMENT */ |
---|
1109 | #endif /* NOCSETS */ |
---|
1110 | myinit[0] = '\0'; /* Haven't sent init string yet */ |
---|
1111 | retrans = 0; /* Packet retransmission count */ |
---|
1112 | sndtyp = 0; /* No previous packet */ |
---|
1113 | xflg = 0; /* Reset x-packet flag */ |
---|
1114 | memstr = 0; /* Reset memory-string flag */ |
---|
1115 | memptr = NULL; /* and buffer pointer */ |
---|
1116 | funcstr = 0; /* Reset "read from function" flag */ |
---|
1117 | funcptr = NULL; /* and function pointer */ |
---|
1118 | bctu = bctl = 1; /* Reset block check type to 1 */ |
---|
1119 | autopar = 0; /* Automatic parity detection flag */ |
---|
1120 | rqf = -1; /* Reset 8th-bit-quote request flag */ |
---|
1121 | ebq = MYEBQ; /* Reset 8th-bit quoting stuff */ |
---|
1122 | ebqflg = 0; /* 8th bit quoting not enabled */ |
---|
1123 | ebqsent = 0; /* No 8th-bit prefix bid sent yet */ |
---|
1124 | sq = 'Y'; /* 8th-bit prefix bid I usually send */ |
---|
1125 | binary = b_save; /* Back to what user last said */ |
---|
1126 | fncnv = f_save; /* ... */ |
---|
1127 | pktnum = 0; /* Initial packet number to send */ |
---|
1128 | cxseen = czseen = discard = 0; /* Reset interrupt flags */ |
---|
1129 | *filnam = '\0'; /* Clear file name */ |
---|
1130 | spktl = 0; /* And its length */ |
---|
1131 | nakstate = 0; /* Assume not in a NAK'ing state */ |
---|
1132 | numerrs = 0; /* Transmission error counter */ |
---|
1133 | if (server) /* If acting as server, */ |
---|
1134 | timint = srvtim; /* Use server timeout interval. */ |
---|
1135 | else /* Otherwise */ |
---|
1136 | timint = chktimo(rtimo,timef); /* Begin by using local value */ |
---|
1137 | |
---|
1138 | #ifdef CK_TIMERS |
---|
1139 | if (rttflg) /* Using round-trip timers? */ |
---|
1140 | rttinit(); |
---|
1141 | #else |
---|
1142 | rcvtimo = timint; |
---|
1143 | #endif /* CK_TIMERS */ |
---|
1144 | |
---|
1145 | spsiz = spsizr; /* Initial send-packet size */ |
---|
1146 | wslots = 1; /* One window slot */ |
---|
1147 | wslotn = 1; /* No window negotiated yet */ |
---|
1148 | winlo = 0; /* Packet 0 is at window-low */ |
---|
1149 | x = mksbuf(1); /* Make a 1-slot send-packet buffer */ |
---|
1150 | if (x < 0) return(x); |
---|
1151 | x = getsbuf(0); /* Allocate first send-buffer. */ |
---|
1152 | debug(F101,"tinit getsbuf","",x); |
---|
1153 | if (x < 0) return(x); |
---|
1154 | dumpsbuf(); |
---|
1155 | x = mkrbuf(wslots); /* & a 1-slot receive-packet buffer. */ |
---|
1156 | if (x < 0) return(x); |
---|
1157 | what = W_NOTHING; /* Doing nothing so far... */ |
---|
1158 | lsstate = 0; /* Initialize locking shift state */ |
---|
1159 | whatru = 0; |
---|
1160 | return(0); |
---|
1161 | } |
---|
1162 | |
---|
1163 | VOID |
---|
1164 | pktinit() { /* Initialize packet sequence */ |
---|
1165 | pktnum = 0; /* number & window low. */ |
---|
1166 | winlo = 0; |
---|
1167 | } |
---|
1168 | |
---|
1169 | /* R I N I T -- Respond to S or I packet */ |
---|
1170 | |
---|
1171 | VOID |
---|
1172 | rinit(d) CHAR *d; { |
---|
1173 | char *tp; |
---|
1174 | ztime(&tp); |
---|
1175 | tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */ |
---|
1176 | tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L); |
---|
1177 | tlog(F110,"Collision action:", fncnam[fncact],0); |
---|
1178 | tlog(F100,"","",0); |
---|
1179 | filcnt = filrej = 0; /* Init file counters */ |
---|
1180 | spar(d); |
---|
1181 | ack1(rpar()); |
---|
1182 | #ifdef datageneral |
---|
1183 | if ((local) && (!quiet)) /* Only do this if local & not quiet */ |
---|
1184 | consta_mt(); /* Start the asynch read task */ |
---|
1185 | #endif /* datageneral */ |
---|
1186 | } |
---|
1187 | |
---|
1188 | |
---|
1189 | /* R E S E T C -- Reset per-transaction character counters */ |
---|
1190 | |
---|
1191 | VOID |
---|
1192 | resetc() { |
---|
1193 | rptn = 0; /* Repeat counts */ |
---|
1194 | fsecs = flci = flco = 0L; /* File chars in and out */ |
---|
1195 | tfc = tlci = tlco = 0L; /* Total file, line chars in & out */ |
---|
1196 | ccu = ccp = 0L; /* Control-char statistics */ |
---|
1197 | #ifdef COMMENT |
---|
1198 | fsize = -1L; /* File size */ |
---|
1199 | #else |
---|
1200 | if (what != W_SEND) |
---|
1201 | fsize = -1L; |
---|
1202 | debug(F101,"resetc fsize","",fsize); |
---|
1203 | #endif /* COMMENT */ |
---|
1204 | timeouts = retrans = 0; /* Timeouts, retransmissions */ |
---|
1205 | spackets = rpackets = 0; /* Packet counts out & in */ |
---|
1206 | crunched = 0; /* Crunched packets */ |
---|
1207 | wcur = 0; /* Current window size */ |
---|
1208 | wmax = 0; /* Maximum window size used */ |
---|
1209 | } |
---|
1210 | |
---|
1211 | /* S I N I T -- Get & verify first file name, then send Send-Init packet */ |
---|
1212 | /* |
---|
1213 | Returns: |
---|
1214 | 1 if send operation begins successfully |
---|
1215 | 0 if send operation fails |
---|
1216 | */ |
---|
1217 | #ifdef DYNAMIC |
---|
1218 | char *cmargbuf = NULL; |
---|
1219 | #else |
---|
1220 | char cmargbuf[256]; |
---|
1221 | #endif /* DYNAMIC */ |
---|
1222 | char *cmargp[2]; |
---|
1223 | |
---|
1224 | VOID |
---|
1225 | fnlist() { |
---|
1226 | sndsrc = nfils; /* Source for filenames */ |
---|
1227 | #ifdef DYNAMIC |
---|
1228 | if (!cmargbuf && !(cmargbuf = malloc(256))) |
---|
1229 | fatal("fnlist: no memory for cmargbuf"); |
---|
1230 | #endif /* DYNAMIC */ |
---|
1231 | cmargbuf[0] = NUL; /* Initialize name buffer */ |
---|
1232 | |
---|
1233 | debug(F101,"sinit nfils","",nfils); |
---|
1234 | debug(F110,"sinit cmarg",cmarg,0); |
---|
1235 | debug(F110,"sinit cmarg2",cmarg2,0); |
---|
1236 | if (nfils == 0) { /* Sending from stdin or memory. */ |
---|
1237 | if ((cmarg2 != NULL) && (*cmarg2)) { |
---|
1238 | cmarg = cmarg2; /* If F packet, "as-name" is used */ |
---|
1239 | cmarg2 = ""; /* if provided */ |
---|
1240 | } else cmarg = "stdin"; /* otherwise just use "stdin" */ |
---|
1241 | strcpy(cmargbuf,cmarg); |
---|
1242 | cmargp[0] = cmargbuf; |
---|
1243 | cmargp[1] = ""; |
---|
1244 | cmlist = cmargp; |
---|
1245 | nfils = 1; |
---|
1246 | } |
---|
1247 | } |
---|
1248 | |
---|
1249 | int |
---|
1250 | sinit() { |
---|
1251 | int x; /* Worker int */ |
---|
1252 | char *tp, *xp, *m; /* Worker string pointers */ |
---|
1253 | /* |
---|
1254 | The DECC prototype for sleep() moved from <signal.h> to <unistd.h> |
---|
1255 | in DECC 5.2, but rather than pull in an entire header file (that might |
---|
1256 | not even be there), potentially involving unwanted conflicts, just do this: |
---|
1257 | */ |
---|
1258 | #ifdef __DECC |
---|
1259 | #ifndef __DECC_VER /* This exists only in 5.0 and above */ |
---|
1260 | _PROTOTYP( int sleep, (unsigned) ); |
---|
1261 | #else |
---|
1262 | #if __DECC_VER < 50200000 |
---|
1263 | _PROTOTYP( int sleep, (unsigned) ); |
---|
1264 | #endif /* __DECC_VER */ |
---|
1265 | #endif /* __DECC_VER */ |
---|
1266 | #endif /* __DECC */ |
---|
1267 | |
---|
1268 | filcnt = filrej = 0; /* Initialize file counters */ |
---|
1269 | fnlist(); |
---|
1270 | |
---|
1271 | if (nfils < 0) { |
---|
1272 | xp = cmarg; |
---|
1273 | } else { |
---|
1274 | #ifndef NOMSEND |
---|
1275 | if (addlist) |
---|
1276 | xp = filehead->fl_name; |
---|
1277 | else |
---|
1278 | #endif /* NOMSEND */ |
---|
1279 | xp = *cmlist; |
---|
1280 | } |
---|
1281 | x = gnfile(); /* Get first filename. */ |
---|
1282 | m = NULL; /* Error message pointer */ |
---|
1283 | debug(F101,"sinit gnfil","",x); |
---|
1284 | switch (x) { |
---|
1285 | case -5: m = "Too many files match wildcard"; break; |
---|
1286 | case -4: m = "Cancelled"; break; |
---|
1287 | case -3: m = "Read access denied"; break; |
---|
1288 | case -2: m = "File is not readable"; break; |
---|
1289 | case -1: m = iswild(filnam) ? "No files match" : "File not found"; |
---|
1290 | break; |
---|
1291 | case 0: m = "No filespec given!"; break; |
---|
1292 | default: |
---|
1293 | break; |
---|
1294 | } |
---|
1295 | debug(F101,"sinit nfils","",nfils); |
---|
1296 | debug(F110,"sinit filnam",filnam,0); |
---|
1297 | if (x < 1) { /* Didn't get a file. */ |
---|
1298 | if (server) /* Doing GET command */ |
---|
1299 | errpkt((CHAR *)m); /* so send Error packet. */ |
---|
1300 | else /* Doing SEND command */ |
---|
1301 | screen(SCR_EM,0,0l,m); /* so print message. */ |
---|
1302 | tlog(F110,xp,m,0L); /* Make transaction log entry. */ |
---|
1303 | freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */ |
---|
1304 | return(0); /* Return failure code */ |
---|
1305 | } |
---|
1306 | if (!local && !server && delay > 0) /* OS-9 sleep(0) == infinite */ |
---|
1307 | sleep(delay); /* Delay if requested */ |
---|
1308 | #ifdef datageneral |
---|
1309 | if ((local) && (!quiet)) /* Only do this if local & not quiet */ |
---|
1310 | consta_mt(); /* Start the asynch read task */ |
---|
1311 | #endif /* datageneral */ |
---|
1312 | freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */ |
---|
1313 | sipkt('S'); /* Send the Send-Init packet. */ |
---|
1314 | ztime(&tp); /* Get current date/time */ |
---|
1315 | tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */ |
---|
1316 | tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L); |
---|
1317 | tlog(F100,"","",0); |
---|
1318 | debug(F111,"sinit ok",filnam,0); |
---|
1319 | return(1); |
---|
1320 | } |
---|
1321 | |
---|
1322 | int |
---|
1323 | #ifdef CK_ANSIC |
---|
1324 | sipkt(char c) /* Send S or I packet. */ |
---|
1325 | #else |
---|
1326 | sipkt(c) char c; |
---|
1327 | #endif |
---|
1328 | /* sipkt */ { |
---|
1329 | CHAR *rp; int k; |
---|
1330 | debug(F101,"sipkt pktnum","",pktnum); |
---|
1331 | k = sseqtbl[pktnum]; /* Find slot for this packet */ |
---|
1332 | debug(F101,"sipkt k","",k); |
---|
1333 | if (k < 0) { /* No slot? */ |
---|
1334 | k = getsbuf(winlo = pktnum); /* Make one. */ |
---|
1335 | debug(F101,"sipkt getsbuf","",k); |
---|
1336 | } |
---|
1337 | ttflui(); /* Flush pending input. */ |
---|
1338 | rp = rpar(); /* Get protocol parameters. */ |
---|
1339 | return(spack(c,pktnum,(int)strlen((char *)rp),rp)); /* Send them. */ |
---|
1340 | } |
---|
1341 | |
---|
1342 | /* X S I N I T -- Retransmit S-packet */ |
---|
1343 | /* |
---|
1344 | For use in the GET-SEND sequence, when we start to send, but receive another |
---|
1345 | copy of the GET command because the receiver didn't get our S packet. |
---|
1346 | This retransmits the S packet and frees the receive buffer for the ACK. |
---|
1347 | This special case is necessary because packet number zero is being re-used. |
---|
1348 | */ |
---|
1349 | VOID |
---|
1350 | xsinit() { |
---|
1351 | int k; |
---|
1352 | k = rseqtbl[0]; |
---|
1353 | debug(F101,"xsinit k","",k); |
---|
1354 | if (k > -1) |
---|
1355 | freerbuf(k); |
---|
1356 | resend(0); |
---|
1357 | } |
---|
1358 | |
---|
1359 | /* R C V F I L -- Receive a file */ |
---|
1360 | |
---|
1361 | /* |
---|
1362 | Incoming filename is in data field of F packet. |
---|
1363 | This function decodes it into the srvcmd buffer, substituting an |
---|
1364 | alternate "as-name", if one was given. |
---|
1365 | Then it does any requested transformations (like converting to |
---|
1366 | lowercase), and finally if a file of the same name already exists, |
---|
1367 | takes the desired collision action. |
---|
1368 | */ |
---|
1369 | char ofn1[CKMAXPATH+1]; /* Buffer for output file name */ |
---|
1370 | char * ofn2; /* Pointer to backup file name */ |
---|
1371 | int ofn1x; /* Flag output file already exists */ |
---|
1372 | int opnerr; /* Flag for open error */ |
---|
1373 | |
---|
1374 | int /* Returns success ? 1 : 0 */ |
---|
1375 | rcvfil(n) char *n; { |
---|
1376 | #ifdef OS2 |
---|
1377 | #ifdef __32BIT__ |
---|
1378 | char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */ |
---|
1379 | #endif /* __32BIT__ */ |
---|
1380 | #endif /* OS2 */ |
---|
1381 | #ifdef DTILDE |
---|
1382 | char *dirp, *tilde_expand(); |
---|
1383 | #endif /* DTILDE */ |
---|
1384 | int dirflg; |
---|
1385 | |
---|
1386 | opnerr = 0; |
---|
1387 | ofn2 = NULL; /* No new name (yet) */ |
---|
1388 | lsstate = 0; /* Cancel locking-shift state */ |
---|
1389 | srvptr = srvcmd; /* Decode file name from packet. */ |
---|
1390 | decode(rdatap,putsrv,0); /* Don't xlate charsets. */ |
---|
1391 | if (*srvcmd == '\0') /* Watch out for null F packet. */ |
---|
1392 | strcpy((char *)srvcmd,"NONAME"); |
---|
1393 | #ifdef DTILDE |
---|
1394 | if (*srvcmd == '~') { |
---|
1395 | dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */ |
---|
1396 | if (*dirp != '\0') strcpy((char *)srvcmd,dirp); |
---|
1397 | } |
---|
1398 | #else |
---|
1399 | #ifdef OS2 |
---|
1400 | if (isalpha(*srvcmd) && srvcmd[1] == ':' && srvcmd[2] == '\0') |
---|
1401 | strcat((char *)srvcmd,"NONAME"); |
---|
1402 | #endif /* OS2 */ |
---|
1403 | #endif /* DTILDE */ |
---|
1404 | screen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */ |
---|
1405 | debug(F110,"rcvfil",(char *)srvcmd,0); /* Debug log entry */ |
---|
1406 | debug(F110,"rcvfil cmarg2",cmarg2,0); |
---|
1407 | tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */ |
---|
1408 | if (cmarg2) { /* Check for alternate name */ |
---|
1409 | if (*cmarg2) { |
---|
1410 | debug(F110,"rcvfil substituting cmarg2",cmarg2,0); |
---|
1411 | strcpy((char *)srvcmd,cmarg2); /* Got one, use it. */ |
---|
1412 | } |
---|
1413 | } |
---|
1414 | cmarg2 = ""; /* Done with alternate name */ |
---|
1415 | |
---|
1416 | if ((int)strlen((char *)srvcmd) > CKMAXPATH) /* Watch out for overflow */ |
---|
1417 | *(srvcmd + CKMAXPATH - 1) = NUL; |
---|
1418 | |
---|
1419 | /* At this point, srvcmd[] contains the incoming filename or as-name */ |
---|
1420 | |
---|
1421 | if (fnrpath) { /* RECEIVE PATHNAMES OFF? */ |
---|
1422 | char *t; /* Yes. */ |
---|
1423 | zstrip((char *)srvcmd,&t); /* Off with it. */ |
---|
1424 | debug(F110,"rcvfil zstrip",t,0); |
---|
1425 | if (!t) /* Be sure we didn't strip too much */ |
---|
1426 | strcpy(ofn1,"UNKNOWN"); |
---|
1427 | else if (*t == '\0') |
---|
1428 | strcpy(ofn1,"UNKNOWN"); |
---|
1429 | else |
---|
1430 | strcpy(ofn1,t); |
---|
1431 | strcpy((char *)srvcmd,ofn1); /* Now copy it back. */ |
---|
1432 | } |
---|
1433 | |
---|
1434 | /* Now srvcmd contains incoming filename with path possibly stripped */ |
---|
1435 | |
---|
1436 | if (fncnv) /* FILE NAMES CONVERTED? */ |
---|
1437 | zrtol((char *)srvcmd,(char *)ofn1); /* Yes, convert to local form */ |
---|
1438 | else |
---|
1439 | strcpy(ofn1,(char *)srvcmd); /* No, copy literally. */ |
---|
1440 | |
---|
1441 | /* Now the incoming filename, possibly converted, is in ofn1[]. */ |
---|
1442 | |
---|
1443 | #ifdef OS2 |
---|
1444 | /* Don't refuse the file just because the name is illegal. */ |
---|
1445 | if (!IsFileNameValid(ofn1)) { /* Name is OK for OS/2? */ |
---|
1446 | #ifdef __32BIT__ |
---|
1447 | char *zs = NULL; |
---|
1448 | zstrip(ofn1, &zs); /* Not valid, strip unconditionally */ |
---|
1449 | if (zs) { |
---|
1450 | if (iattr.longname.len && /* Free previous longname, if any */ |
---|
1451 | iattr.longname.val) |
---|
1452 | free(iattr.longname.val); |
---|
1453 | iattr.longname.len = strlen(zs); /* Store in attribute structure */ |
---|
1454 | iattr.longname.val = (char *) malloc(iattr.longname.len + 1); |
---|
1455 | if (iattr.longname.val) /* Remember this (illegal) name */ |
---|
1456 | strcpy(iattr.longname.val, zs); |
---|
1457 | } |
---|
1458 | #endif /* __32BIT__ */ |
---|
1459 | debug(F110,"rcvfil: invalid file name",ofn1,0); |
---|
1460 | ChangeNameForFAT(ofn1); /* Change to an acceptable name */ |
---|
1461 | debug(F110,"rcvfil: FAT file name",ofn1,0); |
---|
1462 | |
---|
1463 | } else { /* Name is OK. */ |
---|
1464 | |
---|
1465 | debug(F110,"rcvfil: valid file name",ofn1,0); |
---|
1466 | #ifdef __32BIT__ |
---|
1467 | if (iattr.longname.len && |
---|
1468 | iattr.longname.val) /* Free previous longname, if any */ |
---|
1469 | free(iattr.longname.val); |
---|
1470 | iattr.longname.len = 0; |
---|
1471 | iattr.longname.val = NULL; /* This file doesn't need a longname */ |
---|
1472 | #endif /* __32BIT__ */ |
---|
1473 | } |
---|
1474 | #endif /* OS2 */ |
---|
1475 | debug(F110,"rcvfil as",ofn1,0); |
---|
1476 | |
---|
1477 | /* Filename collision action section. */ |
---|
1478 | |
---|
1479 | dirflg = /* Is it a directory name? */ |
---|
1480 | #ifdef CK_TMPDIR |
---|
1481 | isdir(ofn1) |
---|
1482 | #else |
---|
1483 | 0 |
---|
1484 | #endif /* CK_TMPDIR */ |
---|
1485 | ; |
---|
1486 | debug(F101,"rcvfil dirflg","",dirflg); |
---|
1487 | ofn1x = (zchki(ofn1) != -1); /* File already exists? */ |
---|
1488 | debug(F101,"rcvfil ofn1x",ofn1,ofn1x); |
---|
1489 | |
---|
1490 | if ( ( |
---|
1491 | #ifdef UNIX |
---|
1492 | strcmp(ofn1,"/dev/null") && /* It's not the null device? */ |
---|
1493 | #else |
---|
1494 | #ifdef OSK |
---|
1495 | strcmp(ofn1,"/nil") && /* It's not the null device? */ |
---|
1496 | #endif /* OSK */ |
---|
1497 | #endif /* UNIX */ |
---|
1498 | !stdouf ) && /* Not copying to standard output? */ |
---|
1499 | ofn1x || /* File of same name exists? */ |
---|
1500 | dirflg ) { /* Or file is a directory? */ |
---|
1501 | debug(F111,"rcvfil exists",ofn1,fncact); |
---|
1502 | switch (fncact) { /* Yes, do what user said. */ |
---|
1503 | case XYFX_A: /* Append */ |
---|
1504 | debug(F100,"rcvfil append","",0); |
---|
1505 | if (dirflg) { |
---|
1506 | rf_err = "Can't append to a directory"; |
---|
1507 | tlog(F100," error - can't append to directory","",0); |
---|
1508 | discard = opnerr = 1; |
---|
1509 | return(0); |
---|
1510 | } |
---|
1511 | tlog(F110," appending to",ofn1,0); |
---|
1512 | break; |
---|
1513 | case XYFX_Q: /* Query (Ask) */ |
---|
1514 | break; /* not implemented */ |
---|
1515 | case XYFX_B: /* Backup (rename old file) */ |
---|
1516 | if (dirflg) { |
---|
1517 | rf_err = "Can't rename existing directory"; |
---|
1518 | tlog(F100," error - can't rename directory","",0); |
---|
1519 | discard = opnerr = 1; |
---|
1520 | return(0); |
---|
1521 | } |
---|
1522 | znewn(ofn1,&ofn2); /* Get new unique name */ |
---|
1523 | tlog(F110," backup:",ofn2,0); |
---|
1524 | debug(F110,"rcvfil backup ofn1",ofn1,0); |
---|
1525 | debug(F110,"rcvfil backup ofn2",ofn2,0); |
---|
1526 | #ifdef OS2 |
---|
1527 | #ifdef CK_LABELED |
---|
1528 | #ifdef __32BIT__ |
---|
1529 | /* |
---|
1530 | In case this is a FAT file system, we can't change only the FAT name, we |
---|
1531 | also have to change the longname from the extended attributes block. |
---|
1532 | Otherwise, we'll have many files with the same longname and if we copy them |
---|
1533 | to an HPFS volume, only one will survive. |
---|
1534 | */ |
---|
1535 | if (os2getlongname(ofn1, &longname) > -1) { |
---|
1536 | if (strlen(longname)) { |
---|
1537 | char tmp[10]; |
---|
1538 | extern int ck_znewn; |
---|
1539 | sprintf(tmp,".~%d~",ck_znewn); |
---|
1540 | newlongname = |
---|
1541 | (char *) malloc(strlen(longname) + strlen(tmp) + 1); |
---|
1542 | if (newlongname) { |
---|
1543 | strcpy(newlongname, longname); |
---|
1544 | strcat(newlongname, tmp); |
---|
1545 | os2setlongname(ofn1, newlongname); |
---|
1546 | free(newlongname); |
---|
1547 | newlongname = NULL; |
---|
1548 | } |
---|
1549 | } |
---|
1550 | } else debug(F100,"rcvfil os2getlongname failed","",0); |
---|
1551 | #endif /* __32BIT__ */ |
---|
1552 | #endif /* CK_LABELED */ |
---|
1553 | #endif /* OS2 */ |
---|
1554 | |
---|
1555 | #ifdef COMMENT |
---|
1556 | /* Do this later, in opena()... */ |
---|
1557 | if (zrename(ofn1,ofn2) < 0) { |
---|
1558 | rf_err = "Can't transform filename"; |
---|
1559 | debug(F110,"rcvfil rename fails",ofn1,0); |
---|
1560 | discard = opnerr = 1; |
---|
1561 | return(0); |
---|
1562 | } |
---|
1563 | #endif /* COMMENT */ |
---|
1564 | break; |
---|
1565 | |
---|
1566 | case XYFX_D: /* Discard (refuse new file) */ |
---|
1567 | discard = 1; |
---|
1568 | rejection = 1; /* Horrible hack: reason = name */ |
---|
1569 | debug(F101,"rcvfil discard","",discard); |
---|
1570 | tlog(F100," refused: name","",0); |
---|
1571 | break; |
---|
1572 | |
---|
1573 | case XYFX_R: /* Rename incoming file */ |
---|
1574 | znewn(ofn1,&ofn2); /* Make new name for it */ |
---|
1575 | #ifdef OS2 |
---|
1576 | #ifdef __32BIT__ |
---|
1577 | if (iattr.longname.len) { |
---|
1578 | char tmp[10]; |
---|
1579 | extern int ck_znewn; |
---|
1580 | sprintf(tmp,".~%d~",ck_znewn); |
---|
1581 | newlongname = |
---|
1582 | (char *) malloc(iattr.longname.len + strlen(tmp) + 1); |
---|
1583 | if (newlongname) { |
---|
1584 | strcpy(newlongname, iattr.longname.val); |
---|
1585 | strcat(newlongname, tmp); |
---|
1586 | debug(F110, |
---|
1587 | "Rename Incoming: newlongname",newlongname,0); |
---|
1588 | |
---|
1589 | if (iattr.longname.len && |
---|
1590 | iattr.longname.val) |
---|
1591 | free(iattr.longname.val); |
---|
1592 | iattr.longname.len = strlen(newlongname); |
---|
1593 | iattr.longname.val = newlongname; |
---|
1594 | } |
---|
1595 | } |
---|
1596 | #endif /* __32BIT__ */ |
---|
1597 | #endif /* OS2 */ |
---|
1598 | break; |
---|
1599 | case XYFX_X: /* Replace old file */ |
---|
1600 | debug(F100,"rcvfil overwrite","",0); |
---|
1601 | if (dirflg) { |
---|
1602 | rf_err = "Can't overwrite existing directory"; |
---|
1603 | tlog(F100," error - can't overwrite directory","",0); |
---|
1604 | discard = opnerr = 1; |
---|
1605 | #ifdef COMMENT |
---|
1606 | return(0); |
---|
1607 | #else |
---|
1608 | break; |
---|
1609 | #endif /* COMMENT */ |
---|
1610 | } |
---|
1611 | tlog(F110,"overwriting",ofn1,0); |
---|
1612 | break; |
---|
1613 | case XYFX_U: /* Refuse if older */ |
---|
1614 | debug(F100,"rcvfil update","",0); |
---|
1615 | if (dirflg) { |
---|
1616 | rf_err = "File has same name as existing directory"; |
---|
1617 | tlog(F110," error - directory exists:",ofn1,0); |
---|
1618 | discard = opnerr = 1; |
---|
1619 | #ifdef COMMENT |
---|
1620 | /* Don't send an error packet, just refuse the file */ |
---|
1621 | return(0); |
---|
1622 | #endif /* COMMENT */ |
---|
1623 | } |
---|
1624 | break; /* Not here, we don't have */ |
---|
1625 | /* the attribute packet yet. */ |
---|
1626 | default: |
---|
1627 | debug(F101,"rcvfil bad collision action","",fncact); |
---|
1628 | break; |
---|
1629 | } |
---|
1630 | } |
---|
1631 | debug(F110,"rcvfil ofn1",ofn1,0); |
---|
1632 | debug(F110,"rcvfil ofn2",ofn2,0); |
---|
1633 | if (fncact == XYFX_R && ofn1x && ofn2) { /* Renaming incoming file? */ |
---|
1634 | screen(SCR_AN,0,0l,ofn2); /* Display renamed name */ |
---|
1635 | strcpy(n, ofn2); /* Return it */ |
---|
1636 | } else { /* No */ |
---|
1637 | screen(SCR_AN,0,0l,ofn1); /* Display regular name */ |
---|
1638 | strcpy(n, ofn1); /* and return it. */ |
---|
1639 | } |
---|
1640 | |
---|
1641 | #ifdef CK_MKDIR |
---|
1642 | /* Create directory(s) if necessary. */ |
---|
1643 | if (!discard && !fnrpath) { /* RECEIVE PATHAMES ON? */ |
---|
1644 | debug(F110,"rcvfil calling zmkdir",ofn1,0); /* Yes */ |
---|
1645 | if (zmkdir(ofn1) < 0) { |
---|
1646 | debug(F100,"zmkdir fails","",0); |
---|
1647 | tlog(F110," error - directory creation failure:",ofn1,0); |
---|
1648 | rf_err = "Directory creation failure."; |
---|
1649 | discard = 1; |
---|
1650 | return(0); |
---|
1651 | } |
---|
1652 | } |
---|
1653 | #else |
---|
1654 | debug(F110,"sfile CK_MKDIR not defined",ofn1,0); |
---|
1655 | #endif /* CK_MKDIR */ |
---|
1656 | |
---|
1657 | #ifndef NOICP |
---|
1658 | /* #ifndef MAC */ |
---|
1659 | /* Why not Mac? */ |
---|
1660 | strcpy(fspec,ofn1); /* Here too for \v(filespec) */ |
---|
1661 | /* #endif */ |
---|
1662 | #endif /* NOICP */ |
---|
1663 | debug(F110,"rcvfil: n",n,0); |
---|
1664 | ffc = 0L; /* Init per-file counters */ |
---|
1665 | cps = oldcps = 0L; |
---|
1666 | rs_len = 0L; |
---|
1667 | rejection = -1; |
---|
1668 | fsecs = gtimer(); /* Time this file started */ |
---|
1669 | filcnt++; |
---|
1670 | intmsg(filcnt); |
---|
1671 | return(1); /* Successful return */ |
---|
1672 | } |
---|
1673 | |
---|
1674 | |
---|
1675 | /* R E O F -- Receive End Of File packet for incoming file */ |
---|
1676 | |
---|
1677 | /* |
---|
1678 | Closes the received file. |
---|
1679 | Returns: |
---|
1680 | 0 on success. |
---|
1681 | -1 if file could not be closed. |
---|
1682 | 2 if disposition was mail, mail was sent, but temp file not deleted. |
---|
1683 | 3 if disposition was print, file was printed, but not deleted. |
---|
1684 | -2 if disposition was mail and mail could not be sent |
---|
1685 | -3 if disposition was print and file could not be printed |
---|
1686 | */ |
---|
1687 | int |
---|
1688 | reof(f,yy) char *f; struct zattr *yy; { |
---|
1689 | int x; |
---|
1690 | char *p; |
---|
1691 | char c; |
---|
1692 | |
---|
1693 | debug(F111,"reof fncact",f,fncact); |
---|
1694 | debug(F101,"reof discard","",discard); |
---|
1695 | success = 1; /* Assume status is OK */ |
---|
1696 | lsstate = 0; /* Cancel locking-shift state */ |
---|
1697 | if (discard) { /* Handle attribute refusals, etc. */ |
---|
1698 | debug(F101,"reof discarding","",0); |
---|
1699 | success = 0; /* Status = failed. */ |
---|
1700 | if (rejection == '#' || /* Unless rejection reason is */ |
---|
1701 | rejection == 1 || /* date or name (SET FILE COLLISION */ |
---|
1702 | rejection == '?') /* UPDATE or DISCARD) */ |
---|
1703 | success = 1; |
---|
1704 | debug(F101,"reof success","",success); |
---|
1705 | filrej++; /* Count this rejection. */ |
---|
1706 | discard = 0; /* We never opened the file, */ |
---|
1707 | return(0); /* so we don't close it. */ |
---|
1708 | } |
---|
1709 | #ifdef DEBUG |
---|
1710 | if (deblog) { |
---|
1711 | debug(F101,"reof cxseen","",cxseen); |
---|
1712 | debug(F101,"reof czseen","",czseen); |
---|
1713 | debug(F110,"reof rdatap",rdatap,0); |
---|
1714 | } |
---|
1715 | #endif /* DEBUG */ |
---|
1716 | if (cxseen == 0) cxseen = (*rdatap == 'D'); /* Got cancel directive? */ |
---|
1717 | success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */ |
---|
1718 | if (!success) filrej++; /* "Uncount" this file */ |
---|
1719 | debug(F101,"reof success","",czseen); |
---|
1720 | x = clsof(cxseen || czseen); /* Close the file (resets cxseen) */ |
---|
1721 | if (x < 0) { /* If failure to close, FAIL */ |
---|
1722 | if (success) filrej++; |
---|
1723 | success = 0; |
---|
1724 | } |
---|
1725 | if (success && atcapu) zstime(f,yy,0); /* Set file creation date */ |
---|
1726 | #ifdef OS2 |
---|
1727 | #ifdef __32BIT__ |
---|
1728 | #ifdef CK_LABELED |
---|
1729 | if (success && yy->longname.len) |
---|
1730 | os2setlongname(f, yy->longname.val); |
---|
1731 | #endif /* CK_LABELED */ |
---|
1732 | #endif /* __32BIT__ */ |
---|
1733 | #endif /* OS2 */ |
---|
1734 | if (success == 0) xitsta |= W_RECV; /* And program return code */ |
---|
1735 | |
---|
1736 | /* Handle dispositions from attribute packet... */ |
---|
1737 | |
---|
1738 | #ifndef NOFRILLS |
---|
1739 | if (yy->disp.len != 0) { |
---|
1740 | p = yy->disp.val; |
---|
1741 | c = *p++; |
---|
1742 | if (c == 'M') { /* Mail to user. */ |
---|
1743 | x = zmail(p,filnam); /* Do the system's mail command */ |
---|
1744 | if (x < 0) success = 0; /* Remember status */ |
---|
1745 | tlog(F110,"mailed",filnam,0L); |
---|
1746 | tlog(F110," to",p,0L); |
---|
1747 | zdelet(filnam); /* Delete the file */ |
---|
1748 | } else if (c == 'P') { /* Print the file. */ |
---|
1749 | x = zprint(p,filnam); /* Do the system's print command */ |
---|
1750 | if (x < 0) success = 0; /* Remember status */ |
---|
1751 | tlog(F110,"printed",filnam,0L); |
---|
1752 | tlog(F110," with options",p,0L); |
---|
1753 | #ifndef VMS |
---|
1754 | #ifndef STRATUS |
---|
1755 | /* spooler will delete file after print complete in VOS & VMS */ |
---|
1756 | if (zdelet(filnam) && x == 0) x = 3; /* Delete the file */ |
---|
1757 | #endif /* STRATUS */ |
---|
1758 | #endif /* VMS */ |
---|
1759 | } |
---|
1760 | } |
---|
1761 | #endif /* NOFRILLS */ |
---|
1762 | debug(F101,"reof returns","",x); |
---|
1763 | *filnam = '\0'; |
---|
1764 | return(x); |
---|
1765 | } |
---|
1766 | |
---|
1767 | /* R E O T -- Receive End Of Transaction */ |
---|
1768 | |
---|
1769 | VOID |
---|
1770 | reot() { |
---|
1771 | cxseen = czseen = discard = 0; /* Reset interruption flags */ |
---|
1772 | tstats(); |
---|
1773 | } |
---|
1774 | |
---|
1775 | /* S F I L E -- Send File header or teXt header packet */ |
---|
1776 | |
---|
1777 | /* Call with x nonzero for X packet, zero for F packet */ |
---|
1778 | /* Returns 1 on success, 0 on failure */ |
---|
1779 | |
---|
1780 | int |
---|
1781 | sfile(x) int x; { |
---|
1782 | #ifdef pdp11 |
---|
1783 | #define PKTNL 64 |
---|
1784 | #else |
---|
1785 | #define PKTNL 256 |
---|
1786 | #endif /* pdp11 */ |
---|
1787 | char pktnam[PKTNL+1]; /* Local copy of name */ |
---|
1788 | char *s; |
---|
1789 | |
---|
1790 | /* cmarg2 or filnam (with that precedence) have the file's name */ |
---|
1791 | |
---|
1792 | lsstate = 0; /* Cancel locking-shift state */ |
---|
1793 | if (nxtpkt() < 0) return(0); /* Bump packet number, get buffer */ |
---|
1794 | if (x == 0) { /* F-Packet setup */ |
---|
1795 | if (cmarg2 && *cmarg2) { /* If we have a send-as name, */ |
---|
1796 | debug(F111,"sfile cmarg2",cmarg2,cmarg2); |
---|
1797 | strncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */ |
---|
1798 | cmarg2 = ""; /* and blank it out for next time. */ |
---|
1799 | } else { /* Otherwise... */ |
---|
1800 | debug(F101,"sfile fnspath","",fnspath); |
---|
1801 | if (fnspath) { /* Stripping path names? */ |
---|
1802 | char *t; /* Yes. */ |
---|
1803 | zstrip(filnam,&t); /* Strip off the path. */ |
---|
1804 | debug(F110,"sfile zstrip",t,0); |
---|
1805 | if (!t) t = "UNKNOWN"; /* Be cautious... */ |
---|
1806 | else if (*t == '\0') |
---|
1807 | t = "UNKNOWN"; |
---|
1808 | strncpy(pktnam,t,PKTNL); /* Copy stripped name literally. */ |
---|
1809 | } else { /* No stripping. */ |
---|
1810 | strcpy(pktnam,filnam); /* Copy whole name. */ |
---|
1811 | } |
---|
1812 | /* pktnam[] has the packet name, filnam[] has the original name. */ |
---|
1813 | /* But we still need to convert pktnam if FILE NAMES CONVERTED. */ |
---|
1814 | |
---|
1815 | debug(F101,"SATURDAY fncnv","",fncnv); |
---|
1816 | if (fncnv) { /* If converting names, */ |
---|
1817 | zltor(pktnam,(char *)srvcmd); /* convert it to common form, */ |
---|
1818 | strcpy(pktnam,(char *)srvcmd); /* with srvcmd as temp buffer */ |
---|
1819 | *srvcmd = NUL; |
---|
1820 | } |
---|
1821 | } |
---|
1822 | debug(F110,"sfile",filnam,0); /* Log debugging info */ |
---|
1823 | debug(F110," pktnam",pktnam,0); |
---|
1824 | if (openi(filnam) == 0) /* Try to open the input file */ |
---|
1825 | return(0); |
---|
1826 | #ifdef CK_RESEND |
---|
1827 | if (sendmode == SM_PSEND) /* PSENDing? */ |
---|
1828 | if (sendstart > 0L) /* Starting position */ |
---|
1829 | if (zfseek(sendstart) < 0) /* seek to it... */ |
---|
1830 | return(0); |
---|
1831 | #endif /* CK_RESEND */ |
---|
1832 | s = pktnam; /* Name for packet data field */ |
---|
1833 | #ifdef OS2 |
---|
1834 | /* Never send a disk letter. */ |
---|
1835 | if (isalpha(*s) && (*(s+1) == ':')) |
---|
1836 | s += 2; |
---|
1837 | #endif /* OS2 */ |
---|
1838 | |
---|
1839 | } else { /* X-packet setup, not F-packet. */ |
---|
1840 | |
---|
1841 | debug(F110,"sxpack",cmdstr,0); /* Log debugging info */ |
---|
1842 | s = cmdstr; /* Name for data field */ |
---|
1843 | } |
---|
1844 | |
---|
1845 | /* Now s points to the string that goes in the packet data field. */ |
---|
1846 | |
---|
1847 | encstr((CHAR *)s); /* Encode the name. */ |
---|
1848 | /* Send the F or X packet */ |
---|
1849 | /* If the encoded string did not fit into the packet, it was truncated. */ |
---|
1850 | |
---|
1851 | #ifdef COMMENT |
---|
1852 | spack((char) (x ? 'X' : 'F'), pktnum, size, encbuf+7); |
---|
1853 | #else |
---|
1854 | spack((char) (x ? 'X' : 'F'), pktnum, size, data); |
---|
1855 | #endif /* COMMENT */ |
---|
1856 | |
---|
1857 | if (x == 0) { /* Display for F packet */ |
---|
1858 | if (displa) { /* Screen */ |
---|
1859 | screen(SCR_FN,'F',(long)pktnum,filnam); |
---|
1860 | screen(SCR_AN,0,0l,pktnam); |
---|
1861 | screen(SCR_FS,0,fsize,""); |
---|
1862 | } |
---|
1863 | #ifdef pdp11 |
---|
1864 | tlog(F110,"Sending",filnam,0L); /* Transaction log entry */ |
---|
1865 | #else |
---|
1866 | #ifndef ZFNQFP |
---|
1867 | tlog(F110,"Sending",filnam,0L); |
---|
1868 | #else |
---|
1869 | { /* Log fully qualified filename */ |
---|
1870 | char *p = NULL, *q = filnam; |
---|
1871 | if ((p = malloc(CKMAXPATH+1))) |
---|
1872 | if (zfnqfp(filnam, CKMAXPATH, p)) |
---|
1873 | q = p; |
---|
1874 | tlog(F110,"Sending",q,0L); |
---|
1875 | if (p) free(p); |
---|
1876 | } |
---|
1877 | #endif /* ZFNQFP */ |
---|
1878 | #endif /* pdp11 */ |
---|
1879 | tlog(F110," as",pktnam,0L); |
---|
1880 | if (binary) { /* Log file mode in transaction log */ |
---|
1881 | tlog(F101," mode: binary","",(long) binary); |
---|
1882 | } else { /* If text mode, check character set */ |
---|
1883 | tlog(F100," mode: text","",0L); |
---|
1884 | #ifndef NOCSETS |
---|
1885 | tlog(F110," file character set",fcsinfo[fcharset].name,0L); |
---|
1886 | if (tcharset == TC_TRANSP) |
---|
1887 | tlog(F110," xfer character set","transparent",0L); |
---|
1888 | else |
---|
1889 | tlog(F110," xfer character set",tcsinfo[tcharset].name,0L); |
---|
1890 | #endif /* NOCSETS */ |
---|
1891 | } |
---|
1892 | } else { /* Display for X-packet */ |
---|
1893 | |
---|
1894 | screen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */ |
---|
1895 | tlog(F110,"Sending from:",cmdstr,0L); /* Transaction log */ |
---|
1896 | } |
---|
1897 | intmsg(++filcnt); /* Count file, give interrupt msg */ |
---|
1898 | first = 1; /* Init file character lookahead. */ |
---|
1899 | ffc = 0L; /* Init file character counter. */ |
---|
1900 | cps = oldcps = 0L; /* Init cps statistics */ |
---|
1901 | rejection = -1; |
---|
1902 | fsecs = gtimer(); /* Time this file started */ |
---|
1903 | debug(F101,"SFILE fsecs","",fsecs); |
---|
1904 | return(1); |
---|
1905 | } |
---|
1906 | |
---|
1907 | /* S D A T A -- Send a data packet */ |
---|
1908 | |
---|
1909 | /* |
---|
1910 | Returns -1 if no data to send (end of file), -2 if connection is broken. |
---|
1911 | If there is data, a data packet is sent, and sdata() returns 1. |
---|
1912 | |
---|
1913 | For window size greater than 1, we keep sending data packets until window |
---|
1914 | is full or characters start to appear from the other Kermit, whichever |
---|
1915 | happens first. |
---|
1916 | |
---|
1917 | In the windowing case, when there is no more data left to send (or when |
---|
1918 | sending has been interrupted), sdata() does nothing and returns 0 each time |
---|
1919 | it is called until the current packet number catches up to the last data |
---|
1920 | packet that was sent. |
---|
1921 | */ |
---|
1922 | |
---|
1923 | int |
---|
1924 | sdata() { |
---|
1925 | int i, x, len; |
---|
1926 | |
---|
1927 | debug(F101,"sdata entry, first","",first); |
---|
1928 | debug(F101," drain","",drain); |
---|
1929 | |
---|
1930 | /* The "drain" flag is used with window size > 1. It means we have sent */ |
---|
1931 | /* our last data packet. If called and drain is not zero, then we return */ |
---|
1932 | /* 0 as if we had sent an empty data packet, until all data packets have */ |
---|
1933 | /* been ACK'd, then then we can finally return -1 indicating EOF, so that */ |
---|
1934 | /* the protocol can switch to seof state. This is a kludge, but at least */ |
---|
1935 | /* it's localized... */ |
---|
1936 | |
---|
1937 | if (first == 1) drain = 0; /* Start of file, init drain flag. */ |
---|
1938 | |
---|
1939 | if (drain) { /* If draining... */ |
---|
1940 | debug(F101,"sdata draining, winlo","",winlo); |
---|
1941 | if (winlo == pktnum) /* If all data packets are ACK'd */ |
---|
1942 | return(-1); /* return EOF indication */ |
---|
1943 | else /* otherwise */ |
---|
1944 | return(0); /* pretend we sent a data packet. */ |
---|
1945 | } |
---|
1946 | debug(F101,"sdata sbufnum","",sbufnum); |
---|
1947 | for (i = sbufnum; i > 0; i--) { |
---|
1948 | debug(F101,"sdata countdown","",i); |
---|
1949 | x = nxtpkt(); /* Get next pkt number and buffer */ |
---|
1950 | debug(F101,"sdata packet","",pktnum); |
---|
1951 | if (x < 0) return(0); |
---|
1952 | if (cxseen || czseen) { /* If interrupted, done. */ |
---|
1953 | if (wslots > 1) { |
---|
1954 | drain = 1; |
---|
1955 | debug(F101,"sdata cx/zseen, drain","",cxseen); |
---|
1956 | return(0); |
---|
1957 | } else { |
---|
1958 | return(-1); |
---|
1959 | } |
---|
1960 | } |
---|
1961 | debug(F101,"sdata spsiz","",spsiz); |
---|
1962 | len = getpkt(spsiz,1); |
---|
1963 | if (len == 0) { /* Done if no data. */ |
---|
1964 | if (pktnum == winlo) return(-1); |
---|
1965 | drain = 1; /* But can't return -1 until all */ |
---|
1966 | debug(F101,"sdata eof, drain","",drain); |
---|
1967 | return(0); /* ACKs are drained. */ |
---|
1968 | } |
---|
1969 | spack('D',pktnum,len,data); /* Send the data packet. */ |
---|
1970 | /* |
---|
1971 | We should also want to call chkint() here to catch keyboard interruptions. |
---|
1972 | But its return codes don't tell us whether we should return from here or |
---|
1973 | keep going. |
---|
1974 | */ |
---|
1975 | x = ttchk(); /* Peek at input buffer. */ |
---|
1976 | debug(F101,"sdata ttchk","",x); /* ACKs waiting, maybe? */ |
---|
1977 | if (x < 0) /* Or connection broken? */ |
---|
1978 | return(-2); |
---|
1979 | /* |
---|
1980 | Here we check to see if any ACKs or NAKs have arrived, in which case we |
---|
1981 | break out of the D-packet-sending loop and return to the state switcher |
---|
1982 | to process them. This is what makes our windows slide instead of lurch. |
---|
1983 | */ |
---|
1984 | if ( |
---|
1985 | #ifdef GEMDOS |
---|
1986 | /* |
---|
1987 | In the Atari ST version, ttchk() can only return 0 or 1. But note: x will |
---|
1988 | probably always be > 0, since the as-yet-unread packet terminator from the |
---|
1989 | last packet is probably still in the buffer, so sliding windows will |
---|
1990 | probably never happen when the Atari ST is the file sender. The alternative |
---|
1991 | is to say "if (0)", in which case the ST will always send a window full of |
---|
1992 | packets before reading any ACKs or NAKs. |
---|
1993 | */ |
---|
1994 | x > 0 |
---|
1995 | |
---|
1996 | #else /* !GEMDOS */ |
---|
1997 | /* |
---|
1998 | In most other versions, ttchk() returns the actual count. |
---|
1999 | It can't be a Kermit packet if it's less than five bytes long. |
---|
2000 | */ |
---|
2001 | x > 4 + bctu |
---|
2002 | |
---|
2003 | #endif /* GEMDOS */ |
---|
2004 | ) |
---|
2005 | return(1); /* Yes, stop sending data packets */ |
---|
2006 | } /* and go try to read the ACKs. */ |
---|
2007 | return(1); |
---|
2008 | } |
---|
2009 | |
---|
2010 | |
---|
2011 | /* S E O F -- Send an End-Of-File packet */ |
---|
2012 | |
---|
2013 | /* Call with a string pointer to character to put in the data field, */ |
---|
2014 | /* or else a null pointer or "" for no data. */ |
---|
2015 | |
---|
2016 | /* |
---|
2017 | There are two "send-eof" functions. seof() is used to send the normal eof |
---|
2018 | packet at the end of a file's data (even if the file has no data), or when |
---|
2019 | a file transfer is interrupted. sxeof() is used to send an EOF packet that |
---|
2020 | occurs because of attribute refusal. The difference is purely a matter of |
---|
2021 | buffer allocation and packet sequence number management. Both functions |
---|
2022 | act as "front ends" to the common send-eof function, szeof(). |
---|
2023 | */ |
---|
2024 | |
---|
2025 | /* Code common to both seof() and sxeof() */ |
---|
2026 | |
---|
2027 | int |
---|
2028 | szeof(s) CHAR *s; { |
---|
2029 | lsstate = 0; /* Cancel locking-shift state */ |
---|
2030 | if ((s != NULL) && (*s != '\0')) { |
---|
2031 | spack('Z',pktnum,1,s); |
---|
2032 | xitsta |= W_SEND; |
---|
2033 | tlog(F100," *** interrupted, sending discard request","",0L); |
---|
2034 | filrej++; |
---|
2035 | } else { |
---|
2036 | spack('Z',pktnum,0,(CHAR *)""); |
---|
2037 | } |
---|
2038 | discard = 0; /* Turn off per-file discard flag */ |
---|
2039 | return(0); |
---|
2040 | } |
---|
2041 | |
---|
2042 | int |
---|
2043 | seof(s) CHAR *s; { |
---|
2044 | |
---|
2045 | /* |
---|
2046 | ckcpro.w, before calling seof(), sets window size back to 1 and then calls |
---|
2047 | window(), which clears out the old buffers. This is OK because the final |
---|
2048 | data packet for the file has been ACK'd. However, sdata() has already |
---|
2049 | called nxtpkt(), which set the new value of pktnum which seof() will use. |
---|
2050 | So all we need to do here is is allocate a new send-buffer. |
---|
2051 | */ |
---|
2052 | if (getsbuf(pktnum) < 0) { /* Get a buffer for packet n */ |
---|
2053 | debug(F101,"seof can't get s-buffer","",pktnum); |
---|
2054 | return(-1); |
---|
2055 | } |
---|
2056 | return(szeof(s)); |
---|
2057 | } |
---|
2058 | |
---|
2059 | /* |
---|
2060 | Version of seof() to be called when sdata() has not been called before. The |
---|
2061 | difference is that this version calls nxtpkt() to allocate a send-buffer and |
---|
2062 | get the next packet number. |
---|
2063 | */ |
---|
2064 | int |
---|
2065 | sxeof(s) CHAR *s; { |
---|
2066 | int x; |
---|
2067 | x = nxtpkt(); /* Get next pkt number and buffer */ |
---|
2068 | if (x < 0) |
---|
2069 | debug(F101,"sxeof nxtpkt fails","",pktnum); |
---|
2070 | else |
---|
2071 | debug(F101,"sxeof packet","",pktnum); |
---|
2072 | return(szeof(s)); |
---|
2073 | } |
---|
2074 | |
---|
2075 | /* S E O T -- Send an End-Of-Transaction packet */ |
---|
2076 | |
---|
2077 | int |
---|
2078 | seot() { |
---|
2079 | if (nxtpkt() < 0) return(-1); /* Bump packet number, get buffer */ |
---|
2080 | spack('B',pktnum,0,(CHAR *)""); /* Send the EOT packet */ |
---|
2081 | cxseen = czseen = discard = 0; /* Reset interruption flags */ |
---|
2082 | tstats(); /* Log timing info */ |
---|
2083 | return(0); |
---|
2084 | } |
---|
2085 | |
---|
2086 | |
---|
2087 | /* R P A R -- Fill the data array with my send-init parameters */ |
---|
2088 | |
---|
2089 | CHAR dada[32]; /* Use this instead of data[]. */ |
---|
2090 | /* To avoid some kind of wierd */ |
---|
2091 | /* addressing foulup in spack()... */ |
---|
2092 | /* (which might be fixed now...) */ |
---|
2093 | |
---|
2094 | CHAR * |
---|
2095 | rpar() { |
---|
2096 | char *p; |
---|
2097 | int i, x; |
---|
2098 | extern int xfermode; |
---|
2099 | if (rpsiz > MAXPACK) /* Biggest normal packet I want. */ |
---|
2100 | dada[0] = (char) tochar(MAXPACK); /* If > 94, use 94, but specify */ |
---|
2101 | else /* extended packet length below... */ |
---|
2102 | dada[0] = (char) tochar(rpsiz); /* else use what the user said. */ |
---|
2103 | dada[1] = (char) tochar(chktimo(pkttim,0)); /* When to time me out */ |
---|
2104 | dada[2] = (char) tochar(mypadn); /* How much padding I need (none) */ |
---|
2105 | dada[3] = (char) ctl(mypadc); /* Padding character I want */ |
---|
2106 | dada[4] = (char) tochar(eol); /* End-Of-Line character I want */ |
---|
2107 | dada[5] = myctlq; /* Control-Quote character I send */ |
---|
2108 | |
---|
2109 | switch (rqf) { /* 8th-bit prefix (single-shift) */ |
---|
2110 | case -1: /* I'm opening the bids */ |
---|
2111 | case 1: /* Other Kermit already bid 'Y' */ |
---|
2112 | if (parity) ebq = sq = MYEBQ; /* So I reply with '&' if parity */ |
---|
2113 | break; /* otherwise with 'Y'. */ |
---|
2114 | case 0: /* Other Kermit bid nothing */ |
---|
2115 | case 2: /* Other Kermit sent a valid prefix */ |
---|
2116 | break; /* So I reply with 'Y'. */ |
---|
2117 | } |
---|
2118 | debug(F000,"rpar 8bq sq","",sq); |
---|
2119 | debug(F000,"rpar 8bq ebq","",ebq); |
---|
2120 | if (lscapu == 2) /* LOCKING-SHIFT FORCED */ |
---|
2121 | dada[6] = 'N'; /* requires no single-shift */ |
---|
2122 | else /* otherwise send prefix or 'Y' */ |
---|
2123 | dada[6] = (char) sq; |
---|
2124 | ebqsent = dada[6]; /* And remember what I really sent */ |
---|
2125 | |
---|
2126 | dada[7] = (char) (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */ |
---|
2127 | if (rptena) { |
---|
2128 | if (rptflg) /* Run length encoding */ |
---|
2129 | dada[8] = (char) rptq; /* If receiving, agree */ |
---|
2130 | else /* by replying with same character. */ |
---|
2131 | dada[8] = (char) (rptq = myrptq); /* When sending use this. */ |
---|
2132 | } else dada[8] = SP; /* Not enabled, put a space here. */ |
---|
2133 | |
---|
2134 | /* CAPAS mask */ |
---|
2135 | |
---|
2136 | dada[9] = (char) tochar((lscapr ? lscapb : 0) | /* Locking shifts */ |
---|
2137 | (atcapr ? atcapb : 0) | /* Attribute packets */ |
---|
2138 | (lpcapr ? lpcapb : 0) | /* Long packets */ |
---|
2139 | (swcapr ? swcapb : 0) | /* Sliding windows */ |
---|
2140 | (rscapr ? rscapb : 0)); /* RESEND */ |
---|
2141 | dada[10] = (char) tochar(swcapr ? wslotr : 1); /* CAPAS+1 = Window size */ |
---|
2142 | if (urpsiz > 94) |
---|
2143 | rpsiz = urpsiz - 1; /* Long packets ... */ |
---|
2144 | dada[11] = (char) tochar(rpsiz / 95); /* Long packet size, big part */ |
---|
2145 | dada[12] = (char) tochar(rpsiz % 95); /* Long packet size, little part */ |
---|
2146 | dada[13] = '0'; /* CAPAS+4 = WONT CHKPNT */ |
---|
2147 | dada[14] = '_'; /* CAPAS+5 = CHKINT (reserved) */ |
---|
2148 | dada[15] = '_'; /* CAPAS+6 = CHKINT (reserved) */ |
---|
2149 | dada[16] = '_'; /* CAPAS+7 = CHKINT (reserved) */ |
---|
2150 | #ifndef WHATAMI |
---|
2151 | dada[17] = ' '; |
---|
2152 | #else |
---|
2153 | dada[17] = (char) tochar( WM_FLAG | /* CAPAS+8 = WHATAMI... */ |
---|
2154 | (server ? WM_SERVE : 0) | /* I am (not) a server */ |
---|
2155 | (binary ? WM_FMODE : 0) | /* My file transfer mode is ... */ |
---|
2156 | (fncnv ? WM_FNAME : 0)); /* My filename conversion is ... */ |
---|
2157 | #endif /* WHATAMI */ |
---|
2158 | i = 18; /* Position of next field */ |
---|
2159 | if (xfermode == XMODE_A) { /* If TRANSFER MODE AUTOMATIC */ |
---|
2160 | p = cksysid; /* WHOAMI (my system ID) */ |
---|
2161 | x = strlen(p); |
---|
2162 | if (x > 0) { |
---|
2163 | dada[i++] = (char) tochar(x); |
---|
2164 | while (*p) |
---|
2165 | dada[i++] = *p++; |
---|
2166 | } |
---|
2167 | } else { /* TRANSFER MODE MANUAL */ |
---|
2168 | dada[i++] = (char) tochar(1); /* Length */ |
---|
2169 | dada[i++] = '0'; /* "0" means anonymous - don't do it */ |
---|
2170 | } |
---|
2171 | dada[i] = '\0'; /* Terminate the init string */ |
---|
2172 | |
---|
2173 | #ifdef DEBUG |
---|
2174 | if (deblog) { |
---|
2175 | debug(F110,"rpar",dada,0); |
---|
2176 | rdebu(dada,(int)strlen((char *)dada)); |
---|
2177 | } |
---|
2178 | #endif /* DEBUG */ |
---|
2179 | strcpy((char *)myinit,(char *)dada); |
---|
2180 | return(dada); /* Return pointer to string. */ |
---|
2181 | } |
---|
2182 | |
---|
2183 | int |
---|
2184 | spar(s) CHAR *s; { /* Set parameters */ |
---|
2185 | int x, y, lpsiz; |
---|
2186 | |
---|
2187 | debug(F110,"entering spar",s,0); |
---|
2188 | |
---|
2189 | s--; /* Line up with field numbers. */ |
---|
2190 | |
---|
2191 | /* Limit on size of outbound packets */ |
---|
2192 | x = (rln >= 1) ? xunchar(s[1]) : 80; |
---|
2193 | lpsiz = spsizr; /* Remember what they SET. */ |
---|
2194 | if (spsizf) { /* SET-command override? */ |
---|
2195 | if (x < spsizr) spsiz = x; /* Ignore LEN unless smaller */ |
---|
2196 | } else { /* otherwise */ |
---|
2197 | spsiz = (x < 10) ? 80 : x; /* believe them if reasonable */ |
---|
2198 | } |
---|
2199 | spmax = spsiz; /* Remember maximum size */ |
---|
2200 | |
---|
2201 | /* Timeout on inbound packets */ |
---|
2202 | if (timef) { |
---|
2203 | timint = rtimo; /* SET SEND TIMEOUT value overrides */ |
---|
2204 | } else { /* Otherwise use requested value, */ |
---|
2205 | x = (rln >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */ |
---|
2206 | timint = (x < 0) ? rtimo : x; |
---|
2207 | } |
---|
2208 | timint = chktimo(timint,timef); /* Adjust if necessary */ |
---|
2209 | |
---|
2210 | /* Outbound Padding */ |
---|
2211 | npad = 0; padch = '\0'; |
---|
2212 | if (rln >= 3) { |
---|
2213 | npad = xunchar(s[3]); |
---|
2214 | if (rln >= 4) padch = (CHAR) ctl(s[4]); else padch = 0; |
---|
2215 | } |
---|
2216 | if (npad) { |
---|
2217 | int i; |
---|
2218 | for (i = 0; i < npad; i++) padbuf[i] = dopar(padch); |
---|
2219 | } |
---|
2220 | |
---|
2221 | /* Outbound Packet Terminator */ |
---|
2222 | seol = (CHAR) (rln >= 5) ? xunchar(s[5]) : CR; |
---|
2223 | if ((seol < 1) || (seol > 31)) seol = CR; |
---|
2224 | |
---|
2225 | /* Control prefix that the other Kermit is sending */ |
---|
2226 | x = (rln >= 6) ? s[6] : '#'; |
---|
2227 | ctlq = (CHAR) (((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#'); |
---|
2228 | |
---|
2229 | /* 8th-bit prefix */ |
---|
2230 | /* |
---|
2231 | NOTE: Maybe this could be simplified using rcvtyp. |
---|
2232 | If rcvtyp == 'Y' then we're reading the ACK, |
---|
2233 | otherwise we're reading the other Kermit's initial bid. |
---|
2234 | But his horrendous code works, so leave it alone for now. |
---|
2235 | */ |
---|
2236 | rq = (rln >= 7) ? s[7] : 0; |
---|
2237 | if (rq == 'Y') rqf = 1; |
---|
2238 | else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2; |
---|
2239 | else rqf = 0; |
---|
2240 | debug(F000,"spar 8bq rq","",rq); |
---|
2241 | debug(F000,"spar 8bq sq","",sq); |
---|
2242 | debug(F000,"spar 8bq ebq","",ebq); |
---|
2243 | debug(F101,"spar 8bq rqf","",rqf); |
---|
2244 | switch (rqf) { |
---|
2245 | case 0: /* Field is missing from packet. */ |
---|
2246 | ebqflg = 0; /* So no 8th-bit prefixing. */ |
---|
2247 | break; |
---|
2248 | case 1: /* Other Kermit sent 'Y' = Will Do. */ |
---|
2249 | /* |
---|
2250 | When I am the file receiver, ebqsent is 0 because I didn't send a |
---|
2251 | negotiation yet. If my parity is set to anything other than NONE, |
---|
2252 | either because my user SET PARITY or because I detected parity bits |
---|
2253 | on this packet, I reply with '&', otherwise 'Y'. |
---|
2254 | |
---|
2255 | When I am the file sender, ebqsent is what I just sent in rpar(), |
---|
2256 | which can be 'Y', 'N', or '&'. If I sent '&', then this 'Y' means |
---|
2257 | the other Kermit agrees to do 8th-bit prefixing. |
---|
2258 | |
---|
2259 | If I sent 'Y' or 'N', but then detected parity on the ACK packet |
---|
2260 | that came back, then it's too late: there is no longer any way for |
---|
2261 | me to tell the other Kermit that I want to do 8th-bit prefixing, so |
---|
2262 | I must not do it, and in that case, if there is any 8-bit data in |
---|
2263 | the file to be transferred, the transfer will fail because of block |
---|
2264 | check errors. |
---|
2265 | |
---|
2266 | The following clause covers all of these situations: |
---|
2267 | */ |
---|
2268 | if (parity && (ebqsent == 0 || ebqsent == '&')) { |
---|
2269 | ebqflg = 1; |
---|
2270 | ebq = MYEBQ; |
---|
2271 | } |
---|
2272 | break; |
---|
2273 | case 2: /* Other Kermit send a valid prefix */ |
---|
2274 | if (ebqflg = (ebq == sq || sq == 'Y')) |
---|
2275 | ebq = rq; |
---|
2276 | } |
---|
2277 | if (lscapu == 2) { /* But no single-shifts if LOCKING-SHIFT FORCED */ |
---|
2278 | ebqflg = 0; |
---|
2279 | ebq = 'N'; |
---|
2280 | } |
---|
2281 | |
---|
2282 | /* Block check */ |
---|
2283 | x = 1; |
---|
2284 | if (rln >= 8) { |
---|
2285 | if (s[8] == 'B') x = 4; |
---|
2286 | else x = s[8] - '0'; |
---|
2287 | if ((x < 1) || (x > 4)) x = 1; |
---|
2288 | } |
---|
2289 | bctr = x; |
---|
2290 | |
---|
2291 | /* Repeat prefix */ |
---|
2292 | |
---|
2293 | rptflg = 0; /* Assume no repeat-counts */ |
---|
2294 | if (rln >= 9) { /* Is there a repeat-count field? */ |
---|
2295 | char t; /* Yes. */ |
---|
2296 | t = s[9]; /* Get its contents. */ |
---|
2297 | /* |
---|
2298 | If I'm sending files, then I'm reading these parameters from an ACK, and so |
---|
2299 | this character must agree with what I sent. |
---|
2300 | */ |
---|
2301 | if (rptena) { /* If enabled ... */ |
---|
2302 | if ((char) rcvtyp == 'Y') { /* Sending files, reading ACK. */ |
---|
2303 | if (t == myrptq) rptflg = 1; |
---|
2304 | } else { /* I'm receiving files */ |
---|
2305 | if ((t > 32 && t < 63) || (t > 95 && t < 127)) { |
---|
2306 | rptflg = 1; |
---|
2307 | rptq = t; |
---|
2308 | } |
---|
2309 | } |
---|
2310 | } else rptflg = 0; |
---|
2311 | } |
---|
2312 | |
---|
2313 | /* Capabilities */ |
---|
2314 | |
---|
2315 | atcapu = lpcapu = swcapu = rscapu = 0; /* Assume none of these. */ |
---|
2316 | if (lscapu != 2) lscapu = 0; /* Assume no LS unless forced. */ |
---|
2317 | y = 11; /* Position of next field, if any */ |
---|
2318 | if (rln >= 10) { |
---|
2319 | x = xunchar(s[10]); |
---|
2320 | debug(F101,"spar capas","",x); |
---|
2321 | atcapu = (x & atcapb) && atcapr; /* Attributes */ |
---|
2322 | lpcapu = (x & lpcapb) && lpcapr; /* Long packets */ |
---|
2323 | swcapu = (x & swcapb) && swcapr; /* Sliding windows */ |
---|
2324 | rscapu = (x & rscapb) && rscapr; /* RESEND */ |
---|
2325 | debug(F101,"spar lscapu","",lscapu); |
---|
2326 | debug(F101,"spar lscapr","",lscapr); |
---|
2327 | debug(F101,"spar ebqflg","",ebqflg); |
---|
2328 | if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0; |
---|
2329 | debug(F101,"spar swcapr","",swcapr); |
---|
2330 | debug(F101,"spar swcapu","",swcapu); |
---|
2331 | debug(F101,"spar lscapu","",lscapu); |
---|
2332 | for (y = 10; (xunchar(s[y]) & 1) && (rln >= y); y++); |
---|
2333 | debug(F101,"spar y","",y); |
---|
2334 | } |
---|
2335 | |
---|
2336 | /* Long Packets */ |
---|
2337 | debug(F101,"spar lpcapu","",lpcapu); |
---|
2338 | if (lpcapu) { |
---|
2339 | if (rln > y+1) { |
---|
2340 | x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]); |
---|
2341 | debug(F101,"spar lp len","",x); |
---|
2342 | if (spsizf) { /* If overriding negotiations */ |
---|
2343 | spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */ |
---|
2344 | } else { /* otherwise */ |
---|
2345 | spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */ |
---|
2346 | } |
---|
2347 | if (spsiz < 10) spsiz = 80; /* Be defensive... */ |
---|
2348 | } |
---|
2349 | } |
---|
2350 | /* (PWP) save current send packet size for optimal packet size calcs */ |
---|
2351 | spmax = spsiz; /* Maximum negotiated length */ |
---|
2352 | if (slostart && spsiz > 499) spsiz = 244; /* Slow start length */ |
---|
2353 | debug(F101,"spar slow-start spsiz","",spsiz); |
---|
2354 | debug(F101,"spar lp spmax","",spmax); |
---|
2355 | timint = chktimo(timint,timef); /* Recalculate the packet timeout */ |
---|
2356 | |
---|
2357 | /* Sliding Windows... */ |
---|
2358 | |
---|
2359 | if (swcapr) { /* Only if requested... */ |
---|
2360 | if (rln > y) { /* See what other Kermit says */ |
---|
2361 | x = xunchar(s[y+1]); |
---|
2362 | debug(F101,"spar window","",x); |
---|
2363 | wslotn = (x > MAXWS) ? MAXWS : x; |
---|
2364 | /* |
---|
2365 | wslotn = negotiated size (from other Kermit's S or I packet). |
---|
2366 | wslotr = requested window size (from this Kermit's SET WINDOW command). |
---|
2367 | */ |
---|
2368 | if (wslotn > wslotr) /* Use the smaller of the two */ |
---|
2369 | wslotn = wslotr; |
---|
2370 | if (wslotn < 1) /* Watch out for bad negotiation */ |
---|
2371 | wslotn = 1; |
---|
2372 | if (wslotn > 1) { |
---|
2373 | swcapu = 1; /* We do windows... */ |
---|
2374 | if (wslotn > maxtry) /* Retry limit must be greater */ |
---|
2375 | maxtry = wslotn + 1; /* than window size. */ |
---|
2376 | } |
---|
2377 | debug(F101,"spar window after adjustment","",x); |
---|
2378 | } else { /* No window size specified. */ |
---|
2379 | wslotn = 1; /* We don't do windows... */ |
---|
2380 | debug(F101,"spar window","",x); |
---|
2381 | swcapu = 0; |
---|
2382 | debug(F101,"spar no windows","",wslotn); |
---|
2383 | } |
---|
2384 | } |
---|
2385 | |
---|
2386 | /* Now recalculate packet length based on number of windows. */ |
---|
2387 | /* The nogotiated number of window slots will be allocated, */ |
---|
2388 | /* and the maximum packet length will be reduced if necessary, */ |
---|
2389 | /* so that a windowful of packets can fit in the big buffer. */ |
---|
2390 | |
---|
2391 | if (wslotn > 1) { /* Shrink to fit... */ |
---|
2392 | x = adjpkl(spmax,wslotn,bigsbsiz); |
---|
2393 | if (x < spmax) { |
---|
2394 | spmax = x; |
---|
2395 | if (slostart && spsiz > 499) spsiz = 244; /* Slow start again */ |
---|
2396 | debug(F101,"spar sending, redefine spmax","",spmax); |
---|
2397 | } |
---|
2398 | } |
---|
2399 | #ifdef WHATAMI |
---|
2400 | if (rln > y+7) /* Get WHATAMI info if any */ |
---|
2401 | whatru = xunchar(s[y+8]); |
---|
2402 | #endif /* WHATAMI */ |
---|
2403 | |
---|
2404 | if (rln > y+8) { /* Get WHOAREYOU info if any */ |
---|
2405 | int x; |
---|
2406 | x = xunchar(s[y+9]); /* Length of it */ |
---|
2407 | if (x > 0 && x < 16 && rln >= y + 9 + x) { |
---|
2408 | strncpy(whoareu,(char *)s+y+10,x); /* Other Kermit's system ID */ |
---|
2409 | if (whoareu[0]) { /* Got one? */ |
---|
2410 | char *p; |
---|
2411 | #ifdef COMMENT |
---|
2412 | char buf[64]; |
---|
2413 | #endif /* COMMENT */ |
---|
2414 | extern int sysindex; |
---|
2415 | extern struct sysdata sysidlist[]; |
---|
2416 | |
---|
2417 | sysindex = getsysix((char *)whoareu); |
---|
2418 | if (sysindex > -1) { |
---|
2419 | p = sysidlist[sysindex].sid_name; |
---|
2420 | #ifdef COMMENT |
---|
2421 | sprintf(buf,"Remote system type is %s", p); |
---|
2422 | screen(SCR_ST,ST_MSG,0L,buf); |
---|
2423 | #endif /* COMMENT */ |
---|
2424 | tlog(F110,"Remote system type: ",p,0L); |
---|
2425 | if (sysindex > 0) /* Skip this for "anonymous" */ |
---|
2426 | whoarewe(); |
---|
2427 | } |
---|
2428 | } |
---|
2429 | } |
---|
2430 | } |
---|
2431 | /* Record parameters in debug log */ |
---|
2432 | #ifdef DEBUG |
---|
2433 | if (deblog) sdebu(rln); |
---|
2434 | #endif /* DEBUG */ |
---|
2435 | numerrs = 0; /* Start counting errors here. */ |
---|
2436 | return(0); |
---|
2437 | } |
---|
2438 | |
---|
2439 | /* G N F I L E -- Get name of next file to send */ |
---|
2440 | /* |
---|
2441 | Expects global sndsrc to be: |
---|
2442 | -1: next filename to be obtained by calling znext(). |
---|
2443 | 0: no next file name |
---|
2444 | 1: (or greater) next filename to be obtained from **cmlist, |
---|
2445 | or if addlist != 0, from the "filehead" linked list. |
---|
2446 | Returns: |
---|
2447 | 1, with name of next file in filnam. |
---|
2448 | 0, no more files, with filnam set to empty string. |
---|
2449 | -1, file not found |
---|
2450 | -2, file is not readable |
---|
2451 | -3, read access denied |
---|
2452 | -4, cancelled |
---|
2453 | -5, too many files match wildcard |
---|
2454 | */ |
---|
2455 | |
---|
2456 | int |
---|
2457 | gnfile() { |
---|
2458 | int i, x; long y; |
---|
2459 | int retcode = 0; |
---|
2460 | char fullname[CKMAXPATH+1]; |
---|
2461 | |
---|
2462 | debug(F101,"gnfile sndsrc","",sndsrc); |
---|
2463 | fsize = -1L; /* Initialize file size */ |
---|
2464 | if (sndsrc == 0) { /* It's not really a file */ |
---|
2465 | if (nfils > 0) { /* It's a pipe, or stdin */ |
---|
2466 | strcpy(filnam, *cmlist); /* Copy its "name" */ |
---|
2467 | nfils = 0; /* There is no next file */ |
---|
2468 | return(1); /* OK this time */ |
---|
2469 | } else return(0); /* but not next time */ |
---|
2470 | } |
---|
2471 | |
---|
2472 | /* If file group interruption (C-Z) occurred, fail. */ |
---|
2473 | |
---|
2474 | if (czseen) { |
---|
2475 | tlog(F100,"Transaction cancelled","",0L); |
---|
2476 | debug(F100,"gnfile czseen","",0); |
---|
2477 | return(-4); |
---|
2478 | } |
---|
2479 | |
---|
2480 | /* Loop through file list till we find a readable, sendable file */ |
---|
2481 | |
---|
2482 | y = -1L; /* Loop exit (file size) variable */ |
---|
2483 | while (y < 0L) { /* Keep trying till we get one... */ |
---|
2484 | if (sndsrc > 0) { /* File list in cmlist */ |
---|
2485 | debug(F101,"gnfile nfils","",nfils); |
---|
2486 | if (nfils-- > 0) { /* Still some left? */ |
---|
2487 | #ifndef NOMSEND |
---|
2488 | if (addlist) { |
---|
2489 | if (filenext && filenext->fl_name) { |
---|
2490 | strncpy(filnam,filenext->fl_name,CKMAXPATH); |
---|
2491 | cmarg2 = |
---|
2492 | filenext->fl_alias ? |
---|
2493 | filenext->fl_alias : |
---|
2494 | ""; |
---|
2495 | binary = filenext->fl_mode; /* plug and pray... */ |
---|
2496 | } else { |
---|
2497 | printf("?Internal error expanding ADD list\n"); |
---|
2498 | return(-5); |
---|
2499 | } |
---|
2500 | filenext = filenext->fl_next; |
---|
2501 | debug(F111,"gnfile addlist filnam",filnam,nfils); |
---|
2502 | } else { |
---|
2503 | #endif /* NOMSEND */ |
---|
2504 | strncpy(filnam,*cmlist++,CKMAXPATH); |
---|
2505 | debug(F111,"gnfile cmlist filnam",filnam,nfils); |
---|
2506 | #ifndef NOMSEND |
---|
2507 | } |
---|
2508 | #endif /* NOMSEND */ |
---|
2509 | i = 0; |
---|
2510 | #ifndef NOSERVER |
---|
2511 | debug(F101,"gnfile ngetpath","",ngetpath); |
---|
2512 | #endif /* NOSERVER */ |
---|
2513 | nextinpath: |
---|
2514 | #ifndef NOSERVER |
---|
2515 | if (server && !isabsolute(filnam) && (ngetpath > i)) { |
---|
2516 | strncpy(fullname,getpath[i],CKMAXPATH); |
---|
2517 | strncat(fullname,filnam,CKMAXPATH); |
---|
2518 | debug(F111,"gnfile getpath",fullname,i); |
---|
2519 | i++; |
---|
2520 | } else { |
---|
2521 | i = ngetpath + 1; |
---|
2522 | #else |
---|
2523 | i = 1; /* ? */ |
---|
2524 | #endif /* NOSERVER */ |
---|
2525 | strncpy(fullname,filnam,CKMAXPATH); |
---|
2526 | debug(F110,"gnfile absolute",fullname,0); |
---|
2527 | #ifndef NOSERVER |
---|
2528 | } |
---|
2529 | #endif /* NOSERVER */ |
---|
2530 | if (iswild(fullname)) { /* It looks wild... */ |
---|
2531 | /* First check if a file with this name exists */ |
---|
2532 | debug(F110,"gnfile wild",fullname,0); |
---|
2533 | if (zchki(fullname) > -1) { |
---|
2534 | /* |
---|
2535 | Here we have a file whose name actually |
---|
2536 | contains wildcard characters. |
---|
2537 | */ |
---|
2538 | goto gotnam; |
---|
2539 | } |
---|
2540 | x = zxpand(fullname); /* Now try to expand wildcards */ |
---|
2541 | debug(F101,"gnfile zxpand","",x); |
---|
2542 | if (x == 1) { |
---|
2543 | znext(fullname); |
---|
2544 | debug(F110,"gnfile znext",fullname,0); |
---|
2545 | goto gotnam; |
---|
2546 | } |
---|
2547 | if (x == 0) { /* None match */ |
---|
2548 | #ifndef NOSERVER |
---|
2549 | if (server && ngetpath > i) |
---|
2550 | goto nextinpath; |
---|
2551 | #endif /* NOSERVER */ |
---|
2552 | retcode = -1; |
---|
2553 | continue; |
---|
2554 | } |
---|
2555 | if (x < 0) /* Too many to expand */ |
---|
2556 | return(-5); |
---|
2557 | sndsrc = -1; /* Change send-source to znext() */ |
---|
2558 | } |
---|
2559 | } else { /* We're out of files. */ |
---|
2560 | debug(F101,"gnfile done","",nfils); |
---|
2561 | *filnam = '\0'; |
---|
2562 | return(retcode); |
---|
2563 | } |
---|
2564 | } |
---|
2565 | |
---|
2566 | /* Otherwise, step to next element of internal wildcard expansion list. */ |
---|
2567 | |
---|
2568 | if (sndsrc < 0) { |
---|
2569 | x = znext(filnam); |
---|
2570 | debug(F111,"gnfile znext",filnam,x); |
---|
2571 | if (x == 0) { /* If no more, */ |
---|
2572 | sndsrc = 1; /* go back to list */ |
---|
2573 | continue; |
---|
2574 | } else strncpy(fullname,filnam,CKMAXPATH); |
---|
2575 | } |
---|
2576 | |
---|
2577 | /* Get here with a filename. */ |
---|
2578 | |
---|
2579 | gotnam: |
---|
2580 | if (sndsrc) { |
---|
2581 | y = zchki(fullname); /* Check if file readable */ |
---|
2582 | retcode = (int) y; /* Possible return code */ |
---|
2583 | if (y == -1L) { /* If not found */ |
---|
2584 | #ifndef NOSERVER |
---|
2585 | if (server && ngetpath > i) |
---|
2586 | goto nextinpath; |
---|
2587 | #endif /* NOSERVER */ |
---|
2588 | debug(F110,"gnfile skipping:",fullname,0); |
---|
2589 | tlog(F111,fullname,"not sent, reason",(long)y); |
---|
2590 | screen(SCR_ST,ST_SKIP,0l,fullname); |
---|
2591 | continue; |
---|
2592 | } else if (y < 0) { |
---|
2593 | if (y == -3) { /* Exists but not readable */ |
---|
2594 | filrej++; /* Count this one as not sent */ |
---|
2595 | tlog(F110,"Read access denied",fullname,0); /* Log this */ |
---|
2596 | screen(SCR_ST,ST_SKIP,0l,fullname); /* Display message */ |
---|
2597 | } |
---|
2598 | continue; |
---|
2599 | } else { |
---|
2600 | fsize = y; |
---|
2601 | strncpy(filnam,fullname,CKMAXPATH); |
---|
2602 | return(1); |
---|
2603 | } |
---|
2604 | } else { /* sndsrc is 0... */ |
---|
2605 | strncpy(filnam,fullname,CKMAXPATH); |
---|
2606 | return(1); |
---|
2607 | } |
---|
2608 | } |
---|
2609 | *filnam = '\0'; /* Should never get here */ |
---|
2610 | return(0); |
---|
2611 | } |
---|
2612 | |
---|
2613 | /* S N D H L P -- Routine to send builtin help */ |
---|
2614 | |
---|
2615 | int |
---|
2616 | sndhlp(p) char *p; { |
---|
2617 | #ifndef NOSERVER |
---|
2618 | nfils = 0; /* No files, no lists. */ |
---|
2619 | xflg = 1; /* Flag we must send X packet. */ |
---|
2620 | strcpy(cmdstr,versio); /* Data for X packet. */ |
---|
2621 | first = 1; /* Init getchx lookahead */ |
---|
2622 | memstr = 1; /* Just set the flag. */ |
---|
2623 | memptr = p; /* And the pointer. */ |
---|
2624 | binary = XYFT_T; /* Text mode for this. */ |
---|
2625 | return(sinit()); |
---|
2626 | #else |
---|
2627 | return(0); |
---|
2628 | #endif /* NOSERVER */ |
---|
2629 | } |
---|
2630 | |
---|
2631 | /* |
---|
2632 | The following bunch of routines feed internally generated data to the server |
---|
2633 | to send to the client in response to REMOTE commands like DIRECTORY, DELETE, |
---|
2634 | and so on. Note that in writing this data to buffers, we do not use "\n". |
---|
2635 | Instead we use "\15\12", i.e. LITERAL carriage return and linefeed, because |
---|
2636 | that it was is required by the Kermit protocol in text mode. |
---|
2637 | */ |
---|
2638 | static |
---|
2639 | char funcbuf[512]; |
---|
2640 | static int |
---|
2641 | funcnxt = 0, |
---|
2642 | funclen = 0, |
---|
2643 | nxpnd = - 1; |
---|
2644 | static long |
---|
2645 | ndirs = 0, |
---|
2646 | nfiles = 0, |
---|
2647 | nbytes = 0; |
---|
2648 | |
---|
2649 | /* N X T T Y P -- provide data to type file to remote client */ |
---|
2650 | /* |
---|
2651 | Returns the next available character, |
---|
2652 | -1 if no more data. |
---|
2653 | */ |
---|
2654 | int |
---|
2655 | nxttype() { |
---|
2656 | int c; |
---|
2657 | |
---|
2658 | if (zchin(ZIFILE,&c) < 0) { |
---|
2659 | zclose(ZIFILE); |
---|
2660 | return(-1); |
---|
2661 | } else |
---|
2662 | return((unsigned)c); |
---|
2663 | } |
---|
2664 | |
---|
2665 | /* S N D T Y P -- TYPE a file to remote client */ |
---|
2666 | |
---|
2667 | int |
---|
2668 | #ifdef CK_ANSI |
---|
2669 | sndtype(char * file) |
---|
2670 | #else |
---|
2671 | sndtype(file) char * file; |
---|
2672 | #endif /* CK_ANSI */ |
---|
2673 | /* sndtype */ { |
---|
2674 | |
---|
2675 | #ifndef NOSERVER |
---|
2676 | char * p = NULL, name[CKMAXPATH+1]; |
---|
2677 | |
---|
2678 | #ifdef OS2 |
---|
2679 | if (*file) { |
---|
2680 | strcpy(name, file); |
---|
2681 | /* change / to \. */ |
---|
2682 | p = name; |
---|
2683 | while (*p) { /* Change them back to \ */ |
---|
2684 | if (*p == '/') *p = '\\'; |
---|
2685 | p++; |
---|
2686 | } |
---|
2687 | } else |
---|
2688 | return(0); |
---|
2689 | #else |
---|
2690 | strcpy(name, file); |
---|
2691 | #endif /* OS2 */ |
---|
2692 | |
---|
2693 | funcnxt = 0; |
---|
2694 | funclen = strlen(funcbuf); |
---|
2695 | if (zchki(name) == -2) { |
---|
2696 | /* Found a directory */ |
---|
2697 | return(0); |
---|
2698 | } |
---|
2699 | if (!zopeni(ZIFILE,name)) |
---|
2700 | return(0); |
---|
2701 | |
---|
2702 | nfils = 0; /* No files, no lists. */ |
---|
2703 | xflg = 1; /* Flag we must send X packet. */ |
---|
2704 | strcpy(cmdstr,"type"); /* Data for X packet. */ |
---|
2705 | first = 1; /* Init getchx lookahead */ |
---|
2706 | funcstr = 1; /* Just set the flag. */ |
---|
2707 | funcptr = nxttype; /* And the pointer. */ |
---|
2708 | binary = XYFT_T; /* Text mode for this */ |
---|
2709 | return(sinit()); |
---|
2710 | #else |
---|
2711 | return(0); |
---|
2712 | #endif /* NOSERVER */ |
---|
2713 | } |
---|
2714 | |
---|
2715 | /* |
---|
2716 | N X T D I R -- Provide data for senddir() |
---|
2717 | |
---|
2718 | Returns the next available character or -1 if no more data. |
---|
2719 | */ |
---|
2720 | static int |
---|
2721 | nxtdir() { |
---|
2722 | char name[257], *p = NULL; |
---|
2723 | char * dstr = NULL; |
---|
2724 | long len = 0; |
---|
2725 | short month = 0, date = 0, year = 0, hour = 0, minute = 0, seconds = 0; |
---|
2726 | |
---|
2727 | debug(F111,"nxtdir","funcnxt",funcnxt); |
---|
2728 | debug(F110,"nxtdir funcbuf",funcbuf+funcnxt,0); |
---|
2729 | if (funcnxt < funclen) |
---|
2730 | return (funcbuf[funcnxt++]); |
---|
2731 | |
---|
2732 | if (nxpnd > 0) { |
---|
2733 | nxpnd--; |
---|
2734 | if (!znext(name)) { |
---|
2735 | nxpnd = 0; |
---|
2736 | return(nxtdir()); |
---|
2737 | } |
---|
2738 | dstr = zfcdat(name); |
---|
2739 | if (!dstr) dstr = ""; |
---|
2740 | if (*dstr) { |
---|
2741 | month = (dstr[4]-48)*10 + (dstr[5]-48); |
---|
2742 | #ifdef COMMENT |
---|
2743 | switch(month) { /* For anglophones only... */ |
---|
2744 | case 1: mstr = "Jan"; break; |
---|
2745 | case 2: mstr = "Feb"; break; |
---|
2746 | case 3: mstr = "Mar"; break; |
---|
2747 | case 4: mstr = "Apr"; break; |
---|
2748 | case 5: mstr = "May"; break; |
---|
2749 | case 6: mstr = "Jun"; break; |
---|
2750 | case 7: mstr = "Jul"; break; |
---|
2751 | case 8: mstr = "Aug"; break; |
---|
2752 | case 9: mstr = "Sep"; break; |
---|
2753 | case 10: mstr = "Oct"; break; |
---|
2754 | case 11: mstr = "Nov"; break; |
---|
2755 | case 12: mstr = "Dec"; break; |
---|
2756 | default: mstr = " "; |
---|
2757 | } |
---|
2758 | #endif /* COMMENT */ |
---|
2759 | date = (dstr[6]-48)*10 + (dstr[7]-48); |
---|
2760 | year = (((dstr[0]-48)*10 + (dstr[1]-48))*10 |
---|
2761 | + (dstr[2]-48))*10 + (dstr[3]-48); |
---|
2762 | hour = (dstr[9]-48)*10 + (dstr[10]-48); |
---|
2763 | minute = (dstr[12]-48)*10 + (dstr[13]-48); |
---|
2764 | seconds = (dstr[15]-48)*10 + (dstr[16]-48); |
---|
2765 | } else { |
---|
2766 | month = 0; |
---|
2767 | date = 0; |
---|
2768 | year = 0; |
---|
2769 | hour = 0; |
---|
2770 | minute = 0; |
---|
2771 | seconds = 0; |
---|
2772 | } |
---|
2773 | len = zchki(name); |
---|
2774 | /* Find just the name of the file */ |
---|
2775 | #ifdef VMS |
---|
2776 | p = name + ckindex("]",name,0,0,1); |
---|
2777 | #else |
---|
2778 | for (p = name + (int) strlen(name); |
---|
2779 | p != name && *p != '/' |
---|
2780 | #ifdef OS2 |
---|
2781 | && *p != '\\' && *p != ':' |
---|
2782 | #endif /* OS2 */ |
---|
2783 | ; p-- |
---|
2784 | ); |
---|
2785 | if (*p == '/' |
---|
2786 | #ifdef OS2 |
---|
2787 | || *p == '\\' || *p == ':' |
---|
2788 | #endif /* OS2 */ |
---|
2789 | ) |
---|
2790 | p++; |
---|
2791 | #endif /* VMS */ |
---|
2792 | if (len > -1L) { |
---|
2793 | nfiles++; |
---|
2794 | nbytes += len; |
---|
2795 | sprintf(funcbuf," %04d-%02d-%02d %02d:%02d %11ld %s\15\12", |
---|
2796 | year, month, date, hour, minute, len, p); |
---|
2797 | } else { |
---|
2798 | ndirs++; |
---|
2799 | sprintf(funcbuf, |
---|
2800 | " %04d-%02d-%02d %02d:%02d %11s %s\15\12", |
---|
2801 | year, month, date, hour, minute, "(directory)", p); |
---|
2802 | } |
---|
2803 | funcnxt = 0; |
---|
2804 | funclen = strlen(funcbuf); |
---|
2805 | } else if (nxpnd == 0) { /* Done, send summary */ |
---|
2806 | char *blankline = ""; /* At beginning of summary */ |
---|
2807 | char *endline = "\15\12"; /* At end of summary */ |
---|
2808 | /* |
---|
2809 | The idea is to prevent (a) unnecessary multiple blanklines, and (b) |
---|
2810 | prompt-stomping. Preventing (b) is practically impossible, because it |
---|
2811 | depends on the client so for now always include that final CRLF. |
---|
2812 | */ |
---|
2813 | if (!ndirs || !nbytes || !nfiles) |
---|
2814 | blankline = "\15\12"; |
---|
2815 | sprintf(funcbuf, |
---|
2816 | "%sSummary: %ld director%s, %ld file%s, %ld byte%s%s", |
---|
2817 | blankline, |
---|
2818 | ndirs, |
---|
2819 | (ndirs == 1) ? "y" : "ies", |
---|
2820 | nfiles, |
---|
2821 | (nfiles == 1) ? "" : "s", |
---|
2822 | nbytes, |
---|
2823 | (nbytes == 1) ? "" : "s", |
---|
2824 | endline |
---|
2825 | ); |
---|
2826 | nxpnd--; |
---|
2827 | funcnxt = 0; |
---|
2828 | funclen = strlen(funcbuf); |
---|
2829 | } else { |
---|
2830 | funcbuf[0] = '\0'; |
---|
2831 | funcnxt = 0; |
---|
2832 | funclen = 0; |
---|
2833 | } |
---|
2834 | /* If we have data to send... */ |
---|
2835 | |
---|
2836 | if (funcnxt < funclen) |
---|
2837 | return(funcbuf[funcnxt++]); /* Return a character */ |
---|
2838 | else |
---|
2839 | return(-1); /* Nothing left, done. */ |
---|
2840 | } |
---|
2841 | |
---|
2842 | /* S N D D I R -- send directory listing */ |
---|
2843 | |
---|
2844 | int |
---|
2845 | #ifdef CK_ANSI |
---|
2846 | snddir(char * spec) |
---|
2847 | #else |
---|
2848 | snddir(spec) char * spec; |
---|
2849 | #endif /* CK_ANSI */ |
---|
2850 | /* snddir */ { |
---|
2851 | #ifndef NOSERVER |
---|
2852 | char * p = NULL, name[257]; |
---|
2853 | int rc = 0; |
---|
2854 | |
---|
2855 | if (!spec) spec = ""; |
---|
2856 | debug(F110,"snddir",spec,0); |
---|
2857 | if (*spec) { |
---|
2858 | strcpy(name, spec); |
---|
2859 | #ifdef OS2 |
---|
2860 | /* change / to \. */ |
---|
2861 | p = name; |
---|
2862 | while (*p) { /* Change them back to \ */ |
---|
2863 | if (*p == '/') *p = '\\'; |
---|
2864 | p++; |
---|
2865 | } |
---|
2866 | #endif /* OS2 */ |
---|
2867 | } else { |
---|
2868 | #ifdef OS2 |
---|
2869 | strcpy(name, "."); |
---|
2870 | #else |
---|
2871 | #ifdef UNIX |
---|
2872 | strcpy(name, "./*"); |
---|
2873 | #else |
---|
2874 | #ifdef VMS |
---|
2875 | strcpy(name, "*.*"); |
---|
2876 | #else |
---|
2877 | #ifdef datageneral |
---|
2878 | strcpy(name, "+"); |
---|
2879 | #else |
---|
2880 | return(0); |
---|
2881 | #endif /* datageneral */ |
---|
2882 | #endif /* VMS */ |
---|
2883 | #endif /* UNIX */ |
---|
2884 | #endif /* OS2 */ |
---|
2885 | p = name + strlen(name); /* Move it to end of list */ |
---|
2886 | } |
---|
2887 | ndirs = 0L; |
---|
2888 | nfiles = 0L; |
---|
2889 | nbytes = 0L; |
---|
2890 | sprintf(funcbuf,"Listing files: \"%s\"\15\12\15\12",name); |
---|
2891 | funcnxt = 0; |
---|
2892 | funclen = strlen(funcbuf); |
---|
2893 | |
---|
2894 | #ifdef OS2 |
---|
2895 | debug(F110,"snddir about to zchki",name,0); |
---|
2896 | if (zchki(name) == -2) { /* Found a directory */ |
---|
2897 | p--; |
---|
2898 | if (*p == '\\' || *p == '/') |
---|
2899 | strcat(name, "*"); |
---|
2900 | else if (*p == ':') |
---|
2901 | strcat(name, "."); |
---|
2902 | else |
---|
2903 | strcat(name, "\\*"); |
---|
2904 | } |
---|
2905 | #endif /* OS2 */ |
---|
2906 | |
---|
2907 | nxpnd = zxpand(name); |
---|
2908 | debug(F111,"snddir zxpand","nxpnd",nxpnd); |
---|
2909 | |
---|
2910 | nfils = 0; /* No files, no lists. */ |
---|
2911 | xflg = 1; /* Flag we must send X packet. */ |
---|
2912 | strcpy(cmdstr,"REMOTE DIRECTORY"); /* Data for X packet. */ |
---|
2913 | first = 1; /* Init getchx lookahead */ |
---|
2914 | funcstr = 1; /* Just set the flag. */ |
---|
2915 | funcptr = nxtdir; /* And the pointer. */ |
---|
2916 | binary = XYFT_T; /* Text mode for this, */ |
---|
2917 | rc = sinit(); |
---|
2918 | debug(F111,"snddir","sinit()",rc); |
---|
2919 | return(rc); |
---|
2920 | #else |
---|
2921 | return(0); |
---|
2922 | #endif /* NOSERVER */ |
---|
2923 | } |
---|
2924 | |
---|
2925 | /* N X T D E L -- provide data for delete */ |
---|
2926 | |
---|
2927 | /* Returns the next available character or -1 if no more data */ |
---|
2928 | |
---|
2929 | static int |
---|
2930 | nxtdel() { |
---|
2931 | char name[257], *p = NULL; |
---|
2932 | char * dstr = NULL; |
---|
2933 | int len = 0; |
---|
2934 | short month = 0, date = 0, year = 0, hour = 0, minute = 0, seconds = 0; |
---|
2935 | |
---|
2936 | if (funcnxt < funclen) |
---|
2937 | return (funcbuf[funcnxt++]); |
---|
2938 | |
---|
2939 | if (nxpnd > 0) { |
---|
2940 | nxpnd--; |
---|
2941 | if (!znext(name)) { |
---|
2942 | nxpnd = 0; |
---|
2943 | return(nxtdel()); |
---|
2944 | } |
---|
2945 | |
---|
2946 | len = zchki(name); |
---|
2947 | |
---|
2948 | /* Find just the name of the file */ |
---|
2949 | |
---|
2950 | for (p = name + strlen(name); p != name && *p != '/' ; p--) ; |
---|
2951 | if (*p == '/') p++; |
---|
2952 | |
---|
2953 | if (len > -1L) { |
---|
2954 | nfiles++; |
---|
2955 | nbytes += len; |
---|
2956 | sprintf(funcbuf, |
---|
2957 | " %10s: %s\15\12", |
---|
2958 | zdelet(name) ? "skipping" : "deleted", |
---|
2959 | p |
---|
2960 | ); |
---|
2961 | } else |
---|
2962 | sprintf(funcbuf," directory: %s\15\12", p); |
---|
2963 | funcnxt = 0; |
---|
2964 | funclen = strlen(funcbuf); |
---|
2965 | } else |
---|
2966 | |
---|
2967 | /* If done processing the expanded entries send a summary statement */ |
---|
2968 | |
---|
2969 | if (nxpnd == 0) { |
---|
2970 | sprintf(funcbuf, |
---|
2971 | "\15\12%ld file%s deleted, %ld byte%s freed\15\12", |
---|
2972 | nfiles, |
---|
2973 | (nfiles == 1) ? "" : "s", |
---|
2974 | nbytes, |
---|
2975 | (nbytes == 1) ? "" : "s" |
---|
2976 | ); |
---|
2977 | nxpnd--; |
---|
2978 | funcnxt = 0; |
---|
2979 | funclen = strlen(funcbuf); |
---|
2980 | } else { |
---|
2981 | funcbuf[0] = '\0'; |
---|
2982 | funcnxt = 0; |
---|
2983 | funclen = 0; |
---|
2984 | } |
---|
2985 | |
---|
2986 | /* If we have data to send */ |
---|
2987 | |
---|
2988 | if (funcnxt < funclen) |
---|
2989 | return (funcbuf[funcnxt++]); /* Return a character */ |
---|
2990 | else |
---|
2991 | return(-1); /* No more input */ |
---|
2992 | } |
---|
2993 | |
---|
2994 | /* S N D D E L -- Send delete message */ |
---|
2995 | |
---|
2996 | int |
---|
2997 | #ifdef CK_ANSI |
---|
2998 | snddel(char * spec) |
---|
2999 | #else |
---|
3000 | snddel(spec) char * spec; |
---|
3001 | #endif /* CK_ANSI */ |
---|
3002 | /* snddel */ { |
---|
3003 | #ifndef NOSERVER |
---|
3004 | char * p=NULL, name[257]; |
---|
3005 | |
---|
3006 | if (!*spec) |
---|
3007 | return(0); |
---|
3008 | |
---|
3009 | strcpy(name, spec); |
---|
3010 | |
---|
3011 | #ifdef OS2 |
---|
3012 | /* change / to \. */ |
---|
3013 | p = name; |
---|
3014 | while (*p) { /* Change them back to \ */ |
---|
3015 | if (*p == '/') *p = '\\'; |
---|
3016 | p++; |
---|
3017 | } |
---|
3018 | #endif /* OS2 */ |
---|
3019 | |
---|
3020 | nfiles = nbytes = 0L; |
---|
3021 | sprintf(funcbuf,"Deleting \"%s\"\15\12",name); |
---|
3022 | funcnxt = 0; |
---|
3023 | funclen = strlen(funcbuf); |
---|
3024 | |
---|
3025 | nxpnd = zxpand(name); |
---|
3026 | nfils = 0; /* No files, no lists. */ |
---|
3027 | xflg = 1; /* Flag we must send X packet. */ |
---|
3028 | strcpy(cmdstr,"REMOTE DELETE"); /* Data for X packet. */ |
---|
3029 | first = 1; /* Init getchx lookahead */ |
---|
3030 | funcstr = 1; /* Just set the flag. */ |
---|
3031 | funcptr = nxtdel; /* And the pointer. */ |
---|
3032 | binary = XYFT_T; /* Use text mode for this, */ |
---|
3033 | return(sinit()); |
---|
3034 | #else |
---|
3035 | return(0); |
---|
3036 | #endif /* NOSERVER */ |
---|
3037 | } |
---|
3038 | |
---|
3039 | #ifdef OS2 |
---|
3040 | /* S N D S P A C E -- send disk space message */ |
---|
3041 | int |
---|
3042 | sndspace(int drive) { |
---|
3043 | #ifndef NOSERVER |
---|
3044 | static char spctext[64]; |
---|
3045 | if (drive) |
---|
3046 | sprintf(spctext, |
---|
3047 | " Drive %c: %ldK free\15\12", drive, |
---|
3048 | zdskspace(drive - 'A' + 1) / 1024L); |
---|
3049 | else |
---|
3050 | sprintf(spctext, " Free space: %ldK\15\12", zdskspace(0) / 1024L); |
---|
3051 | nfils = 0; /* No files, no lists. */ |
---|
3052 | xflg = 1; /* Flag we must send X packet. */ |
---|
3053 | strcpy(cmdstr,"free space"); /* Data for X packet. */ |
---|
3054 | first = 1; /* Init getchx lookahead */ |
---|
3055 | memstr = 1; /* Just set the flag. */ |
---|
3056 | memptr = spctext; /* And the pointer. */ |
---|
3057 | binary = XYFT_T; /* Text mode for this. */ |
---|
3058 | return(sinit()); |
---|
3059 | #else |
---|
3060 | return(0); |
---|
3061 | #endif /* NOSERVER */ |
---|
3062 | } |
---|
3063 | |
---|
3064 | /* S N D W H O -- send who message */ |
---|
3065 | int |
---|
3066 | sndwho(char * who) { |
---|
3067 | #ifndef NOSERVER |
---|
3068 | nfils = 0; /* No files, no lists. */ |
---|
3069 | xflg = 1; /* Flag we must send X packet. */ |
---|
3070 | strcpy(cmdstr,"who"); /* Data for X packet. */ |
---|
3071 | first = 1; /* Init getchx lookahead */ |
---|
3072 | memstr = 1; /* Just set the flag. */ |
---|
3073 | #ifdef NT |
---|
3074 | memptr = "\15\12K95 SERVER\15\12"; /* And the pointer. */ |
---|
3075 | #else |
---|
3076 | memptr = "\15\12K/2 SERVER\15\12"; |
---|
3077 | #endif /* NT */ |
---|
3078 | binary = XYFT_T; /* Use text mode */ |
---|
3079 | return(sinit()); |
---|
3080 | #else |
---|
3081 | return(0); |
---|
3082 | #endif /* NOSERVER */ |
---|
3083 | } |
---|
3084 | #endif /* OS2 */ |
---|
3085 | |
---|
3086 | /* C W D -- Change current working directory */ |
---|
3087 | |
---|
3088 | /* |
---|
3089 | String passed has first byte as length of directory name, rest of string |
---|
3090 | is name. Fails if can't connect, else ACKs (with name) and succeeds. |
---|
3091 | */ |
---|
3092 | |
---|
3093 | int |
---|
3094 | cwd(vdir) char *vdir; { |
---|
3095 | char *cdd, *zgtdir(), *dirp; |
---|
3096 | |
---|
3097 | vdir[xunchar(*vdir) + 1] = '\0'; /* Terminate string with a null */ |
---|
3098 | dirp = vdir+1; |
---|
3099 | tlog(F110,"Directory requested: ",dirp,0L); |
---|
3100 | if (zchdir(dirp)) { /* Try to change */ |
---|
3101 | cdd = zgtdir(); /* Get new working directory. */ |
---|
3102 | debug(F110,"cwd",cdd,0); |
---|
3103 | encstr((CHAR *)cdd); |
---|
3104 | #ifdef COMMENT |
---|
3105 | ack1((CHAR *)(encbuf+7)); |
---|
3106 | #else |
---|
3107 | ack1(data); |
---|
3108 | #endif /* COMMENT */ |
---|
3109 | screen(SCR_CD,0,0l,cdd); |
---|
3110 | tlog(F110,"Changed directory to",cdd,0L); |
---|
3111 | return(1); |
---|
3112 | } else { |
---|
3113 | debug(F110,"cwd failed",dirp,0); |
---|
3114 | tlog(F110,"Failed to change directory to",dirp,0L); |
---|
3115 | return(0); |
---|
3116 | } |
---|
3117 | } |
---|
3118 | |
---|
3119 | |
---|
3120 | /* S Y S C M D -- Do a system command */ |
---|
3121 | |
---|
3122 | /* Command string is formed by concatenating the two arguments. */ |
---|
3123 | |
---|
3124 | int |
---|
3125 | syscmd(prefix,suffix) char *prefix, *suffix; { |
---|
3126 | char *cp; |
---|
3127 | |
---|
3128 | if (!prefix) |
---|
3129 | return(0); |
---|
3130 | if (!*prefix) |
---|
3131 | return(0); |
---|
3132 | for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++); |
---|
3133 | while (*cp++ = *suffix++) |
---|
3134 | #ifdef OS2 |
---|
3135 | /* This takes away more than we gain in convenience |
---|
3136 | if (*(cp-1) == '/') *(cp-1) = '\\' */ |
---|
3137 | #endif /* OS2 */ |
---|
3138 | ; /* Copy suffix */ |
---|
3139 | |
---|
3140 | debug(F110,"syscmd",cmdstr,0); |
---|
3141 | |
---|
3142 | if (zxcmd(ZIFILE,cmdstr) > 0) { |
---|
3143 | debug(F110,"syscmd zxcmd ok",cmdstr,0); |
---|
3144 | nfils = sndsrc = 0; /* Flag that input is from stdin */ |
---|
3145 | xflg = hcflg = 1; /* And special flags for pipe */ |
---|
3146 | binary = XYFT_T; /* Go to text mode */ |
---|
3147 | return (sinit()); /* Send S packet */ |
---|
3148 | } else { |
---|
3149 | debug(F100,"syscmd zxcmd failed",cmdstr,0); |
---|
3150 | return(0); |
---|
3151 | } |
---|
3152 | } |
---|
3153 | |
---|
3154 | /* R E M S E T -- Remote Set */ |
---|
3155 | /* Called by server to set variables as commanded in REMOTE SET packets. */ |
---|
3156 | /* Returns 1 on success, 0 on failure. */ |
---|
3157 | |
---|
3158 | int |
---|
3159 | remset(s) char *s; { |
---|
3160 | int len, i, x, y; |
---|
3161 | char *p; |
---|
3162 | |
---|
3163 | len = xunchar(*s++); /* Length of first field */ |
---|
3164 | p = s + len; /* Pointer to second length field */ |
---|
3165 | *p++ = '\0'; /* Zero out second length field */ |
---|
3166 | x = atoi(s); /* Value of first field */ |
---|
3167 | debug(F111,"remset",s,x); |
---|
3168 | debug(F110,"remset",p,0); |
---|
3169 | switch (x) { /* Do the right thing */ |
---|
3170 | case 132: /* Attributes (all, in) */ |
---|
3171 | atcapr = atoi(p); |
---|
3172 | return(1); |
---|
3173 | case 133: /* File length attributes */ |
---|
3174 | case 233: /* IN/OUT combined */ |
---|
3175 | case 148: /* Both kinds of lengths */ |
---|
3176 | case 248: |
---|
3177 | atleni = atleno = atoi(p); |
---|
3178 | return(1); |
---|
3179 | case 134: /* File Type (text/binary) */ |
---|
3180 | case 234: |
---|
3181 | attypi = attypo = atoi(p); |
---|
3182 | return(1); |
---|
3183 | case 135: /* File creation date */ |
---|
3184 | case 235: |
---|
3185 | atdati = atdato = atoi(p); |
---|
3186 | return(1); |
---|
3187 | case 139: /* File Blocksize */ |
---|
3188 | case 239: |
---|
3189 | atblki = atblko = atoi(p); |
---|
3190 | return(1); |
---|
3191 | case 141: /* Encoding / Character Set */ |
---|
3192 | case 241: |
---|
3193 | atenci = atenco = atoi(p); |
---|
3194 | return(1); |
---|
3195 | case 142: /* Disposition */ |
---|
3196 | case 242: |
---|
3197 | atdisi = atdiso = atoi(p); |
---|
3198 | return(1); |
---|
3199 | case 145: /* System ID */ |
---|
3200 | case 245: |
---|
3201 | atsidi = atsido = atoi(p); |
---|
3202 | return(1); |
---|
3203 | case 147: /* System-Dependent Info */ |
---|
3204 | case 247: |
---|
3205 | atsysi = atsyso = atoi(p); |
---|
3206 | return(1); |
---|
3207 | case 232: /* Attributes (all, out) */ |
---|
3208 | atcapr = atoi(p); |
---|
3209 | return(1); |
---|
3210 | case 300: /* File type (text, binary) */ |
---|
3211 | binary = atoi(p); |
---|
3212 | return(1); |
---|
3213 | case 301: /* File name conversion */ |
---|
3214 | fncnv = 1 - atoi(p); /* (oops) */ |
---|
3215 | return(1); |
---|
3216 | case 302: /* File name collision */ |
---|
3217 | x = atoi(p); |
---|
3218 | if (x == XYFX_R) warn = 1; /* Rename */ |
---|
3219 | if (x == XYFX_X) warn = 0; /* Replace */ |
---|
3220 | fncact = x; |
---|
3221 | return(1); |
---|
3222 | case 310: /* Incomplete File Disposition */ |
---|
3223 | keep = atoi(p); /* Keep, Discard */ |
---|
3224 | return(1); |
---|
3225 | case 311: /* Blocksize */ |
---|
3226 | fblksiz = atoi(p); |
---|
3227 | return(1); |
---|
3228 | case 312: /* Record Length */ |
---|
3229 | frecl = atoi(p); |
---|
3230 | return(1); |
---|
3231 | case 313: /* Record format */ |
---|
3232 | frecfm = atoi(p); |
---|
3233 | return(1); |
---|
3234 | case 314: /* File organization */ |
---|
3235 | forg = atoi(p); |
---|
3236 | return(1); |
---|
3237 | case 315: /* File carriage control */ |
---|
3238 | fcctrl = atoi(p); |
---|
3239 | return(1); |
---|
3240 | case 400: /* Block check */ |
---|
3241 | y = atoi(p); |
---|
3242 | if (y < 5 && y > 0) { |
---|
3243 | bctr = y; |
---|
3244 | return(1); |
---|
3245 | } else if (*p == 'B') { |
---|
3246 | bctr = 4; |
---|
3247 | return(1); |
---|
3248 | } |
---|
3249 | return(0); |
---|
3250 | case 401: /* Receive packet-length */ |
---|
3251 | rpsiz = urpsiz = atoi(p); |
---|
3252 | if (urpsiz > MAXRP) urpsiz = MAXRP; /* Max long-packet length */ |
---|
3253 | if (rpsiz > 94) rpsiz = 94; /* Max short-packet length */ |
---|
3254 | urpsiz = adjpkl(urpsiz,wslots,bigrbsiz); |
---|
3255 | return(1); |
---|
3256 | case 402: /* Receive timeout */ |
---|
3257 | y = atoi(p); /* Client is telling us */ |
---|
3258 | if (y > -1 && y < 999) { /* the timeout that it wants */ |
---|
3259 | pkttim = chktimo(y,timef); /* us to tell it to use. */ |
---|
3260 | return(1); |
---|
3261 | } else return(0); |
---|
3262 | case 403: /* Retry limit */ |
---|
3263 | y = atoi(p); |
---|
3264 | if (y > -1 && y < 95) { |
---|
3265 | maxtry = y; |
---|
3266 | return(1); |
---|
3267 | } else return(0); |
---|
3268 | case 404: /* Server timeout */ |
---|
3269 | y = atoi(p); |
---|
3270 | if (y < 0) return(0); |
---|
3271 | srvtim = y; |
---|
3272 | return(1); |
---|
3273 | |
---|
3274 | #ifndef NOCSETS |
---|
3275 | case 405: /* Transfer character set */ |
---|
3276 | for (i = 0; i < ntcsets; i++) { |
---|
3277 | if (!strcmp(tcsinfo[i].designator,p)) break; |
---|
3278 | } |
---|
3279 | debug(F101,"remset xfer charset lookup","",i); |
---|
3280 | if (i == ntcsets) return(0); |
---|
3281 | tcharset = tcsinfo[i].code; /* if known, use it */ |
---|
3282 | if (tcharset == TC_TRANSP) |
---|
3283 | rx = NULL; |
---|
3284 | else |
---|
3285 | rx = xlr[tcharset][fcharset]; /* translation function */ |
---|
3286 | return(1); |
---|
3287 | #endif /* NOCSETS */ |
---|
3288 | |
---|
3289 | case 406: /* Window slots */ |
---|
3290 | y = atoi(p); |
---|
3291 | if (y == 0) y = 1; |
---|
3292 | if (y < 1 && y > MAXWS) return(0); |
---|
3293 | wslotr = y; |
---|
3294 | swcapr = 1; |
---|
3295 | urpsiz = adjpkl(urpsiz,wslots,bigrbsiz); |
---|
3296 | return(1); |
---|
3297 | default: /* Anything else... */ |
---|
3298 | return(0); |
---|
3299 | } |
---|
3300 | } |
---|
3301 | |
---|
3302 | /* Adjust packet length based on number of window slots and buffer size */ |
---|
3303 | |
---|
3304 | int |
---|
3305 | adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; { |
---|
3306 | if (protocol != PROTO_K) return(pktlen); |
---|
3307 | debug(F101,"adjpkl len","",pktlen); |
---|
3308 | debug(F101,"adjpkl slots","",slots); |
---|
3309 | debug(F101,"adjpkl bufsiz","",bufsiz); |
---|
3310 | if (((pktlen + 6) * slots) > bufsiz) |
---|
3311 | pktlen = (bufsiz / slots) - 6; |
---|
3312 | debug(F101,"adjpkl new len","",pktlen); |
---|
3313 | return(pktlen); |
---|
3314 | } |
---|
3315 | |
---|
3316 | /* Set transfer mode and file naming based on comparison of system types */ |
---|
3317 | |
---|
3318 | VOID |
---|
3319 | whoarewe() { |
---|
3320 | extern int xfermode; |
---|
3321 | extern char whoareu[]; |
---|
3322 | int flag = 0; |
---|
3323 | debug(F101,"whoarewe xfermode","",xfermode); |
---|
3324 | if (xfermode == XMODE_A) { /* If TRANSFER MODE AUTOMATIC */ |
---|
3325 | if (whoareu[0]) { /* and we know partner's system type */ |
---|
3326 | char * p = (char *)whoareu; |
---|
3327 | debug(F110,"whoarewe remote sysid",whoareu,0); |
---|
3328 | if (!strcmp(p,cksysid)) /* Other system same as us */ |
---|
3329 | flag = 1; |
---|
3330 | #ifdef UNIX |
---|
3331 | if (!strcmp(p,"L3")) /* UNIX is sort of like AmigaDOS */ |
---|
3332 | flag = 1; /* (same directory separator) */ |
---|
3333 | else if (!strcmp(p,"N3")) /* UNIX like Aegis */ |
---|
3334 | flag = 1; |
---|
3335 | #else |
---|
3336 | #ifdef AMIGA |
---|
3337 | /* Like UNIX, but case distinctions are ignored and can begin with device:. */ |
---|
3338 | else if (!strcmp(p,"U1")) /* Amiga is sort of like UNIX */ |
---|
3339 | flag = 1; |
---|
3340 | else if (!strcmp(p,"N3")) /* Amiga is sort of like Aegis */ |
---|
3341 | flag = 1; |
---|
3342 | #else |
---|
3343 | #ifdef OS2 /* (Includes Windows 95/NT) */ |
---|
3344 | |
---|
3345 | /* DOS, GEMDOS, Windows 3.x, Windows 95, Windows NT */ |
---|
3346 | /* All "the same" for FAT partitions but all bets off otherwise */ |
---|
3347 | /* so this part needs some refinement ... */ |
---|
3348 | |
---|
3349 | else if (!strcmp(p,"U8")) /* MS-DOS */ |
---|
3350 | flag = 1; |
---|
3351 | else if (!strcmp(p,"UO")) /* OS/2 */ |
---|
3352 | flag = 1; |
---|
3353 | else if (!strcmp(p,"UN")) /* Windows NT or 95 */ |
---|
3354 | flag = 1; |
---|
3355 | else if (!strcmp(p,"K2")) /* GEMDOS */ |
---|
3356 | flag = 1; |
---|
3357 | #else |
---|
3358 | #ifdef GEMDOS |
---|
3359 | else if (!strcmp(p,"U8")) |
---|
3360 | flag = 1; |
---|
3361 | else if (!strcmp(p,"UO")) |
---|
3362 | flag = 1; |
---|
3363 | else if (!strcmp(p,"UN")) |
---|
3364 | flag = 1; |
---|
3365 | else if (!strcmp(p,"K2")) |
---|
3366 | flag = 1; |
---|
3367 | #endif /* GEMDOS */ |
---|
3368 | #endif /* OS2 */ |
---|
3369 | #endif /* AMIGA */ |
---|
3370 | #endif /* UNIX */ |
---|
3371 | |
---|
3372 | debug(F101,"whoarewe flag","",flag); |
---|
3373 | if (flag) { /* We have a match */ |
---|
3374 | fncnv = XYFN_L; /* so literal filenames */ |
---|
3375 | #ifdef VMS |
---|
3376 | binary = XYFT_L; /* For VMS-to-VMS, use labeled */ |
---|
3377 | #else |
---|
3378 | #ifdef OS2 |
---|
3379 | if (!strcmp(cksysid,"UO") && !strcmp((char *)whoareu,"UO")) |
---|
3380 | binary = XYFT_L; /* For OS/2-to-OS/2, use labeled */ |
---|
3381 | #else |
---|
3382 | binary = XYFT_B; /* For all others use binary */ |
---|
3383 | #endif /* OS2 */ |
---|
3384 | #endif /* VMS */ |
---|
3385 | } |
---|
3386 | } |
---|
3387 | } |
---|
3388 | } |
---|