1 | /* C K C F N 3 -- Packet buffer management for C-Kermit */ |
---|
2 | |
---|
3 | /* (plus assorted functions tacked on at the end) */ |
---|
4 | |
---|
5 | /* |
---|
6 | Author: Frank da Cruz <fdc@columbia.edu>, |
---|
7 | Columbia University Academic Information Systems, New York City. |
---|
8 | |
---|
9 | Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New |
---|
10 | York. The C-Kermit software may not be, in whole or in part, licensed or |
---|
11 | sold for profit as a software product itself, nor may it be included in or |
---|
12 | distributed with commercial products or otherwise distributed by commercial |
---|
13 | concerns to their clients or customers without written permission of the |
---|
14 | Office of Kermit Development and Distribution, Columbia University. This |
---|
15 | copyright notice must not be removed, altered, or obscured. |
---|
16 | */ |
---|
17 | |
---|
18 | #include "ckcsym.h" |
---|
19 | #include "ckcdeb.h" |
---|
20 | #include "ckcasc.h" |
---|
21 | #include "ckcker.h" |
---|
22 | #include "ckcxla.h" |
---|
23 | |
---|
24 | #ifndef NODISPO |
---|
25 | #ifdef pdp11 |
---|
26 | #define NODISPO |
---|
27 | #endif /* pdpd11 */ |
---|
28 | #endif /* NODISPO */ |
---|
29 | |
---|
30 | extern int unkcs, wmax, wcur, discard, bctu, bctl, local, fdispla, what, |
---|
31 | sendmode, opnerr, dest; |
---|
32 | extern long sendstart; |
---|
33 | |
---|
34 | extern char * ofn2; |
---|
35 | extern char ofn1[]; |
---|
36 | extern int ofn1x; |
---|
37 | |
---|
38 | extern int xflg, remfile, remappd; |
---|
39 | extern CHAR *data; |
---|
40 | extern char filnam[]; |
---|
41 | #ifndef NOFRILLS |
---|
42 | extern int rprintf, rmailf; /* REMOTE MAIL, PRINT */ |
---|
43 | extern char * printfile; |
---|
44 | extern int printpipe; |
---|
45 | char optbuf[100]; /* Options for MAIL or REMOTE PRINT */ |
---|
46 | #endif /* NOFRILLS */ |
---|
47 | extern int wslots; |
---|
48 | extern int fblksiz, frecl, forg, frecfm, fncact, fncsav, fcctrl, lf_opts; |
---|
49 | #ifdef pdp11 |
---|
50 | extern CHAR srvcmd[]; |
---|
51 | extern char tmpbuf[]; |
---|
52 | CHAR *pktmsg = (CHAR *) tmpbuf; |
---|
53 | #else |
---|
54 | #ifdef DYNAMIC |
---|
55 | extern CHAR *srvcmd; |
---|
56 | extern CHAR *pktmsg; |
---|
57 | #else |
---|
58 | extern CHAR srvcmd[]; |
---|
59 | extern CHAR pktmsg[]; |
---|
60 | #endif /* DYNAMIC */ |
---|
61 | #endif /* pdp11 */ |
---|
62 | |
---|
63 | extern int binary, spsiz; |
---|
64 | extern int pktnum, cxseen, czseen, nfils, stdinf; |
---|
65 | extern int memstr, stdouf, keep, sndsrc, hcflg; |
---|
66 | extern int server, en_cwd, en_mai, en_pri; |
---|
67 | |
---|
68 | extern int |
---|
69 | atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko, |
---|
70 | attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; |
---|
71 | |
---|
72 | #ifdef STRATUS |
---|
73 | extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto; |
---|
74 | #endif /* STRATUS */ |
---|
75 | |
---|
76 | #ifdef datageneral |
---|
77 | extern int quiet; |
---|
78 | #endif /* datageneral */ |
---|
79 | |
---|
80 | extern long fsize, filcnt, ffc, tfc; |
---|
81 | |
---|
82 | #ifndef NOCSETS |
---|
83 | extern int tcharset, fcharset; |
---|
84 | extern int ntcsets; |
---|
85 | extern struct csinfo tcsinfo[], fcsinfo[]; |
---|
86 | |
---|
87 | /* Pointers to translation functions */ |
---|
88 | #ifdef CK_ANSIC |
---|
89 | extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */ |
---|
90 | extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */ |
---|
91 | extern CHAR (*rx)(CHAR); /* Pointer to input character translation function */ |
---|
92 | extern CHAR (*sx)(CHAR); /* Pointer to output character translation function */ |
---|
93 | #else |
---|
94 | extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */ |
---|
95 | extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */ |
---|
96 | extern CHAR (*rx)(); /* Pointer to input character translation function */ |
---|
97 | extern CHAR (*sx)(); /* Pointer to output character translation function */ |
---|
98 | #endif /* CK_ANSIC */ |
---|
99 | #endif /* NOCSETS */ |
---|
100 | |
---|
101 | /* Variables global to Kermit that are defined in this module */ |
---|
102 | |
---|
103 | int winlo; /* packet number at low window edge */ |
---|
104 | |
---|
105 | int sbufnum; /* number of free buffers */ |
---|
106 | int dum001 = 1234; /* protection... */ |
---|
107 | int sbufuse[MAXWS]; /* buffer in-use flag */ |
---|
108 | int dum003 = 1111; |
---|
109 | int rbufnum; /* number of free buffers */ |
---|
110 | int dum002 = 4321; /* more protection */ |
---|
111 | int rbufuse[MAXWS]; /* buffer in-use flag */ |
---|
112 | int sseqtbl[64]; /* sequence # to buffer # table */ |
---|
113 | int rseqtbl[64]; /* sequence # to buffer # table */ |
---|
114 | int sacktbl[64]; /* sequence # ack table */ |
---|
115 | |
---|
116 | #ifdef DYNAMIC |
---|
117 | struct pktinfo *s_pkt = NULL; /* array of pktinfo structures */ |
---|
118 | struct pktinfo *r_pkt = NULL; /* array of pktinfo structures */ |
---|
119 | #else |
---|
120 | struct pktinfo s_pkt[MAXWS]; /* array of pktinfo structures */ |
---|
121 | struct pktinfo r_pkt[MAXWS]; /* array of pktinfo structures */ |
---|
122 | #endif /* DYNAMIC */ |
---|
123 | |
---|
124 | #ifdef DEBUG |
---|
125 | char xbuf[200]; /* For debug logging */ |
---|
126 | #endif /* DEBUG */ |
---|
127 | |
---|
128 | #ifdef DYNAMIC |
---|
129 | CHAR *bigsbuf = NULL, *bigrbuf = NULL; |
---|
130 | #else |
---|
131 | char bigsbt[8]; /* Protection (shouldn't need this). */ |
---|
132 | /* BUT DON'T REMOVE IT! */ |
---|
133 | CHAR bigsbuf[SBSIZ + 5]; /* Send-packet buffer area */ |
---|
134 | char bigrbt[8]; /* Safety padding */ |
---|
135 | CHAR bigrbuf[RBSIZ + 5]; /* Receive-packet area */ |
---|
136 | #endif |
---|
137 | int bigsbsiz = SBSIZ; /* Sizes of big send & rcv buffers. */ |
---|
138 | int bigrbsiz = RBSIZ; |
---|
139 | |
---|
140 | #ifdef VMS |
---|
141 | int zchkpath(char *s); |
---|
142 | #endif /* VMS */ |
---|
143 | |
---|
144 | /* FUNCTIONS */ |
---|
145 | |
---|
146 | /* For sanity, use "i" for buffer slots, "n" for packet numbers. */ |
---|
147 | |
---|
148 | /* I N I B U F S */ |
---|
149 | |
---|
150 | /* |
---|
151 | Allocates the big send and receive buffers. |
---|
152 | Call with size for big send buffer (s) and receive buffer (r). |
---|
153 | These sizes can be different. |
---|
154 | Attempts to allocate buffers of the requested size, but if it can't, |
---|
155 | it will allocate smaller ones. |
---|
156 | Sets global variables bigsbsiz and bigrbsiz to the actual sizes, |
---|
157 | and bigsbuf and bigrbuf pointing to the actual buffers. |
---|
158 | Designed to be called more than once. |
---|
159 | Returns 0 on success, -1 on failure. |
---|
160 | */ |
---|
161 | |
---|
162 | CHAR *bigbufp = NULL; |
---|
163 | |
---|
164 | int |
---|
165 | inibufs(s,r) int s, r; { |
---|
166 | #ifdef DYNAMIC |
---|
167 | unsigned |
---|
168 | int size; |
---|
169 | #ifdef OS2 |
---|
170 | unsigned /* Don't you wish everybody had unsigned long... */ |
---|
171 | #endif /* OS2 */ |
---|
172 | long z; |
---|
173 | int x; |
---|
174 | |
---|
175 | debug(F101,"inibufs s","",s); |
---|
176 | debug(F101,"inibufs r","",r); |
---|
177 | |
---|
178 | if (s < 80 || r < 80) return(-1); /* Validate arguments. */ |
---|
179 | |
---|
180 | if (!s_pkt) { /* Allocate packet info structures */ |
---|
181 | if (!(s_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS))) |
---|
182 | fatal("ini_pkts: no memory for s_pkt"); |
---|
183 | } |
---|
184 | for (x = 0; x < MAXWS; x++) |
---|
185 | s_pkt[x].pk_adr = NULL; /* Initialize addresses */ |
---|
186 | |
---|
187 | if (!r_pkt) { |
---|
188 | if (!(r_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS))) |
---|
189 | fatal("ini_pkts: no memory for s_pkt"); |
---|
190 | } |
---|
191 | for (x = 0; x < MAXWS; x++) |
---|
192 | r_pkt[x].pk_adr = NULL; /* Initialize addresses */ |
---|
193 | |
---|
194 | if (!srvcmd) { /* Allocate srvcmd buffer */ |
---|
195 | srvcmd = (CHAR *) malloc(r + 100); |
---|
196 | if (!srvcmd) return(-1); |
---|
197 | *srvcmd = NUL; |
---|
198 | } |
---|
199 | if (!pktmsg) { /* Allocate pktmsg buffer */ |
---|
200 | pktmsg = (CHAR *) malloc(81); |
---|
201 | if (!pktmsg) return(-1); |
---|
202 | *pktmsg = NUL; |
---|
203 | } |
---|
204 | |
---|
205 | if (bigbufp) { /* Free previous buffers, if any. */ |
---|
206 | free(bigbufp); |
---|
207 | bigbufp = NULL; |
---|
208 | } |
---|
209 | size = s + r + 40; /* Combined requested size + padding */ |
---|
210 | z = (unsigned) s + (unsigned) r + 40; |
---|
211 | debug(F101,"inibufs size 1","",size); |
---|
212 | debug(F101,"inibufs size z","",z); |
---|
213 | if ((long) size != z) { |
---|
214 | debug(F100,"inibufs overflow","",0); |
---|
215 | size = 65535; |
---|
216 | } |
---|
217 | |
---|
218 | /* Try to get the space. If malloc fails, try to get a little less. */ |
---|
219 | /* (Obviously, this algorithm can be refined.) */ |
---|
220 | |
---|
221 | while (!(bigbufp = (CHAR *) malloc(size))) { |
---|
222 | debug(F101,"inibufs bigbuf malloc failed","",size); |
---|
223 | size = (size * 2) / 3; /* Failed, cut size by 1/3. */ |
---|
224 | if (size < 200) /* Try again until too small. */ |
---|
225 | return(-1); |
---|
226 | } |
---|
227 | debug(F101,"inibufs size 2","",size); /* OK, we got some space. */ |
---|
228 | |
---|
229 | /* |
---|
230 | Now divide the allocated space between the send and receive buffers in the |
---|
231 | requested proportion. The natural formula would be (s / (s + r)) * size |
---|
232 | (for the send buffer), but that doesn't work with integer arithmetic and we |
---|
233 | can't use floating point because some machines don't have it. This can be |
---|
234 | rearranged as (s * size) / (s + r). But (s * size) can be VERY large, too |
---|
235 | large for 32 bits. So let's do it this way. This arithmetic works for |
---|
236 | buffer sizes up to about 5,000,000. |
---|
237 | */ |
---|
238 | #define FACTOR 20L |
---|
239 | z = ( (long) s * FACTOR ) / ( (long) s + (long) r ); |
---|
240 | x = ( z * ( (long) size / FACTOR ) ); |
---|
241 | if (x < 0) return(-1); /* Catch overflow */ |
---|
242 | |
---|
243 | bigsbsiz = x - 5; /* Size of send buffer */ |
---|
244 | bigsbuf = bigbufp; /* Address of send buffer */ |
---|
245 | debug(F101,"inibufs bigsbsiz","",bigsbsiz); |
---|
246 | |
---|
247 | bigrbsiz = size - x - 5; /* Size of receive buffer */ |
---|
248 | bigrbuf = bigbufp + x; /* Addresss of receive buffer */ |
---|
249 | debug(F101,"inibufs bigrbsiz","",bigrbsiz); |
---|
250 | |
---|
251 | return(0); /* Success */ |
---|
252 | #else /* No dynamic allocation */ |
---|
253 | bigsbsiz = SBSIZ; /* Just use the symbols */ |
---|
254 | bigrbsiz = RBSIZ; /* ... */ |
---|
255 | return(0); /* Success. */ |
---|
256 | #endif /* DYNAMIC */ |
---|
257 | } |
---|
258 | |
---|
259 | |
---|
260 | /* M A K E B U F -- Makes and clears a new buffers. */ |
---|
261 | |
---|
262 | /* Call with: */ |
---|
263 | /* slots: number of buffer slots to make, 1 to 32 */ |
---|
264 | /* bufsiz: size of the big buffer */ |
---|
265 | /* buf: address of the big buffer */ |
---|
266 | /* xx: pointer to array of pktinfo structures for these buffers */ |
---|
267 | |
---|
268 | /* Subdivides the big buffer into "slots" buffers. */ |
---|
269 | |
---|
270 | /* Returns: */ |
---|
271 | /* -1 if too many or too few slots requested, */ |
---|
272 | /* -2 if slots would be too small. */ |
---|
273 | /* n (positive) on success = size of one buffer. */ |
---|
274 | /* with pktinfo structure initialized for this set of buffers. */ |
---|
275 | |
---|
276 | int |
---|
277 | makebuf(slots,bufsiz,buf,xx) |
---|
278 | /* makebuf */ int slots, bufsiz; CHAR buf[]; struct pktinfo *xx; { |
---|
279 | |
---|
280 | CHAR *a; |
---|
281 | int i, size; |
---|
282 | |
---|
283 | debug(F101,"makebuf","",slots); |
---|
284 | debug(F101,"makebuf bufsiz","",bufsiz); |
---|
285 | debug(F101,"makebuf MAXWS","",MAXWS); |
---|
286 | |
---|
287 | if (slots > MAXWS || slots < 1) return(-1); |
---|
288 | if (bufsiz < slots * 10 ) return(-2); |
---|
289 | |
---|
290 | size = bufsiz / slots; /* Divide up the big buffer. */ |
---|
291 | a = buf; /* Address of first piece. */ |
---|
292 | |
---|
293 | for (i = 0; i < slots; i++) { |
---|
294 | struct pktinfo *x = &xx[i]; |
---|
295 | x->bf_adr = a; /* Address of this buffer */ |
---|
296 | x->bf_len = size; /* Length of this buffer */ |
---|
297 | x->pk_len = 0; /* Length of data field */ |
---|
298 | x->pk_typ = ' '; /* packet type */ |
---|
299 | x->pk_seq = -1; /* packet sequence number */ |
---|
300 | x->pk_rtr = 0; /* retransmissions */ |
---|
301 | *a = '\0'; /* Clear the buffer */ |
---|
302 | a += size; /* Position to next buffer slot */ |
---|
303 | } |
---|
304 | return(size); |
---|
305 | } |
---|
306 | |
---|
307 | /* M A K S B U F -- Makes the send-packet buffer */ |
---|
308 | |
---|
309 | int |
---|
310 | mksbuf(slots) int slots; { |
---|
311 | int i, x; |
---|
312 | sbufnum = 0; |
---|
313 | if ((x = makebuf(slots,bigsbsiz,bigsbuf,s_pkt)) < 0) { |
---|
314 | debug(F101,"mksbuf makebuf return","",x); |
---|
315 | return(x); |
---|
316 | } |
---|
317 | debug(F101,"mksbuf makebuf return","",x); |
---|
318 | for (i = 0; i < 64; i++) { /* Initialize sequence-number- */ |
---|
319 | sseqtbl[i] = -1; /* to-buffer-number table. */ |
---|
320 | sacktbl[i] = 0; |
---|
321 | } |
---|
322 | for (i = 0; i < MAXWS; i++) |
---|
323 | sbufuse[i] = 0; /* Mark each buffer as free */ |
---|
324 | sbufnum = slots; |
---|
325 | wcur = 0; |
---|
326 | return(x); |
---|
327 | } |
---|
328 | |
---|
329 | /* M A K R B U F -- Makes the receive-packet buffer */ |
---|
330 | |
---|
331 | int |
---|
332 | mkrbuf(slots) int slots; { |
---|
333 | int i, x; |
---|
334 | rbufnum = 0; |
---|
335 | if ((x = makebuf(slots,bigrbsiz,bigrbuf,r_pkt)) < 0) { |
---|
336 | debug(F101,"mkrbuf makebuf return","",x); |
---|
337 | return(x); |
---|
338 | } |
---|
339 | debug(F101,"mkrbuf makebuf return","",x); |
---|
340 | for (i = 0; i < 64; i++) { /* Initialize sequence-number- */ |
---|
341 | rseqtbl[i] = -1; /* to-buffer-number table. */ |
---|
342 | } |
---|
343 | for (i = 0; i < MAXWS; i++) |
---|
344 | rbufuse[i] = 0; /* Mark each buffer as free */ |
---|
345 | rbufnum = slots; |
---|
346 | wcur = 0; |
---|
347 | return(x); |
---|
348 | } |
---|
349 | |
---|
350 | /* W I N D O W -- Resize the window to n */ |
---|
351 | |
---|
352 | int |
---|
353 | window(n) int n; { |
---|
354 | debug(F101,"window","",n); |
---|
355 | if (n < 1 || n > MAXWS) return(-1); |
---|
356 | if (mksbuf(n) < 0) return(-1); |
---|
357 | if (mkrbuf(n) < 0) return(-1); |
---|
358 | wslots = n; |
---|
359 | #ifdef DEBUG |
---|
360 | if (deblog) dumpsbuf(); |
---|
361 | if (deblog) dumprbuf(); |
---|
362 | #endif /* DEBUG */ |
---|
363 | return(0); |
---|
364 | } |
---|
365 | |
---|
366 | /* G E T S B U F -- Allocate a send-buffer. */ |
---|
367 | |
---|
368 | /* Call with packet sequence number to allocate buffer for. */ |
---|
369 | /* Returns: */ |
---|
370 | /* -4 if argument is invalid (negative, or greater than 63) */ |
---|
371 | /* -3 if buffers were thought to be available but really weren't (bug!) */ |
---|
372 | /* -2 if the number of free buffers is negative (bug!) */ |
---|
373 | /* -1 if no free buffers. */ |
---|
374 | /* 0 or positive, packet sequence number, with buffer allocated for it. */ |
---|
375 | |
---|
376 | int |
---|
377 | getsbuf(n) int n; { /* Allocate a send-buffer */ |
---|
378 | int i; |
---|
379 | if (n < 0 || n > 63) { |
---|
380 | debug(F101,"getsbuf bad arg","",n); |
---|
381 | return(-4); /* Bad argument */ |
---|
382 | } |
---|
383 | debug(F101,"getsbuf, packet","",n); |
---|
384 | debug(F101,"getsbuf, sbufnum","",sbufnum); |
---|
385 | if (sbufnum == 0) return(-1); /* No free buffers. */ |
---|
386 | if (sbufnum < 0) return(-2); /* Shouldn't happen. */ |
---|
387 | for (i = 0; i < wslots; i++) /* Find the first one not in use. */ |
---|
388 | if (sbufuse[i] == 0) { /* Got one? */ |
---|
389 | sbufuse[i] = 1; /* Mark it as in use. */ |
---|
390 | sbufnum--; /* One less free buffer. */ |
---|
391 | *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */ |
---|
392 | s_pkt[i].pk_seq = n; /* Put in the sequence number */ |
---|
393 | sseqtbl[n] = i; /* Back pointer from sequence number */ |
---|
394 | sacktbl[n] = 0; /* ACK flag */ |
---|
395 | s_pkt[i].pk_len = 0; /* Data field length now zero. */ |
---|
396 | s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */ |
---|
397 | s_pkt[i].pk_rtr = 0; /* Zero the retransmission count */ |
---|
398 | data = s_pkt[i].bf_adr + 7; /* Set global "data" address. */ |
---|
399 | if ((what & (W_SEND|W_REMO)) && (++wcur > wmax)) |
---|
400 | wmax = wcur; /* For statistics. */ |
---|
401 | return(n); /* Return its index. */ |
---|
402 | } |
---|
403 | sbufnum = 0; /* Didn't find one. */ |
---|
404 | return(-3); /* Shouldn't happen! */ |
---|
405 | } |
---|
406 | |
---|
407 | int |
---|
408 | getrbuf() { /* Allocate a receive buffer */ |
---|
409 | int i; |
---|
410 | debug(F101,"getrbuf rbufnum","",rbufnum); |
---|
411 | debug(F101,"getrbuf wslots","",wslots); |
---|
412 | debug(F101,"getrbuf dum002","",dum002); |
---|
413 | debug(F101,"getrbuf dum003","",dum003); |
---|
414 | if (rbufnum == 0) return(-1); /* No free buffers. */ |
---|
415 | if (rbufnum < 0) return(-2); /* Shouldn't happen. */ |
---|
416 | for (i = 0; i < wslots; i++) /* Find the first one not in use. */ |
---|
417 | if (rbufuse[i] == 0) { /* Got one? */ |
---|
418 | rbufuse[i] = 1; /* Mark it as in use. */ |
---|
419 | *r_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */ |
---|
420 | rbufnum--; /* One less free buffer. */ |
---|
421 | debug(F101,"getrbuf new rbufnum","",rbufnum); |
---|
422 | if ((what & W_RECV) && (++wcur > wmax)) |
---|
423 | wmax = wcur; /* For statistics. */ |
---|
424 | return(i); /* Return its index. */ |
---|
425 | } |
---|
426 | debug(F101,"getrbuf foulup","",i); |
---|
427 | rbufnum = 0; /* Didn't find one. */ |
---|
428 | return(-3); /* Shouldn't happen! */ |
---|
429 | } |
---|
430 | |
---|
431 | /* F R E E S B U F -- Free send-buffer for given packet sequence number */ |
---|
432 | |
---|
433 | /* Returns: */ |
---|
434 | /* 1 upon success */ |
---|
435 | /* -1 if specified buffer does not exist */ |
---|
436 | |
---|
437 | int |
---|
438 | freesbuf(n) int n; { /* Release send-buffer for packet n. */ |
---|
439 | int i; |
---|
440 | |
---|
441 | debug(F101,"freesbuf","",n); |
---|
442 | if (n < 0 || n > 63) /* No such packet. */ |
---|
443 | return(-1); |
---|
444 | i = sseqtbl[n]; /* Get the window slot number. */ |
---|
445 | if (i > -1 && i <= wslots) { |
---|
446 | sseqtbl[n] = -1; /* If valid, remove from seqtbl */ |
---|
447 | sbufnum++; /* and count one more free buffer */ |
---|
448 | sbufuse[i] = 0; /* and mark it as free, */ |
---|
449 | if (what & (W_SEND|W_REMO)) /* decrement active slots */ |
---|
450 | wcur--; /* for statistics and display. */ |
---|
451 | } else { |
---|
452 | debug(F101," sseqtbl[n]","",sseqtbl[n]); |
---|
453 | return(-1); |
---|
454 | } |
---|
455 | |
---|
456 | /* The following is done only so dumped buffers will look right. */ |
---|
457 | |
---|
458 | if (1) { |
---|
459 | *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */ |
---|
460 | s_pkt[i].pk_seq = -1; /* Invalidate the sequence number */ |
---|
461 | s_pkt[i].pk_len = 0; /* Data field length now zero. */ |
---|
462 | s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */ |
---|
463 | s_pkt[i].pk_rtr = 0; /* And the retries field. */ |
---|
464 | } |
---|
465 | return(1); |
---|
466 | } |
---|
467 | |
---|
468 | int |
---|
469 | freerbuf(i) int i; { /* Release receive-buffer slot "i". */ |
---|
470 | int n; |
---|
471 | |
---|
472 | /* NOTE !! Currently, this function frees the indicated buffer, but */ |
---|
473 | /* does NOT erase the data. The program counts on this. Will find a */ |
---|
474 | /* better way later.... */ |
---|
475 | |
---|
476 | debug(F101,"freerbuf, slot","",i); |
---|
477 | if (i < 0 || i >= wslots) { /* No such slot. */ |
---|
478 | debug(F101,"freerbuf no such slot","",i); |
---|
479 | return(-1); |
---|
480 | } |
---|
481 | n = r_pkt[i].pk_seq; /* Get the packet sequence number */ |
---|
482 | debug(F101,"freerbuf, packet","",n); |
---|
483 | if (n > -1 && n < 64) /* If valid, remove from seqtbl */ |
---|
484 | rseqtbl[n] = -1; |
---|
485 | if (rbufuse[i] != 0) { /* If really allocated, */ |
---|
486 | rbufuse[i] = 0; /* mark it as free, */ |
---|
487 | rbufnum++; /* and count one more free buffer. */ |
---|
488 | if (what & W_RECV) /* Keep track of current slots */ |
---|
489 | wcur--; /* for statistics and display */ |
---|
490 | debug(F101,"freerbuf, new rbufnum","",rbufnum); |
---|
491 | } |
---|
492 | |
---|
493 | /* The following is done only so dumped buffers will look right. */ |
---|
494 | |
---|
495 | if (1) { |
---|
496 | /* *r_pkt[i].bf_adr = '\0'; */ /* Zero the buffer data field */ |
---|
497 | r_pkt[i].pk_seq = -1; /* And from packet list */ |
---|
498 | r_pkt[i].pk_len = 0; /* Data field length now zero. */ |
---|
499 | r_pkt[i].pk_typ = ' '; /* Blank the packet type too. */ |
---|
500 | r_pkt[i].pk_rtr = 0; /* And the retries field. */ |
---|
501 | } |
---|
502 | return(1); |
---|
503 | } |
---|
504 | |
---|
505 | /* This is like freerbuf, except it's called with a packet sequence number */ |
---|
506 | /* rather than a packet buffer index. */ |
---|
507 | |
---|
508 | VOID |
---|
509 | freerpkt(seq) int seq; { |
---|
510 | int k; |
---|
511 | debug(F101,"freerpkt seq","",seq); |
---|
512 | k = rseqtbl[seq]; |
---|
513 | debug(F101,"freerpkt k","",k); |
---|
514 | if (k > -1) { |
---|
515 | k = freerbuf(k); |
---|
516 | debug(F101,"freerpkt freerbuf","",k); |
---|
517 | } |
---|
518 | } |
---|
519 | |
---|
520 | |
---|
521 | /* C H K W I N -- Check if packet n is in window. */ |
---|
522 | |
---|
523 | /* Returns: */ |
---|
524 | /* 0 if it is in the current window, */ |
---|
525 | /* +1 if it would have been in previous window (e.g. if ack was lost), */ |
---|
526 | /* -1 if it is outside any window (protocol error), */ |
---|
527 | /* -2 if either of the argument packet numbers is out of range. */ |
---|
528 | |
---|
529 | /* Call with packet number to check (n), lowest packet number in window */ |
---|
530 | /* (bottom), and number of slots in window (slots). */ |
---|
531 | |
---|
532 | int |
---|
533 | chkwin(n,bottom,slots) int n, bottom, slots; { |
---|
534 | int top, prev; |
---|
535 | |
---|
536 | debug(F101,"chkwin packet","",n); |
---|
537 | debug(F101,"chkwin winlo","",bottom); |
---|
538 | debug(F101,"chkwin slots","",slots); |
---|
539 | |
---|
540 | /* First do the easy and common cases, where the windows are not split. */ |
---|
541 | |
---|
542 | if (n < 0 || n > 63 || bottom < 0 || bottom > 63) |
---|
543 | return(-2); |
---|
544 | |
---|
545 | if (n == bottom) return(0); /* In a perfect world... */ |
---|
546 | |
---|
547 | top = bottom + slots; /* Calculate window top. */ |
---|
548 | if (top < 64 && n < top && n >= bottom) |
---|
549 | return(0); /* In current window. */ |
---|
550 | |
---|
551 | prev = bottom - slots; /* Bottom of previous window. */ |
---|
552 | if (prev > -1 && n < bottom && n > prev) |
---|
553 | return(1); /* In previous. */ |
---|
554 | |
---|
555 | /* Now consider the case where the current window is split. */ |
---|
556 | |
---|
557 | if (top > 63) { /* Wraparound... */ |
---|
558 | top -= 64; /* Get modulo-64 sequence number */ |
---|
559 | if (n < top || n >= bottom) { |
---|
560 | return(0); /* In current window. */ |
---|
561 | } else { /* Not in current window. */ |
---|
562 | if (n < bottom && n >= prev) /* Previous window can't be split. */ |
---|
563 | return(1); /* In previous window. */ |
---|
564 | else |
---|
565 | return(-1); /* Not in previous window. */ |
---|
566 | } |
---|
567 | } |
---|
568 | |
---|
569 | /* Now the case where current window not split, but previous window is. */ |
---|
570 | |
---|
571 | if (prev < 0) { /* Is previous window split? */ |
---|
572 | prev += 64; /* Yes. */ |
---|
573 | if (n < bottom || n >= prev) |
---|
574 | return(1); /* In previous window. */ |
---|
575 | } else { /* Previous window not split. */ |
---|
576 | if (n < bottom && n >= prev) |
---|
577 | return(1); /* In previous window. */ |
---|
578 | } |
---|
579 | |
---|
580 | /* It's not in the current window, and not in the previous window... */ |
---|
581 | |
---|
582 | return(-1); /* So it's not in any window. */ |
---|
583 | } |
---|
584 | |
---|
585 | int |
---|
586 | dumpsbuf() { /* Dump send-buffers */ |
---|
587 | #ifdef DEBUG |
---|
588 | int j, x; /* to debug log. */ |
---|
589 | |
---|
590 | if (! deblog) return(0); |
---|
591 | x = zsoutl(ZDFILE,"SEND BUFFERS:"); |
---|
592 | if (x < 0) { |
---|
593 | deblog = 0; |
---|
594 | return(0); |
---|
595 | } |
---|
596 | x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries"); |
---|
597 | if (x < 0) { |
---|
598 | deblog = 0; |
---|
599 | return(0); |
---|
600 | } |
---|
601 | for ( j = 0; j < wslots; j++ ) { |
---|
602 | sprintf(xbuf, |
---|
603 | "%4d%6d%10d%5d%6d%4c%5d%6d\n", |
---|
604 | j, |
---|
605 | sbufuse[j], |
---|
606 | s_pkt[j].bf_adr, |
---|
607 | s_pkt[j].bf_len, |
---|
608 | s_pkt[j].pk_len, |
---|
609 | s_pkt[j].pk_typ, |
---|
610 | s_pkt[j].pk_seq, |
---|
611 | s_pkt[j].pk_rtr |
---|
612 | ); |
---|
613 | if (zsout(ZDFILE,xbuf) < 0) { |
---|
614 | deblog = 0; |
---|
615 | return(0); |
---|
616 | } |
---|
617 | if (s_pkt[j].pk_adr) { |
---|
618 | x = (int)strlen((char *) s_pkt[j].pk_adr); |
---|
619 | if (x) |
---|
620 | sprintf(xbuf,"[%.72s%s]\n",s_pkt[j].pk_adr, x > 72 ? "..." : ""); |
---|
621 | else |
---|
622 | sprintf(xbuf,"[(empty string)]\n"); |
---|
623 | } else { |
---|
624 | sprintf(xbuf,"[(null pointer)]\n"); |
---|
625 | } |
---|
626 | if (zsout(ZDFILE,xbuf) < 0) { |
---|
627 | deblog = 0; |
---|
628 | return(0); |
---|
629 | } |
---|
630 | } |
---|
631 | sprintf(xbuf,"free: %d, winlo: %d\n", sbufnum, winlo); |
---|
632 | if (zsout(ZDFILE,xbuf) < 0) { |
---|
633 | deblog = 0; |
---|
634 | return(0); |
---|
635 | } |
---|
636 | #endif /* DEBUG */ |
---|
637 | return(0); |
---|
638 | } |
---|
639 | int |
---|
640 | dumprbuf() { /* Dump receive-buffers */ |
---|
641 | #ifdef DEBUG |
---|
642 | int j, x; |
---|
643 | if (! deblog) return(0); |
---|
644 | if (zsoutl(ZDFILE,"RECEIVE BUFFERS:") < 0) { |
---|
645 | deblog = 0; |
---|
646 | return(0); |
---|
647 | } |
---|
648 | x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries"); |
---|
649 | if (x < 0) { |
---|
650 | deblog = 0; |
---|
651 | return(0); |
---|
652 | } |
---|
653 | for ( j = 0; j < wslots; j++ ) { |
---|
654 | sprintf(xbuf, |
---|
655 | "%4d%6d%10d%5d%6d%4c%5d%6d\n", |
---|
656 | j, |
---|
657 | rbufuse[j], |
---|
658 | r_pkt[j].bf_adr, |
---|
659 | r_pkt[j].bf_len, |
---|
660 | r_pkt[j].pk_len, |
---|
661 | r_pkt[j].pk_typ, |
---|
662 | r_pkt[j].pk_seq, |
---|
663 | r_pkt[j].pk_rtr |
---|
664 | ); |
---|
665 | if (zsout(ZDFILE,xbuf) < 0) { |
---|
666 | deblog = 0; |
---|
667 | return(0); |
---|
668 | } |
---|
669 | x = (int)strlen((char *)r_pkt[j].bf_adr); |
---|
670 | sprintf(xbuf,"[%.72s%s]\n",r_pkt[j].bf_adr, x > 72 ? "..." : ""); |
---|
671 | if (zsout(ZDFILE,xbuf) < 0) { |
---|
672 | deblog = 0; |
---|
673 | return(0); |
---|
674 | } |
---|
675 | } |
---|
676 | sprintf(xbuf,"free: %d, winlo: %d\n", rbufnum, winlo); |
---|
677 | if (zsout(ZDFILE,xbuf) < 0) { |
---|
678 | deblog = 0; |
---|
679 | return(0); |
---|
680 | } |
---|
681 | #endif /* DEBUG */ |
---|
682 | return(0); |
---|
683 | } |
---|
684 | |
---|
685 | /*** Some misc functions also moved here from the other ckcfn*.c modules ***/ |
---|
686 | /*** to even out the module sizes. ***/ |
---|
687 | |
---|
688 | /* Attribute Packets. */ |
---|
689 | |
---|
690 | /* |
---|
691 | Call with xp == 0 if we're sending a real file (F packet), |
---|
692 | or xp != 0 for screen data (X packet). |
---|
693 | Returns 0 on success, -1 on failure. |
---|
694 | */ |
---|
695 | int |
---|
696 | sattr(xp) int xp; { /* Send Attributes */ |
---|
697 | int i, j, aln; |
---|
698 | char *tp; |
---|
699 | struct zattr x; |
---|
700 | |
---|
701 | if (zsattr(&x) < 0) return(-1); /* Get attributes or die trying */ |
---|
702 | if (nxtpkt() < 0) return(-1); /* Next packet number */ |
---|
703 | i = 0; /* i = Data field character number */ |
---|
704 | if (atsido) { /* System type */ |
---|
705 | data[i++] = '.'; |
---|
706 | data[i++] = tochar(x.systemid.len); /* Copy from attr structure */ |
---|
707 | for (j = 0; j < x.systemid.len; j++) |
---|
708 | data[i++] = x.systemid.val[j]; |
---|
709 | } |
---|
710 | #ifdef STRATUS |
---|
711 | if (atcreo) { /* File creator */ |
---|
712 | data[i++] = '$'; |
---|
713 | data[i++] = tochar(x.creator.len); /* Copy from attr structure */ |
---|
714 | for (j = 0; j < x.creator.len; j++) |
---|
715 | data[i++] = x.creator.val[j]; |
---|
716 | } |
---|
717 | if (atacto) { /* File account */ |
---|
718 | data[i++] = '%'; |
---|
719 | data[i++] = tochar(x.account.len); /* Copy from attr structure */ |
---|
720 | for (j = 0; j < x.account.len; j++) |
---|
721 | data[i++] = x.account.val[j]; |
---|
722 | } |
---|
723 | if (atfrmo) { /* Packet data format */ |
---|
724 | data[i++] = '/'; |
---|
725 | data[i++] = tochar(x.recfm.len); /* Copy from attr structure */ |
---|
726 | for (j = 0; j < x.recfm.len; j++) |
---|
727 | data[i++] = x.recfm.val[j]; |
---|
728 | } |
---|
729 | #endif /* STRATUS */ |
---|
730 | if (attypo) { /* File type */ |
---|
731 | data[i++] = '"'; |
---|
732 | if ( |
---|
733 | #ifdef VMS |
---|
734 | binary == XYFT_I || binary == XYFT_L || /* IMAGE or LABELED */ |
---|
735 | !strncmp(x.recfm.val,"F",1) /* or RECFM=Fxxxxxx */ |
---|
736 | #else |
---|
737 | binary /* User said SET FILE TYPE BINARY */ |
---|
738 | #endif /* VMS */ |
---|
739 | ) { /* Binary */ |
---|
740 | data[i++] = tochar(2); /* Two characters */ |
---|
741 | data[i++] = 'B'; /* B for Binary */ |
---|
742 | data[i++] = '8'; /* 8-bit bytes (note assumption...) */ |
---|
743 | #ifdef CK_LABELED |
---|
744 | if (binary != XYFT_L |
---|
745 | #ifdef VMS |
---|
746 | && binary != XYFT_I |
---|
747 | #endif /* VMS */ |
---|
748 | ) |
---|
749 | binary = XYFT_B; |
---|
750 | #endif /* CK_LABELED */ |
---|
751 | } else { /* Text */ |
---|
752 | data[i++] = tochar(3); /* Three characters */ |
---|
753 | data[i++] = 'A'; /* A = (extended) ASCII with CRLFs */ |
---|
754 | data[i++] = 'M'; /* M for carriage return */ |
---|
755 | data[i++] = 'J'; /* J for linefeed */ |
---|
756 | #ifdef VMS |
---|
757 | binary = XYFT_T; /* We automatically detected text */ |
---|
758 | #endif /* VMS */ |
---|
759 | |
---|
760 | #ifdef NOCSETS |
---|
761 | data[i++] = '*'; /* Encoding */ |
---|
762 | data[i++] = tochar(1); /* Length of value is 1 */ |
---|
763 | data[i++] = 'A'; /* A for ASCII */ |
---|
764 | #else |
---|
765 | if (tcharset == TC_TRANSP) { /* Transfer character set */ |
---|
766 | data[i++] = '*'; /* Encoding */ |
---|
767 | data[i++] = tochar(1); /* Length of value is 1 */ |
---|
768 | data[i++] = 'A'; /* A for ASCII */ |
---|
769 | } else { |
---|
770 | tp = tcsinfo[tcharset].designator; |
---|
771 | if ((tp != NULL) && (aln = (int)strlen(tp)) > 0) { |
---|
772 | data[i++] = '*'; /* Encoding */ |
---|
773 | data[i++] = tochar(aln+1); /* Length of designator. */ |
---|
774 | data[i++] = 'C'; /* Text in specified charset. */ |
---|
775 | for (j = 0; j < aln; j++) /* Copy designator */ |
---|
776 | data[i++] = *tp++; /* Example: *&I6/100 */ |
---|
777 | } |
---|
778 | } |
---|
779 | #endif /* NOCSETS */ |
---|
780 | } |
---|
781 | } |
---|
782 | if ((xp == 0) && (x.length > -1L)) { /* If it's a real file */ |
---|
783 | |
---|
784 | if (atdato && (aln = x.date.len) > 0) { /* Creation date, if any */ |
---|
785 | data[i++] = '#'; |
---|
786 | data[i++] = tochar(aln); |
---|
787 | for (j = 0; j < aln; j++) |
---|
788 | data[i++] = x.date.val[j]; |
---|
789 | } |
---|
790 | if (atleno) { |
---|
791 | data[i] = '!'; /* File length in K */ |
---|
792 | sprintf((char *) &data[i+2],"%ld",x.lengthk); |
---|
793 | aln = (int)strlen((char *)(data+i+2)); |
---|
794 | data[i+1] = tochar(aln); |
---|
795 | i += aln + 2; |
---|
796 | |
---|
797 | data[i] = '1'; /* File length in bytes */ |
---|
798 | sprintf((char *) &data[i+2],"%ld",x.length); |
---|
799 | aln = (int)strlen((char *)(data+i+2)); |
---|
800 | data[i+1] = tochar(aln); |
---|
801 | i += aln + 2; |
---|
802 | } |
---|
803 | if (atblko && fblksiz) { /* Blocksize, if set */ |
---|
804 | data[i] = '('; |
---|
805 | sprintf((char *) &data[i+2],"%d",fblksiz); |
---|
806 | aln = (int)strlen((char *)(data+i+2)); |
---|
807 | data[i+1] = tochar(aln); |
---|
808 | i += aln + 2; |
---|
809 | } |
---|
810 | } |
---|
811 | #ifndef NOFRILLS |
---|
812 | if ((rprintf || rmailf) && atdiso) { /* MAIL, or REMOTE PRINT? */ |
---|
813 | data[i++] = '+'; /* Disposition */ |
---|
814 | data[i++] = tochar((int)strlen(optbuf) + 1); /* Options, if any */ |
---|
815 | if (rprintf) |
---|
816 | data[i++] = 'P'; /* P for Print */ |
---|
817 | else |
---|
818 | data[i++] = 'M'; /* M for Mail */ |
---|
819 | for (j = 0; optbuf[j]; j++) /* Copy any options */ |
---|
820 | data[i++] = optbuf[j]; |
---|
821 | } |
---|
822 | #endif /* NOFRILLS */ |
---|
823 | #ifdef CK_RESEND |
---|
824 | if (sendmode == SM_RESEND) { |
---|
825 | data[i++] = '+'; /* Disposition */ |
---|
826 | data[i++] = tochar(1); |
---|
827 | data[i++] = 'R'; /* is RESEND */ |
---|
828 | } |
---|
829 | #endif /* CK_RESEND */ |
---|
830 | data[i++] = '@'; /* End of Attributes */ |
---|
831 | data[i++] = SP; /* Length 0 */ |
---|
832 | data[i] = '\0'; /* Make sure it's null-terminated */ |
---|
833 | aln = (int)strlen((char *)data); /* Get overall length of attributes */ |
---|
834 | |
---|
835 | /* Change this code to break attribute data up into multiple packets! */ |
---|
836 | |
---|
837 | j = (spsiz < 95) ? (92 - bctl) : (spsiz - 2 - bctl); |
---|
838 | if (aln > j) { /* Check length of result */ |
---|
839 | spack('A',pktnum,0,(CHAR *)""); /* send an empty attribute packet */ |
---|
840 | debug(F101,"sattr pkt too long","",aln); /* if too long */ |
---|
841 | debug(F101,"sattr spsiz","",spsiz); |
---|
842 | } else { /* Otherwise */ |
---|
843 | spack('A',pktnum,aln,data); /* send the real thing. */ |
---|
844 | debug(F111,"sattr",data,aln); |
---|
845 | } |
---|
846 | |
---|
847 | return(0); |
---|
848 | } |
---|
849 | |
---|
850 | static char *refused = ""; |
---|
851 | |
---|
852 | static char *reason[] = { |
---|
853 | "size", "type", "date", "creator", "account", "area", "password", |
---|
854 | "blocksize", "access", "encoding", "disposition", "protection", |
---|
855 | "protection", "origin", "format", |
---|
856 | "sys-dependent", /* 0 */ |
---|
857 | "size", /* 1 */ |
---|
858 | "2", /* 2 */ |
---|
859 | "3", /* 3 */ |
---|
860 | "4", /* 4 */ |
---|
861 | "5", /* 5 */ |
---|
862 | "6", /* 6 */ |
---|
863 | "7", /* 7 */ |
---|
864 | "8", /* 8 */ |
---|
865 | "9", /* 9 */ |
---|
866 | ":", /* : */ |
---|
867 | ";", /* ; */ |
---|
868 | "<", /* < */ |
---|
869 | "=", /* = */ |
---|
870 | ">", /* > */ |
---|
871 | "name", /* ? */ |
---|
872 | "@" |
---|
873 | }; |
---|
874 | static int nreason = sizeof(reason) / sizeof(char *); |
---|
875 | int rejection = -1; |
---|
876 | |
---|
877 | char * |
---|
878 | getreason(s) char *s; { /* Decode attribute refusal reason */ |
---|
879 | char c, *p; |
---|
880 | if (rejection == 1) /* Kludge for SET FIL COLL DISCARD */ |
---|
881 | return("name"); /* when other Kermit doesn't... */ |
---|
882 | p = s; |
---|
883 | if (*p++ != 'N') return(""); /* Should start with N */ |
---|
884 | else if ((c = *p) > SP) { /* get reason, */ |
---|
885 | rejection = c; /* remember it, */ |
---|
886 | c -= '!'; /* get offset */ |
---|
887 | p = ((unsigned int) ((CHAR) c) <= nreason) ? reason[c] : "unknown"; |
---|
888 | } |
---|
889 | return(p); |
---|
890 | } |
---|
891 | |
---|
892 | int |
---|
893 | rsattr(s) CHAR *s; { /* Read response to attribute packet */ |
---|
894 | debug(F111,"rsattr: ",s,*s); |
---|
895 | if (*s == 'N') { /* If it's 'N' followed by anything, */ |
---|
896 | refused = getreason((char *)s); /* they are refusing, get reason. */ |
---|
897 | debug(F110," refused",refused,0); |
---|
898 | tlog(F110," refused:",refused,0L); |
---|
899 | return(-1); |
---|
900 | } |
---|
901 | #ifdef CK_RESEND |
---|
902 | if (sendmode == SM_RESEND && *s == '1') { /* RESEND length */ |
---|
903 | int n; long z; CHAR *p; |
---|
904 | p = s + 1; |
---|
905 | n = xunchar(*p++); |
---|
906 | debug(F101,"rsattr RESEND n","",n); |
---|
907 | z = 0L; |
---|
908 | while (n-- > 0) /* We assume the format is good. */ |
---|
909 | z = 10L * z + (long) (*p++ - '0'); |
---|
910 | debug(F101,"rsattr RESEND z","",z); |
---|
911 | if (z > 0L) sendstart = z; |
---|
912 | debug(F101,"rsattr RESEND sendstart","",sendstart); |
---|
913 | if (sendstart > 0L) |
---|
914 | if (zfseek(sendstart) < 0) /* Input file is already open. */ |
---|
915 | return(0); |
---|
916 | #ifdef CK_CURSES |
---|
917 | if (fdispla == XYFD_C) |
---|
918 | screen(SCR_FS,0,fsize,""); /* Refresh file transfer display */ |
---|
919 | #endif /* CK_CURSES */ |
---|
920 | } |
---|
921 | #endif /* CK_RESEND */ |
---|
922 | refused = ""; |
---|
923 | return(0); |
---|
924 | } |
---|
925 | |
---|
926 | long rs_len = 0L; /* Length of file being resent to */ |
---|
927 | |
---|
928 | /* |
---|
929 | Get attributes from incoming A packet. Returns: |
---|
930 | 0 on success, file is to be accepted |
---|
931 | -1 on failure, file is to be refused |
---|
932 | */ |
---|
933 | int |
---|
934 | gattr(s, yy) CHAR *s; struct zattr *yy; { /* Read incoming attribute packet */ |
---|
935 | char c, d; |
---|
936 | char *ff; |
---|
937 | int aln, i; |
---|
938 | |
---|
939 | #define ABUFL 40 /* Temporary buffer for conversions */ |
---|
940 | char abuf[ABUFL]; |
---|
941 | #define FTBUFL 10 /* File type buffer */ |
---|
942 | static char ftbuf[FTBUFL]; |
---|
943 | #define DTBUFL 40 /* File creation date */ |
---|
944 | static char dtbuf[DTBUFL]; |
---|
945 | #define TSBUFL 10 /* Transfer syntax */ |
---|
946 | static char tsbuf[TSBUFL]; |
---|
947 | #define IDBUFL 10 /* System ID */ |
---|
948 | static char idbuf[IDBUFL]; |
---|
949 | #ifndef DYNAMIC |
---|
950 | #define DSBUFL 100 /* Disposition */ |
---|
951 | static char dsbuf[DSBUFL]; |
---|
952 | #define SPBUFL 512 /* System-dependent parameters */ |
---|
953 | static char spbuf[SPBUFL]; |
---|
954 | #else |
---|
955 | #define DSBUFL 100 /* Disposition */ |
---|
956 | static char *dsbuf = NULL; |
---|
957 | #define SPBUFL 512 /* System-dependent parameters */ |
---|
958 | static char *spbuf = NULL; |
---|
959 | #endif /* DYNAMIC */ |
---|
960 | #define RPBUFL 20 /* Attribute reply */ |
---|
961 | static char rpbuf[RPBUFL]; |
---|
962 | |
---|
963 | char *rp; /* Pointer to reply buffer */ |
---|
964 | int retcode; /* Return code */ |
---|
965 | |
---|
966 | d = SP; /* Initialize disposition */ |
---|
967 | ff = filnam; /* Filename returned by rcvfil */ |
---|
968 | if (fncact == XYFX_R && ofn1x && ofn1[0]) /* But watch out for FC=RENAME */ |
---|
969 | ff = ofn1; /* because we haven't renamed it yet */ |
---|
970 | |
---|
971 | /* Fill in the attributes we have received */ |
---|
972 | |
---|
973 | rp = rpbuf; /* Initialize reply buffer */ |
---|
974 | *rp++ = 'N'; /* for negative reply. */ |
---|
975 | *rp = NUL; |
---|
976 | retcode = 0; /* Initialize return code. */ |
---|
977 | |
---|
978 | if (dest == DEST_P) { /* SET DESTINATION PRINTER */ |
---|
979 | #ifdef DYNAMIC |
---|
980 | if (!dsbuf) |
---|
981 | if ((dsbuf = malloc(DSBUFL+1)) == NULL) |
---|
982 | fatal("gtattr: no memory for dsbuf"); |
---|
983 | #endif /* DYNAMIC */ |
---|
984 | dsbuf[0] = 'P'; |
---|
985 | dsbuf[1] = '\0'; |
---|
986 | yy->disp.val = dsbuf; |
---|
987 | yy->disp.len = 1; |
---|
988 | } |
---|
989 | while (c = *s++) { /* Get attribute tag */ |
---|
990 | aln = xunchar(*s++); /* Length of attribute string */ |
---|
991 | switch (c) { |
---|
992 | case '!': /* File length in K */ |
---|
993 | for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */ |
---|
994 | abuf[i] = *s++; |
---|
995 | abuf[i] = '\0'; /* Terminate with null */ |
---|
996 | if (i < aln) s += (aln - i); /* If field was too long for buffer */ |
---|
997 | yy->lengthk = atol(abuf); /* Convert to number */ |
---|
998 | break; |
---|
999 | |
---|
1000 | case '"': /* file type */ |
---|
1001 | for (i = 0; (i < aln) && (i < FTBUFL); i++) |
---|
1002 | ftbuf[i] = *s++; /* Copy it into a static string */ |
---|
1003 | ftbuf[i] = '\0'; |
---|
1004 | if (i < aln) s += (aln - i); |
---|
1005 | if (attypi) { /* TYPE attribute is enabled? */ |
---|
1006 | yy->type.val = ftbuf; /* Pointer to string */ |
---|
1007 | yy->type.len = i; /* Length of string */ |
---|
1008 | debug(F111,"gattr file type",ftbuf,i); |
---|
1009 | debug(F101,"gattr binary","",binary); |
---|
1010 | if ( /* Unknown type? */ |
---|
1011 | (*ftbuf != 'A' && *ftbuf != 'B' && *ftbuf != 'I') |
---|
1012 | #ifdef CK_LABELED |
---|
1013 | /* ... Or our FILE TYPE is LABELED and the incoming file is text... */ |
---|
1014 | || (binary == XYFT_L && *ftbuf == 'A' && !xflg) |
---|
1015 | #endif /* CK_LABELED */ |
---|
1016 | ) { |
---|
1017 | retcode = -1; /* Reject the file */ |
---|
1018 | *rp++ = c; |
---|
1019 | if (!opnerr) tlog(F100," refused: type","",0); |
---|
1020 | break; |
---|
1021 | } |
---|
1022 | /* |
---|
1023 | The following code moved here from opena() so we set binary mode |
---|
1024 | as soon as requested by the attribute packet. That way when the first |
---|
1025 | data packet comes, the mode of transfer can be displayed correctly |
---|
1026 | before opena() is called. |
---|
1027 | */ |
---|
1028 | if (yy->type.val[0] == 'A') { /* Check received attributes. */ |
---|
1029 | binary = XYFT_T; /* Set current type to Text. */ |
---|
1030 | debug(F100,"gattr attribute A = text","",binary); /* */ |
---|
1031 | } else if (yy->type.val[0] == 'B') { |
---|
1032 | #ifdef CK_LABELED |
---|
1033 | if (binary != XYFT_L |
---|
1034 | #ifdef VMS |
---|
1035 | && binary != XYFT_U /* VMS special case */ |
---|
1036 | #endif /* VMS */ |
---|
1037 | ) |
---|
1038 | #endif /* CK_LABELED */ |
---|
1039 | #ifdef MAC |
---|
1040 | if (binary != XYFT_M) /* If not MacBinary... */ |
---|
1041 | #endif /* MAC */ |
---|
1042 | binary = XYFT_B; |
---|
1043 | debug(F101,"gattr attribute B = binary","",binary); |
---|
1044 | } |
---|
1045 | } |
---|
1046 | break; |
---|
1047 | |
---|
1048 | case '#': /* File creation date */ |
---|
1049 | for (i = 0; (i < aln) && (i < DTBUFL); i++) |
---|
1050 | dtbuf[i] = *s++; /* Copy it into a static string */ |
---|
1051 | if (i < aln) s += (aln - i); |
---|
1052 | dtbuf[i] = '\0'; |
---|
1053 | if (atdati) { |
---|
1054 | yy->date.val = dtbuf; /* Pointer to string */ |
---|
1055 | yy->date.len = i; /* Length of string */ |
---|
1056 | if (fncact == XYFX_U) { /* Receiving in update mode? */ |
---|
1057 | if (zstime(ff,yy,1) > 0) { /* Compare dates */ |
---|
1058 | *rp++ = c; /* Discard if older, reason = date. */ |
---|
1059 | if (!opnerr) tlog(F100," refused: date","",0); |
---|
1060 | retcode = -1; /* Rejection notice. */ |
---|
1061 | } |
---|
1062 | } |
---|
1063 | } |
---|
1064 | break; |
---|
1065 | |
---|
1066 | case '(': /* File Block Size */ |
---|
1067 | for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */ |
---|
1068 | abuf[i] = *s++; |
---|
1069 | abuf[i] = '\0'; /* Terminate with null */ |
---|
1070 | if (i < aln) s += (aln - i); |
---|
1071 | if (atblki) |
---|
1072 | yy->blksize = atol(abuf); /* Convert to number */ |
---|
1073 | break; |
---|
1074 | |
---|
1075 | case '*': /* Encoding (transfer syntax) */ |
---|
1076 | for (i = 0; (i < aln) && (i < TSBUFL); i++) |
---|
1077 | tsbuf[i] = *s++; /* Copy it into a static string */ |
---|
1078 | if (i < aln) s += (aln - i); |
---|
1079 | tsbuf[i] = '\0'; |
---|
1080 | if (atenci) { |
---|
1081 | yy->encoding.val = tsbuf; /* Pointer to string */ |
---|
1082 | yy->encoding.len = i; /* Length of string */ |
---|
1083 | debug(F101,"gattr encoding",tsbuf,i); |
---|
1084 | switch (*tsbuf) { |
---|
1085 | #ifndef NOCSETS |
---|
1086 | case 'A': /* Normal, nothing special */ |
---|
1087 | tcharset = TC_TRANSP; /* Transparent chars untranslated */ |
---|
1088 | break; |
---|
1089 | case 'C': /* Specified character set */ |
---|
1090 | for (i = 0; i < ntcsets; i++) { |
---|
1091 | if (!strcmp(tcsinfo[i].designator,tsbuf+1)) break; |
---|
1092 | } |
---|
1093 | debug(F101,"gattr xfer charset lookup","",i); |
---|
1094 | if (i == ntcsets) { /* If unknown character set, */ |
---|
1095 | debug(F110,"gattr: xfer charset unknown",tsbuf+1,0); |
---|
1096 | if (!unkcs) { /* and SET UNKNOWN DISCARD, */ |
---|
1097 | retcode = -1; /* reject the file. */ |
---|
1098 | *rp++ = c; |
---|
1099 | if (!opnerr) |
---|
1100 | tlog(F100," refused: character set","",0); |
---|
1101 | } |
---|
1102 | } else { |
---|
1103 | tcharset = tcsinfo[i].code; /* if known, use it */ |
---|
1104 | rx = xlr[tcharset][fcharset]; /* xlation function */ |
---|
1105 | } |
---|
1106 | debug(F101,"gattr tcharset","",tcharset); |
---|
1107 | break; |
---|
1108 | #endif /* NOCSETS */ |
---|
1109 | default: /* Something else. */ |
---|
1110 | debug(F110,"gattr unk encoding attribute",tsbuf,0); |
---|
1111 | if (!unkcs) { /* If SET UNK DISC */ |
---|
1112 | retcode = -1; |
---|
1113 | *rp++ = c; |
---|
1114 | if (!opnerr) tlog(F100," refused: encoding","",0); |
---|
1115 | } |
---|
1116 | break; |
---|
1117 | } |
---|
1118 | } |
---|
1119 | break; |
---|
1120 | |
---|
1121 | case '+': /* Disposition */ |
---|
1122 | #ifdef DYNAMIC |
---|
1123 | if (!dsbuf) |
---|
1124 | if ((dsbuf = malloc(DSBUFL+1)) == NULL) |
---|
1125 | fatal("gtattr: no memory for dsbuf"); |
---|
1126 | #endif /* DYNAMIC */ |
---|
1127 | for (i = 0; (i < aln) && (i < DSBUFL); i++) |
---|
1128 | dsbuf[i] = *s++; /* Copy it into a separate string */ |
---|
1129 | dsbuf[i] = '\0'; |
---|
1130 | if (i < aln) s += (aln - i); |
---|
1131 | rs_len = 0; |
---|
1132 | if (atdisi) { /* We are doing this attribute */ |
---|
1133 | /* Copy it into the attribute structure */ |
---|
1134 | yy->disp.val = dsbuf; /* Pointer to string */ |
---|
1135 | yy->disp.len = i; /* Length of string */ |
---|
1136 | d = *dsbuf; |
---|
1137 | #ifndef NODISPO |
---|
1138 | /* |
---|
1139 | Define NODISPO to disable receipt of mail or print files and of RESEND. |
---|
1140 | */ |
---|
1141 | if ( |
---|
1142 | #ifndef datageneral /* MAIL supported only for */ |
---|
1143 | #ifndef OS2 /* UNIX, VMS, and OS-9 */ |
---|
1144 | #ifndef MAC |
---|
1145 | #ifndef GEMDOS |
---|
1146 | #ifndef AMIGA |
---|
1147 | d != 'M' && /* MAIL */ |
---|
1148 | #endif /* AMIGA */ |
---|
1149 | #endif /* GEMDOS */ |
---|
1150 | #endif /* MAC */ |
---|
1151 | #endif /* OS/2 */ |
---|
1152 | #endif /* datageneral */ |
---|
1153 | #ifdef CK_RESEND |
---|
1154 | d != 'R' && /* RESEND */ |
---|
1155 | #endif /* CK_RESEND */ |
---|
1156 | d != 'P') { /* PRINT */ |
---|
1157 | retcode = -1; /* Unknown/unsupported disposition */ |
---|
1158 | *rp++ = c; |
---|
1159 | if (!opnerr) tlog(F101," refused: bad disposition","",d); |
---|
1160 | } |
---|
1161 | #ifndef NOFRILLS |
---|
1162 | if (d == 'M' && !en_mai) { |
---|
1163 | retcode = -1; |
---|
1164 | *rp++ = c; |
---|
1165 | if (!opnerr) tlog(F100," refused: mail disabled","",0); |
---|
1166 | } else |
---|
1167 | #endif /* NOFRILLS */ |
---|
1168 | if (d == 'P' && !en_pri) { |
---|
1169 | retcode = -1; |
---|
1170 | *rp++ = c; |
---|
1171 | if (!opnerr) tlog(F100," refused: print disabled","",0); |
---|
1172 | } else if (d == 'R') { /* File is being resent */ |
---|
1173 | #ifdef CK_RESEND |
---|
1174 | rs_len = zchki(ff); /* Get length of file */ |
---|
1175 | debug(F111,"gattr RESEND",ff,rs_len); |
---|
1176 | #ifdef VMS |
---|
1177 | rs_len &= (long) -512; /* Ensure block boundary if VMS */ |
---|
1178 | rs_len -= 512; /* In case last block not complete */ |
---|
1179 | debug(F111,"gattr rs_len",ff,rs_len); |
---|
1180 | #endif /* VMS */ |
---|
1181 | if (rs_len < 0L) |
---|
1182 | rs_len = 0L; |
---|
1183 | if (rs_len > 0L) { |
---|
1184 | fncsav = fncact; /* Save collision action */ |
---|
1185 | fncact = XYFX_A; /* Switch to APPEND */ |
---|
1186 | } |
---|
1187 | #else |
---|
1188 | retcode = -1; /* This shouldn't happen */ |
---|
1189 | *rp++ = c; /* 'cause it wasn't negotiated. */ |
---|
1190 | if (!opnerr) tlog(F100," refused: resend","",0); |
---|
1191 | #endif /* CK_RESEND */ |
---|
1192 | } |
---|
1193 | #else /* NODISPO */ |
---|
1194 | retcode = -1; |
---|
1195 | *rp++ = c; |
---|
1196 | if (!opnerr) tlog(F100," refused: NODISPO","",0); |
---|
1197 | #endif /* NODISPO */ |
---|
1198 | } |
---|
1199 | break; |
---|
1200 | |
---|
1201 | case '.': /* Sender's system ID */ |
---|
1202 | for (i = 0; (i < aln) && (i < IDBUFL); i++) |
---|
1203 | idbuf[i] = *s++; /* Copy it into a static string */ |
---|
1204 | idbuf[i] = '\0'; |
---|
1205 | if (i < aln) s += (aln - i); |
---|
1206 | if (atsidi) { |
---|
1207 | yy->systemid.val = idbuf; /* Pointer to string */ |
---|
1208 | yy->systemid.len = i; /* Length of string */ |
---|
1209 | } |
---|
1210 | break; |
---|
1211 | |
---|
1212 | case '0': /* System-dependent parameters */ |
---|
1213 | #ifdef DYNAMIC |
---|
1214 | if (!spbuf && !(spbuf = malloc(SPBUFL))) |
---|
1215 | fatal("gattr: no memory for spbuf"); |
---|
1216 | #endif /* DYNAMIC */ |
---|
1217 | for (i = 0; (i < aln) && (i < SPBUFL); i++) |
---|
1218 | spbuf[i] = *s++; /* Copy it into a static string */ |
---|
1219 | spbuf[i] = '\0'; |
---|
1220 | if (i < aln) s += (aln - i); |
---|
1221 | if (atsysi) { |
---|
1222 | yy->sysparam.val = spbuf; /* Pointer to string */ |
---|
1223 | yy->sysparam.len = i; /* Length of string */ |
---|
1224 | } |
---|
1225 | break; |
---|
1226 | |
---|
1227 | case '1': /* File length in bytes */ |
---|
1228 | for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */ |
---|
1229 | abuf[i] = *s++; |
---|
1230 | abuf[i] = '\0'; /* Terminate with null */ |
---|
1231 | if (i < aln) s += (aln - i); |
---|
1232 | yy->length = atol(abuf); /* Convert to number */ |
---|
1233 | debug(F111,"gattr length",abuf,(int) yy->length); |
---|
1234 | break; |
---|
1235 | |
---|
1236 | #ifdef STRATUS |
---|
1237 | case '/': /* Format of data in packets */ |
---|
1238 | /* We just copy it into the record and let the fio module */ |
---|
1239 | /* figure out what to do with it. */ |
---|
1240 | for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */ |
---|
1241 | abuf[i] = *s++; |
---|
1242 | abuf[i] = '\0'; /* Terminate with null */ |
---|
1243 | if (atsysi) { /* same switch as OS-DEPENDENT */ |
---|
1244 | yy->recfm.val = spbuf; /* Pointer to string */ |
---|
1245 | yy->recfm.len = i; /* Length of string */ |
---|
1246 | } |
---|
1247 | break; |
---|
1248 | #endif /* STRATUS */ |
---|
1249 | |
---|
1250 | default: /* Unknown attribute */ |
---|
1251 | s += aln; /* Just skip past it */ |
---|
1252 | break; |
---|
1253 | } |
---|
1254 | } |
---|
1255 | |
---|
1256 | /* Check file length now, because we also need to know the file type */ |
---|
1257 | /* in case zchkspa() differentiates text and binary (VMS version does) */ |
---|
1258 | |
---|
1259 | if (atleni) { /* Length attribute enabled? */ |
---|
1260 | if (yy->length > -1L) { /* Length-in-bytes attribute rec'd? */ |
---|
1261 | if (!zchkspa(ff,(yy->length))) { /* Check space */ |
---|
1262 | retcode = -1; /* Not enuf */ |
---|
1263 | *rp++ = '1'; |
---|
1264 | if (!opnerr) tlog(F100," refused: length bytes","",0); |
---|
1265 | } |
---|
1266 | } else if (yy->lengthk > -1L) { /* Length in K attribute rec'd? */ |
---|
1267 | if (!zchkspa(ff,(yy->lengthk * 1024))) { |
---|
1268 | retcode = -1; /* Check space */ |
---|
1269 | *rp++ = '!'; |
---|
1270 | if (!opnerr) tlog(F100," refused: length K","",0); |
---|
1271 | } |
---|
1272 | } |
---|
1273 | } |
---|
1274 | if (yy->length > -1L) { /* Remember the file size */ |
---|
1275 | fsize = yy->length; |
---|
1276 | } else if (yy->lengthk > -1L) { |
---|
1277 | fsize = yy->lengthk * 1024L; |
---|
1278 | } else fsize = -1L; |
---|
1279 | |
---|
1280 | #ifdef DEBUG |
---|
1281 | if (deblog) { |
---|
1282 | sprintf(abuf,"%ld",fsize); |
---|
1283 | debug(F110,"gattr fsize",abuf,0); |
---|
1284 | } |
---|
1285 | #endif /* DEBUG */ |
---|
1286 | if (retcode == 0) rp = rpbuf; /* Null reply string if accepted */ |
---|
1287 | *rp = '\0'; /* End of reply string */ |
---|
1288 | #ifdef CK_RESEND |
---|
1289 | if (d == 'R') { /* Receiving a RESEND? */ |
---|
1290 | debug(F101,"gattr RESEND","",retcode); |
---|
1291 | /* We ignore retcodes because this overrides */ |
---|
1292 | if (binary != XYFT_B) { /* Reject if not binary */ |
---|
1293 | retcode = -1; /* in case type field came */ |
---|
1294 | strcpy(rpbuf,"N+"); /* after the disposition field */ |
---|
1295 | debug(F111,"gattr RESEND not binary",rpbuf,binary); |
---|
1296 | } else { /* Binary mode */ |
---|
1297 | retcode = 0; /* Accept the file */ |
---|
1298 | discard = 0; /* If SET FILE COLLISION DISCARD */ |
---|
1299 | sprintf(rpbuf+2,"%ld",rs_len); /* Reply with length of file */ |
---|
1300 | rpbuf[0] = '1'; /* '1' means Length in Bytes */ |
---|
1301 | rpbuf[1] = tochar((int)strlen(rpbuf+2)); /* Length of length */ |
---|
1302 | debug(F111,"gattr RESEND OK",rpbuf,retcode); |
---|
1303 | } |
---|
1304 | } |
---|
1305 | #endif /* CK_RESEND */ |
---|
1306 | if (retcode == 0 && discard != 0) { /* Do we still have a discard flag? */ |
---|
1307 | strcpy(rpbuf,"N?"); /* Yes, must be filename collision */ |
---|
1308 | retcode = -1; /* "?" = name (reply-only code) */ |
---|
1309 | } |
---|
1310 | yy->reply.val = rpbuf; /* Add it to attribute structure */ |
---|
1311 | yy->reply.len = (int)strlen(rpbuf); |
---|
1312 | if (retcode < 0) { /* If we are rejecting */ |
---|
1313 | discard = 1; /* remember to discard the file */ |
---|
1314 | rejection = rpbuf[1]; /* and use the first reason given. */ |
---|
1315 | if (fncsav != -1) { |
---|
1316 | fncact = fncsav; |
---|
1317 | fncsav = -1; |
---|
1318 | } |
---|
1319 | } |
---|
1320 | debug(F111,"gattr return",rpbuf,retcode); |
---|
1321 | return(retcode); |
---|
1322 | } |
---|
1323 | |
---|
1324 | /* I N I T A T T R -- Initialize file attribute structure */ |
---|
1325 | |
---|
1326 | int |
---|
1327 | initattr(yy) struct zattr *yy; { |
---|
1328 | yy->lengthk = yy->length = -1L; |
---|
1329 | yy->type.val = ""; |
---|
1330 | yy->type.len = 0; |
---|
1331 | yy->date.val = ""; |
---|
1332 | yy->date.len = 0; |
---|
1333 | yy->encoding.val = ""; |
---|
1334 | yy->encoding.len = 0; |
---|
1335 | yy->disp.val = ""; |
---|
1336 | yy->disp.len = 0; |
---|
1337 | yy->systemid.val = ""; |
---|
1338 | yy->systemid.len = 0; |
---|
1339 | yy->sysparam.val = ""; |
---|
1340 | yy->sysparam.len = 0; |
---|
1341 | yy->creator.val = ""; |
---|
1342 | yy->creator.len = 0; |
---|
1343 | yy->account.val = ""; |
---|
1344 | yy->account.len = 0; |
---|
1345 | yy->area.val = ""; |
---|
1346 | yy->area.len = 0; |
---|
1347 | yy->password.val = ""; |
---|
1348 | yy->password.len = 0; |
---|
1349 | yy->blksize = -1L; |
---|
1350 | yy->xaccess.val = ""; |
---|
1351 | yy->xaccess.len = 0; |
---|
1352 | yy->lprotect.val = ""; |
---|
1353 | yy->lprotect.len = 0; |
---|
1354 | yy->gprotect.val = ""; |
---|
1355 | yy->gprotect.len = 0; |
---|
1356 | yy->recfm.val = ""; |
---|
1357 | yy->recfm.len = 0; |
---|
1358 | yy->reply.val = ""; |
---|
1359 | yy->reply.len = 0; |
---|
1360 | #ifdef OS2 |
---|
1361 | yy->longname.len = 0 ; |
---|
1362 | yy->longname.val = "" ; |
---|
1363 | #endif /* OS2 */ |
---|
1364 | return(0); |
---|
1365 | } |
---|
1366 | |
---|
1367 | /* A D E B U -- Write attribute packet info to debug log */ |
---|
1368 | |
---|
1369 | int |
---|
1370 | adebu(f,zz) char *f; struct zattr *zz; { |
---|
1371 | #ifdef DEBUG |
---|
1372 | if (deblog == 0) return(0); |
---|
1373 | debug(F110,"Attributes for incoming file ",f,0); |
---|
1374 | debug(F101," length in K","",(int) zz->lengthk); |
---|
1375 | debug(F111," file type",zz->type.val,zz->type.len); |
---|
1376 | debug(F111," creation date",zz->date.val,zz->date.len); |
---|
1377 | debug(F111," creator",zz->creator.val,zz->creator.len); |
---|
1378 | debug(F111," account",zz->account.val,zz->account.len); |
---|
1379 | debug(F111," area",zz->area.val,zz->area.len); |
---|
1380 | debug(F111," password",zz->password.val,zz->password.len); |
---|
1381 | debug(F101," blksize","",(int) zz->blksize); |
---|
1382 | debug(F111," access",zz->xaccess.val,zz->xaccess.len); |
---|
1383 | debug(F111," encoding",zz->encoding.val,zz->encoding.len); |
---|
1384 | debug(F111," disposition",zz->disp.val,zz->disp.len); |
---|
1385 | debug(F111," lprotection",zz->lprotect.val,zz->lprotect.len); |
---|
1386 | debug(F111," gprotection",zz->gprotect.val,zz->gprotect.len); |
---|
1387 | debug(F111," systemid",zz->systemid.val,zz->systemid.len); |
---|
1388 | debug(F111," recfm",zz->recfm.val,zz->recfm.len); |
---|
1389 | debug(F111," sysparam",zz->sysparam.val,zz->sysparam.len); |
---|
1390 | debug(F101," length","",(int) zz->length); |
---|
1391 | debug(F110," reply",zz->reply.val,0); |
---|
1392 | #endif /* DEBUG */ |
---|
1393 | return(0); |
---|
1394 | } |
---|
1395 | |
---|
1396 | /* O P E N A -- Open a file, with attributes. */ |
---|
1397 | /* |
---|
1398 | This function tries to open a new file to put the arriving data in. The |
---|
1399 | filename is the one in the srvcmd buffer. File collision actions are: |
---|
1400 | OVERWRITE (the existing file is overwritten), RENAME (the new file is |
---|
1401 | renamed), BACKUP (the existing file is renamed), DISCARD (the new file is |
---|
1402 | refused), UPDATE (the incoming file replaces the existing file only if the |
---|
1403 | incoming file has a newer creation date). |
---|
1404 | |
---|
1405 | Returns 0 on failure, nonzero on success. |
---|
1406 | */ |
---|
1407 | extern char *rf_err; |
---|
1408 | |
---|
1409 | int |
---|
1410 | opena(f,zz) char *f; struct zattr *zz; { |
---|
1411 | int x, dispos = 0; |
---|
1412 | static struct filinfo fcb; /* Must be static! */ |
---|
1413 | |
---|
1414 | debug(F110,"opena f",f,0); |
---|
1415 | debug(F101,"opena discard","",discard); |
---|
1416 | |
---|
1417 | adebu(f,zz); /* Write attributes to debug log */ |
---|
1418 | |
---|
1419 | ffc = 0L; /* Init file-character counter */ |
---|
1420 | |
---|
1421 | /* Set up file control structure */ |
---|
1422 | |
---|
1423 | fcb.bs = fblksiz; /* Blocksize */ |
---|
1424 | #ifndef NOCSETS |
---|
1425 | fcb.cs = fcharset; /* Character set */ |
---|
1426 | #else |
---|
1427 | fcb.cs = 0; /* Character set */ |
---|
1428 | #endif /* NOCSETS */ |
---|
1429 | fcb.rl = frecl; /* Record Length */ |
---|
1430 | fcb.fmt = frecfm; /* Record Format */ |
---|
1431 | fcb.org = forg; /* Organization */ |
---|
1432 | fcb.cc = fcctrl; /* Carriage control */ |
---|
1433 | fcb.typ = binary; /* Type */ |
---|
1434 | debug(F101,"opena xflg","",xflg); |
---|
1435 | debug(F101,"opena remfile","",remfile); |
---|
1436 | debug(F101,"opena remappd","",remappd); |
---|
1437 | if (xflg && remfile && remappd) /* REMOTE output redirected with >> */ |
---|
1438 | fcb.dsp = XYFZ_A; |
---|
1439 | else |
---|
1440 | fcb.dsp = (fncact == XYFX_A) ? XYFZ_A : XYFZ_N; /* Disposition */ |
---|
1441 | debug(F101,"opena disp","",fcb.dsp); |
---|
1442 | fcb.os_specific = '\0'; /* OS-specific info */ |
---|
1443 | #ifdef CK_LABELED |
---|
1444 | fcb.lblopts = lf_opts; /* Labeled file options */ |
---|
1445 | #else |
---|
1446 | fcb.lblopts = 0; |
---|
1447 | #endif /* CK_LABELED */ |
---|
1448 | |
---|
1449 | if (zz->disp.len > 0) { /* Incoming file has a disposition? */ |
---|
1450 | debug(F111,"open disposition",zz->disp.val,zz->disp.len); |
---|
1451 | dispos = (int) (*(zz->disp.val)); |
---|
1452 | } |
---|
1453 | if (!dispos && xflg && remfile && remappd) /* REMOTE redirect append ? */ |
---|
1454 | dispos = fcb.dsp; |
---|
1455 | |
---|
1456 | debug(F101,"opena dispos","",dispos); |
---|
1457 | |
---|
1458 | if (!dispos) { /* No special disposition? */ |
---|
1459 | if (fncact == XYFX_B && ofn1x && ofn2) { /* File collision = BACKUP? */ |
---|
1460 | if (zrename(ofn1,ofn2) < 0) { /* Rename existing file. */ |
---|
1461 | debug(F110,"opena rename fails",ofn1,0); |
---|
1462 | rf_err = "Can't create backup file"; |
---|
1463 | return(0); |
---|
1464 | } else debug(F110,"opena rename ok",ofn2,0); |
---|
1465 | } |
---|
1466 | } else if (dispos == 'R') { /* Receiving a RESEND */ |
---|
1467 | #ifdef COMMENT |
---|
1468 | if (fncact == XYFX_R) /* and file collision = RENAME */ |
---|
1469 | if (ofn1x) |
---|
1470 | #endif /* COMMENT */ |
---|
1471 | if (ofn1[0]) |
---|
1472 | f = ofn1; /* use original name. */ |
---|
1473 | if (fncact == XYFX_R) /* if file collision is RENAME */ |
---|
1474 | strcpy(filnam,ofn1); /* restore the real name */ |
---|
1475 | screen(SCR_AN,0,0L,f); /* update name on screen */ |
---|
1476 | } |
---|
1477 | debug(F111,"opena [file]=mode: ",f,fcb.dsp); |
---|
1478 | if (x = openo(f,zz,&fcb)) { /* Try to open the file. */ |
---|
1479 | #ifdef pdp11 |
---|
1480 | tlog(F110," local name:",f,0L); /* OK, open, record local name. */ |
---|
1481 | #else |
---|
1482 | #ifndef ZFNQFP |
---|
1483 | tlog(F110," local name:",f,0L); |
---|
1484 | #else |
---|
1485 | { /* Log full local pathname */ |
---|
1486 | char *p = NULL, *q = f; |
---|
1487 | if ((p = malloc(CKMAXPATH+1))) |
---|
1488 | if (zfnqfp(filnam, CKMAXPATH, p)) |
---|
1489 | q = p; |
---|
1490 | tlog(F110," local name:",q,0L); |
---|
1491 | if (p) free(p); |
---|
1492 | } |
---|
1493 | #endif /* ZFNQFP */ |
---|
1494 | #endif /* pdp11 */ |
---|
1495 | |
---|
1496 | |
---|
1497 | |
---|
1498 | if (binary) { /* Log file mode in transaction log */ |
---|
1499 | tlog(F101," mode: binary","",(long) binary); |
---|
1500 | } else { /* If text mode, check character set */ |
---|
1501 | tlog(F100," mode: text","",0L); |
---|
1502 | #ifndef NOCSETS |
---|
1503 | tlog(F110," file character-set",fcsinfo[fcharset].name,0L); |
---|
1504 | if (tcharset == TC_TRANSP) |
---|
1505 | tlog(F110," xfer character-set","transparent",0L); |
---|
1506 | else |
---|
1507 | tlog(F110," xfer character-set",tcsinfo[tcharset].name,0L); |
---|
1508 | #endif /* NOCSETS */ |
---|
1509 | debug(F111," opena charset",zz->encoding.val,zz->encoding.len); |
---|
1510 | } |
---|
1511 | if (fsize > -1L) screen(SCR_FS,0,fsize,""); |
---|
1512 | |
---|
1513 | #ifdef datageneral |
---|
1514 | /* |
---|
1515 | Need to turn on multi-tasking console interrupt task here, since multiple |
---|
1516 | files may be received (huh?) ... |
---|
1517 | */ |
---|
1518 | if ((local) && (!quiet)) /* Only do this if local & not quiet */ |
---|
1519 | consta_mt(); /* Start the async read task */ |
---|
1520 | #endif /* datageneral */ |
---|
1521 | |
---|
1522 | } else { /* Did not open file OK. */ |
---|
1523 | |
---|
1524 | char * e; |
---|
1525 | e = ck_errstr(); /* Get system error message */ |
---|
1526 | if (*e) |
---|
1527 | screen(SCR_EM,0,0l,e); |
---|
1528 | else |
---|
1529 | screen(SCR_EM,0,0l,"Can't open output file"); |
---|
1530 | tlog(F110,"Failure to open",f,0L); |
---|
1531 | tlog(F110,"Error:",e,0L); |
---|
1532 | debug(F110,"opena error",e,0); |
---|
1533 | } |
---|
1534 | return(x); /* Pass on return code from openo */ |
---|
1535 | } |
---|
1536 | |
---|
1537 | /* C A N N E D -- Check if current file transfer cancelled */ |
---|
1538 | |
---|
1539 | int |
---|
1540 | canned(buf) CHAR *buf; { |
---|
1541 | if (*buf == 'X') cxseen = 1; |
---|
1542 | if (*buf == 'Z') czseen = 1; |
---|
1543 | debug(F101,"canned: cxseen","",cxseen); |
---|
1544 | debug(F101," czseen","",czseen); |
---|
1545 | return((czseen || cxseen) ? 1 : 0); |
---|
1546 | } |
---|
1547 | |
---|
1548 | |
---|
1549 | /* O P E N I -- Open an existing file for input */ |
---|
1550 | |
---|
1551 | int |
---|
1552 | openi(name) char *name; { |
---|
1553 | int x, filno; |
---|
1554 | char *name2; |
---|
1555 | |
---|
1556 | if (memstr) return(1); /* Just return if file is memory. */ |
---|
1557 | |
---|
1558 | debug(F110,"openi",name,0); |
---|
1559 | debug(F101," sndsrc","",sndsrc); |
---|
1560 | |
---|
1561 | filno = (sndsrc == 0) ? ZSTDIO : ZIFILE; /* ... */ |
---|
1562 | |
---|
1563 | debug(F101," file number","",filno); |
---|
1564 | |
---|
1565 | if (server && !en_cwd) { /* If running as server */ |
---|
1566 | zstrip(name,&name2); /* and CWD is disabled... */ |
---|
1567 | if ( /* check if pathname was included. */ |
---|
1568 | #ifdef VMS |
---|
1569 | zchkpath(name) |
---|
1570 | #else |
---|
1571 | strcmp(name,name2) |
---|
1572 | #endif /* VMS */ |
---|
1573 | ) { |
---|
1574 | tlog(F110,name,"authorization failure",0L); |
---|
1575 | debug(F110," openi authorization failure",name,0); |
---|
1576 | return(0); |
---|
1577 | } else name = name2; |
---|
1578 | } |
---|
1579 | if (zopeni(filno,name)) { /* Otherwise, try to open it. */ |
---|
1580 | debug(F110," ok",name,0); |
---|
1581 | return(1); |
---|
1582 | } else { /* If not found, */ |
---|
1583 | char xname[100]; /* convert the name */ |
---|
1584 | zrtol(name,xname); /* to local form and then */ |
---|
1585 | x = zopeni(filno,xname); /* try opening it again. */ |
---|
1586 | debug(F101," zopeni","",x); |
---|
1587 | if (x) { |
---|
1588 | debug(F110," ok",xname,0); |
---|
1589 | return(1); /* It worked. */ |
---|
1590 | } else { |
---|
1591 | #ifdef COMMENT |
---|
1592 | screen(SCR_EM,0,0l,"Can't open file"); /* It didn't work. */ |
---|
1593 | #endif /* COMMENT */ |
---|
1594 | tlog(F110,xname,"could not be opened",0L); |
---|
1595 | debug(F110," openi failed",xname,0); |
---|
1596 | return(0); |
---|
1597 | } |
---|
1598 | } |
---|
1599 | } |
---|
1600 | |
---|
1601 | /* O P E N O -- Open a new file for output. */ |
---|
1602 | |
---|
1603 | static int isopen = 0; |
---|
1604 | |
---|
1605 | int |
---|
1606 | openo(name,zz,fcb) char *name; struct zattr *zz; struct filinfo *fcb; { |
---|
1607 | char *name2; |
---|
1608 | int channel; |
---|
1609 | |
---|
1610 | if (stdouf) /* Receiving to stdout? */ |
---|
1611 | return(zopeno(ZSTDIO,"",zz,NULL)); |
---|
1612 | |
---|
1613 | debug(F110,"openo: name",name,0); |
---|
1614 | |
---|
1615 | if (cxseen || czseen || discard) { /* If interrupted, get out before */ |
---|
1616 | debug(F100," open cancelled","",0); /* destroying existing file. */ |
---|
1617 | return(1); /* Pretend to succeed. */ |
---|
1618 | } |
---|
1619 | |
---|
1620 | channel = ZOFILE; /* SET DESTINATION DISK or PRINTER */ |
---|
1621 | if (dest == DEST_S) { /* SET DEST SCREEN... */ |
---|
1622 | channel = ZCTERM; |
---|
1623 | fcb = NULL; |
---|
1624 | } |
---|
1625 | if (server && !en_cwd) { /* If running as server */ |
---|
1626 | zstrip(name,&name2); /* and CWD is disabled, */ |
---|
1627 | if (strcmp(name,name2)) { /* check if pathname was included. */ |
---|
1628 | tlog(F110,name,"authorization failure",0L); |
---|
1629 | debug(F110," openo authorization failure",name,0); |
---|
1630 | return(0); |
---|
1631 | } else name = name2; |
---|
1632 | } |
---|
1633 | if (zopeno(channel,name,zz,fcb) == 0) { /* Try to open the file */ |
---|
1634 | isopen = 0; |
---|
1635 | debug(F110,"openo failed",name,0); |
---|
1636 | tlog(F110,"Failure to open",name,0L); |
---|
1637 | return(0); |
---|
1638 | } else { |
---|
1639 | isopen = 1; |
---|
1640 | debug(F110,"openo ok, name",name,0); |
---|
1641 | return(1); |
---|
1642 | } |
---|
1643 | } |
---|
1644 | |
---|
1645 | /* O P E N T -- Open the terminal for output, in place of a file */ |
---|
1646 | |
---|
1647 | int |
---|
1648 | opent(zz) struct zattr *zz; { |
---|
1649 | ffc = tfc = 0L; |
---|
1650 | binary = XYFT_T; |
---|
1651 | return(zopeno(ZCTERM,"",zz,NULL)); |
---|
1652 | } |
---|
1653 | |
---|
1654 | /* C L S I F -- Close the current input file. */ |
---|
1655 | |
---|
1656 | int |
---|
1657 | clsif() { |
---|
1658 | int x = 0; |
---|
1659 | #ifdef datageneral |
---|
1660 | if ((local) && (!quiet)) /* Only do this if local & not quiet */ |
---|
1661 | if (nfils < 1) /* More files to send ... leave it on! */ |
---|
1662 | connoi_mt(); |
---|
1663 | #endif /* datageneral */ |
---|
1664 | if (memstr) { /* If input was memory string, */ |
---|
1665 | memstr = 0; /* indicate no more. */ |
---|
1666 | } else x = zclose(ZIFILE); /* else close input file. */ |
---|
1667 | if (cxseen || czseen) /* If interrupted */ |
---|
1668 | screen(SCR_ST,ST_INT,0l,""); /* say so */ |
---|
1669 | else if (discard) /* If I'm refusing */ |
---|
1670 | screen(SCR_ST,ST_REFU,0l,refused); /* say why */ |
---|
1671 | else { /* Otherwise */ |
---|
1672 | fstats(); /* update statistics */ |
---|
1673 | screen(SCR_ST,ST_OK,0l,""); /* and say transfer was OK */ |
---|
1674 | } |
---|
1675 | hcflg = 0; /* Reset flags */ |
---|
1676 | sendstart = 0L; /* Don't do this again! */ |
---|
1677 | #ifdef COMMENT |
---|
1678 | /* |
---|
1679 | This prevents a subsequent call to clsof() from deleting the file |
---|
1680 | when given the discard flag. |
---|
1681 | */ |
---|
1682 | *filnam = '\0'; /* and current file name */ |
---|
1683 | #endif /* COMMENT */ |
---|
1684 | return(x); |
---|
1685 | } |
---|
1686 | |
---|
1687 | |
---|
1688 | /* C L S O F -- Close an output file. */ |
---|
1689 | |
---|
1690 | /* Call with disp != 0 if file is to be discarded. */ |
---|
1691 | /* Returns -1 upon failure to close, 0 or greater on success. */ |
---|
1692 | |
---|
1693 | int |
---|
1694 | clsof(disp) int disp; { |
---|
1695 | int x; |
---|
1696 | |
---|
1697 | debug(F101,"clsof disp","",disp); |
---|
1698 | if (fncsav != -1) { /* Saved file collision action... */ |
---|
1699 | fncact = fncsav; /* Restore it. */ |
---|
1700 | fncsav = -1; /* Unsave it. */ |
---|
1701 | } |
---|
1702 | #ifdef datageneral |
---|
1703 | if ((local) && (!quiet)) /* Only do this if local & not quiet */ |
---|
1704 | connoi_mt(); |
---|
1705 | #endif /* datageneral */ |
---|
1706 | if ((x = zclose(ZOFILE)) < 0) { /* Try to close the file */ |
---|
1707 | tlog(F100,"Failure to close",filnam,0L); |
---|
1708 | screen(SCR_ST,ST_ERR,0l,""); |
---|
1709 | } else if (disp) { /* Interrupted or refused */ |
---|
1710 | if (keep == 0) { /* If not keeping incomplete files */ |
---|
1711 | if (isopen && /* AND the file is actually open */ |
---|
1712 | *filnam && (what & W_RECV)) /* AND we're receiving!!!... */ |
---|
1713 | zdelet(filnam); /* ONLY THEN, delete it */ |
---|
1714 | if (what != W_NOTHING) { |
---|
1715 | debug(F100,"Incomplete: discarded","",0); |
---|
1716 | tlog(F100," incomplete: discarded","",0L); |
---|
1717 | screen(SCR_ST,ST_DISC,0l,""); |
---|
1718 | } |
---|
1719 | } else { /* Keep incomplete copy */ |
---|
1720 | fstats(); |
---|
1721 | if (!discard) { /* Unless discarding for other reason... */ |
---|
1722 | if (what != W_NOTHING) { |
---|
1723 | debug(F100,"Incomplete: Kept","",0); |
---|
1724 | tlog(F100," incomplete: kept","",0L); |
---|
1725 | } |
---|
1726 | } |
---|
1727 | if (what != W_NOTHING) |
---|
1728 | screen(SCR_ST,ST_INC,0l,""); |
---|
1729 | } |
---|
1730 | } else { /* Nothing wrong, just keep it */ |
---|
1731 | debug(F100,"Closed","",0); /* and give comforting messages. */ |
---|
1732 | fstats(); |
---|
1733 | screen(SCR_ST,ST_OK,0L,""); |
---|
1734 | } |
---|
1735 | rs_len = 0; |
---|
1736 | isopen = 0; /* It's not open any more. */ |
---|
1737 | cxseen = 0; /* Reset per-file interruption flag */ |
---|
1738 | return(x); /* Send back zclose() return code. */ |
---|
1739 | } |
---|
1740 | |
---|
1741 | #ifdef SUNOS4S5 |
---|
1742 | tolower(c) char c; { return((c)-'A'+'a'); } |
---|
1743 | toupper(c) char c; { return((c)-'a'+'A'); } |
---|
1744 | #endif /* SUNOS4S5 */ |
---|