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