home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / wps / com / c_kermit / sources / ckcfn3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-01-01  |  30.1 KB  |  910 lines

  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. #include "ckcdeb.h"
  6. #include "ckcasc.h"
  7. #include "ckcker.h"
  8. #include "ckcxla.h"
  9. #define NULL 0
  10. extern int deblog;
  11. extern int unkcs;
  12. extern int wmax;
  13. extern CHAR *data, filnam[];
  14. extern char optbuf[];
  15. extern int wslots;
  16.  
  17. extern int binary, tcharset, fcharset, rprintf, rmailf, spsiz;
  18. extern int pktnum, cxseen, czseen, bsave, bsavef, filcnt;
  19. extern int memstr, n_len, stdouf, ffc, tfc, keep, sndsrc, hcflg;
  20. extern int ntcsets;
  21. extern long fsize;
  22. extern struct csinfo tcsinfo[];
  23.  
  24. /* Pointers to translation functions */
  25. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();    
  26. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();    
  27. extern CHAR (*rx)();    /* Pointer to input character translation function */
  28. extern CHAR (*sx)();    /* Pointer to output character translation function */
  29.  
  30. /* Variables global to Kermit that are defined in this module */
  31.  
  32. int winlo;                /* packet number at low window edge  */
  33. int sslotsiz,rslotsiz;            /* # of send & receive window slots  */
  34.  
  35. int bigsbufsiz;
  36. int bigrbufsiz;
  37.  
  38. int sbufnum;                /* number of free buffers */
  39. int dum001 = 1234;            /* protection... */
  40. int sbufuse[MAXWS];            /* buffer in-use flag */
  41. int dum003 = 1111;
  42. int rbufnum;                /* number of free buffers */
  43. int dum002 = 4321;            /* more protection */
  44. int rbufuse[MAXWS];            /* buffer in-use flag */
  45. int sseqtbl[64];            /* sequence # to buffer # table */
  46. int rseqtbl[64];            /* sequence # to buffer # table */
  47.  
  48. struct pktinfo s_pkt[MAXWS];        /* array of pktinfo structures */
  49. struct pktinfo r_pkt[MAXWS];        /* array of pktinfo structures */
  50.  
  51. char xbuf[1000];            /* For debug logging */
  52.  
  53. CHAR bigsbuf[BIGSBUFSIZ + 5];        /* Send-packet buffer area */
  54. CHAR bigrbuf[BIGRBUFSIZ + 5];        /* Receive-packet area */
  55.  
  56. /* FUNCTIONS */
  57.  
  58. /* For sanity, use "i" for buffer slots, "n" for packet numbers. */
  59.  
  60.  
  61. /* M A K E B U F  --  Makes and clears a new buffers.  */
  62.  
  63. /* Call with: */
  64. /*  slots:  number of buffer slots to make, 1 to 31 */
  65. /*  bufsiz: size of the big buffer */
  66. /*  buf:    address of the big buffer */
  67. /*  xx:     pointer to array of pktinfo structures for these buffers */
  68.  
  69. /* Subdivides the big buffer into "slots" buffers. */
  70.  
  71. /* Returns: */
  72. /*  -1 if too many or too few slots requested,     */
  73. /*  -2 if slots would be too small.      */
  74. /*   n (positive) on success = size of one buffer. */
  75. /*   with pktinfo structure initialized for this set of buffers. */
  76.  
  77. makebuf(slots,bufsiz,buf,xx)
  78.     int slots, bufsiz; CHAR buf[]; struct pktinfo *xx; {
  79.  
  80.     CHAR *a;
  81.     int i, size;
  82.  
  83.     debug(F101,"makebuf","",slots);
  84.     debug(F101,"makebuf bufsiz","",bufsiz);
  85.     debug(F101,"makebuf MAXWS","",MAXWS);
  86.  
  87.     if (slots > MAXWS || slots < 1) return(-1);
  88.     if (bufsiz < slots * 10 ) return(-2);
  89.  
  90.     size = bufsiz / slots;        /* Divide up the big buffer. */
  91.     a = buf;                /* Address of first piece. */
  92.  
  93.     for (i = 0; i < slots; i++) {
  94.     struct pktinfo *x = &xx[i];
  95.     x->bf_adr = a;            /* Address of this buffer */
  96.     x->bf_len = size;        /* Length of this buffer */
  97.     x->pk_len = 0;            /* Length of data field */
  98.         x->pk_typ = ' ';        /* packet type */
  99.     x->pk_seq = -1;            /* packet sequence number */
  100.         x->pk_flg = 0;            /* ack'd bit */
  101.         x->pk_rtr = 0;            /* retransmissions */
  102.     *a = '\0';            /* Clear the buffer */
  103.     a += size;            /* Position to next buffer slot */
  104.     }
  105.     return(size);
  106. }
  107.  
  108. /*  M A K S B U F  --  Makes the send-packet buffer  */
  109.  
  110. mksbuf(slots) {
  111.     int i, x;
  112.     if ((x = makebuf(slots,BIGSBUFSIZ,bigsbuf,s_pkt)) < 0) {
  113.     debug(F101,"mksbuf makebuf return","",x);
  114.     return(x);
  115.     }
  116.     debug(F101,"mksbuf makebuf return","",x);
  117.     for (i = 0; i < 64; i++) {        /* Initialize sequence-number- */
  118.     sseqtbl[i] = -1;        /* to-buffer-number table. */
  119.     }
  120.     for (i = 0; i < MAXWS; i++)
  121.       sbufuse[i] = 0;            /* Mark each buffer as free */
  122.     sbufnum = slots;
  123.     return(x);
  124. }
  125.  
  126. /*  M A K R B U F  --  Makes the receive-packet buffer  */
  127.  
  128. mkrbuf(slots) {
  129.     int i, x;
  130.     if ((x = makebuf(slots,BIGRBUFSIZ,bigrbuf,r_pkt)) < 0) {
  131.     debug(F101,"mkrbuf makebuf return","",x);
  132.     return(x);
  133.     }
  134.     debug(F101,"mkrbuf makebuf return","",x);
  135.     for (i = 0; i < 64; i++) {        /* Initialize sequence-number- */
  136.     rseqtbl[i] = -1;        /* to-buffer-number table. */
  137.     }
  138.     for (i = 0; i < MAXWS; i++)
  139.       rbufuse[i] = 0;            /* Mark each buffer as free */
  140.     rbufnum = slots;
  141.     return(x);
  142. }
  143.  
  144. /*  W I N D O W  --  Resize the window to n  */
  145.  
  146. window(n) {
  147.     debug(F101,"window","",n);
  148.     if (n < 1 || n > 31) return(-1);
  149.     if (mksbuf(n) < 0) return(-1);
  150.     if (mkrbuf(n) < 0) return(-1);
  151.     wslots = n;
  152.     if (deblog) dumpsbuf(0,n);
  153.     if (deblog) dumprbuf(0,n);
  154.     return(0);
  155. }
  156.  
  157. /*  G E T S B U F  --  Allocate a send-buffer.  */
  158.  
  159. /*  Call with packet sequence number to allocate buffer for. */
  160. /*  Returns: */
  161. /*   -3 if buffers were thought to be available but really weren't (bug!) */
  162. /*   -2 if the number of free buffers is negative (bug!) */
  163. /*   -1 if no free buffers. */
  164. /*   0 or positive, packet sequence number, with buffer allocated for it. */
  165.  
  166. getsbuf(n) int n; {            /* Allocate a send-buffer */
  167.     int i;
  168.     if (sbufnum == 0) return(-1);    /* No free buffers. */
  169.     if (sbufnum < 0) return(-2);    /* Shouldn't happen. */
  170.     debug(F101,"getsbuf, packet","",n);
  171.     for (i = 0; i < wslots; i++)    /* Find the first one not in use. */
  172.       if (sbufuse[i] == 0) {        /* Got one? */
  173.       sbufuse[i] = 1;        /* Mark it as in use. */
  174.       sbufnum--;            /* One less free buffer. */
  175.       *s_pkt[i].bf_adr = '\0';    /* Zero the buffer data field */
  176.       s_pkt[i].pk_seq = n;        /* Put in the sequence number */
  177.           sseqtbl[n] = i;        /* Back pointer from sequence number */
  178.       s_pkt[i].pk_len = 0;        /* Data field length now zero. */
  179.       s_pkt[i].pk_typ = ' ';    /* Blank the packet type too. */
  180.       s_pkt[i].pk_flg = 0;        /* Zero the flags */
  181.       s_pkt[i].pk_rtr = 0;        /* Zero the retransmission count */
  182.       data = s_pkt[i].bf_adr + 7;    /* Set global "data" address. */
  183.       if (i+1 > wmax) wmax = i+1;    /* For statistics. */
  184.       return(n);            /* Return its index. */
  185.       }
  186.     sbufnum = 0;            /* Didn't find one. */
  187.     return(-3);                /* Shouldn't happen! */
  188. }
  189.  
  190. getrbuf() {                /* Allocate a receive buffer */
  191.     int i;
  192.     debug(F101,"getrbuf rbufnum","",rbufnum);
  193.     debug(F101,"getrbuf wslots","",wslots);
  194.     debug(F101,"getrbuf dum002","",dum002);
  195.     debug(F101,"getrbuf dum003","",dum003);
  196.     if (rbufnum == 0) return(-1);    /* No free buffers. */
  197.     if (rbufnum < 0) return(-2);    /* Shouldn't happen. */
  198.     for (i = 0; i < wslots; i++)    /* Find the first one not in use. */
  199.       if (rbufuse[i] == 0) {        /* Got one? */
  200.       rbufuse[i] = 1;        /* Mark it as in use. */
  201.       *r_pkt[i].bf_adr = '\0';    /* Zero the buffer data field */
  202.       rbufnum--;            /* One less free buffer. */
  203.       debug(F101,"getrbuf new rbufnum","",rbufnum);
  204.       if (i+1 > wmax) wmax = i+1;    /* For statistics. */
  205.       return(i);            /* Return its index. */
  206.       }
  207.     debug(F101,"getrbuf foulup","",i);
  208.     rbufnum = 0;            /* Didn't find one. */
  209.     return(-3);                /* Shouldn't happen! */
  210. }
  211.  
  212. /*  F R E E S B U F  --  Free send-buffer "i"  */
  213.  
  214. /*  Returns:  */
  215. /*   1 upon success  */
  216. /*  -1 if specified buffer does not exist */
  217.  
  218. freesbuf(n) int n; {            /* Release send-buffer for packet n. */
  219.     int i;
  220.  
  221.     debug(F101,"freesbuf","",n);
  222.     if (n < 0 || n > 63)        /* No such packet. */
  223.       return(-1);
  224.     i = sseqtbl[n];            /* Get the pktinfo struct index */
  225.     if (i > -1) {
  226.     sseqtbl[n] = -1;        /* If valid, remove from seqtbl */
  227.     if (sbufuse[i] != 0) {        /* If really allocated, */
  228.         sbufuse[i] = 0;        /* mark it as free, */
  229.         sbufnum++;            /* and count one more free buffer. */
  230.     }
  231.     } else {
  232.     debug(F101," sseqtbl[n]","",sseqtbl[n]);
  233.     return(-1);
  234.     }
  235.  
  236. /* The following is done only so dumped buffers will look right. */
  237.  
  238.     if (1) {
  239.     *s_pkt[i].bf_adr = '\0';    /* Zero the buffer data field */
  240.     s_pkt[i].pk_seq = -1;        /* Invalidate the sequence number */
  241.     s_pkt[i].pk_len = 0;        /* Data field length now zero. */
  242.     s_pkt[i].pk_typ = ' ';        /* Blank the packet type too. */
  243.     s_pkt[i].pk_flg = 0;        /* And zero the flag */
  244.     s_pkt[i].pk_rtr = 0;        /* And the retries field. */
  245.     }
  246.     return(1);
  247. }
  248.  
  249. freerbuf(i) int i; {            /* Release receive-buffer slot "i". */
  250.     int n;
  251.  
  252. /* NOTE !! Currently, this function frees the indicated buffer, but */
  253. /* does NOT erase the data.  The program counts on this.  Will find a */
  254. /* better way later.... */
  255.  
  256.     debug(F101,"freerbuf, slot","",i);
  257.     if (i < 0 || i >= wslots) {        /* No such slot. */
  258.     debug(F101,"freerbuf no such slot","",i);
  259.     return(-1);
  260.     }
  261.     n = r_pkt[i].pk_seq;        /* Get the packet sequence number */
  262.     debug(F101,"freerbuf, packet","",n);
  263.     if (n > -1) rseqtbl[n] = -1;    /* If valid, remove from seqtbl */
  264.     if (rbufuse[i] != 0) {        /* If really allocated, */
  265.     rbufuse[i] = 0;            /* mark it as free, */
  266.     rbufnum++;            /* and count one more free buffer. */
  267.     debug(F101,"freerbuf, new rbufnum","",rbufnum);
  268.     }
  269.  
  270. /* The following is done only so dumped buffers will look right. */
  271.  
  272.     if (1) {
  273.      /* *r_pkt[i].bf_adr = '\0'; */    /* Zero the buffer data field */
  274.     r_pkt[i].pk_seq = -1;        /* And from packet list */
  275.     r_pkt[i].pk_len = 0;        /* Data field length now zero. */
  276.     r_pkt[i].pk_typ = ' ';        /* Blank the packet type too. */
  277.     r_pkt[i].pk_flg = 0;        /* And zero the flag */
  278.     r_pkt[i].pk_rtr = 0;        /* And the retries field. */
  279.     }
  280.     return(1);
  281. }
  282.  
  283. /*  C H K W I N  --  Check if packet n is in window. */
  284.  
  285. /*  Returns: */
  286. /*    0 if it is in the current window,  */
  287. /*   +1 if in would have been in previous window (e.g. if ack was lost), */
  288. /*   -1 if it is outside any window (protocol error),   */
  289. /*   -2 if either of the argument packet numbers is out of range.  */
  290.  
  291. /* Call with packet number to check (n), lowest packet number in window */
  292. /* (bottom), and number of slots in window (slots).  */
  293.  
  294. chkwin(n,bottom,slots) int n, bottom, slots; {
  295.     int top, prev;
  296.  
  297.     debug(F101,"chkwin packet","",n);
  298.     debug(F101,"chkwin winlo","",bottom);
  299.     debug(F101,"chkwin slots","",slots);
  300.  
  301. /* First do the easy and common cases, where the windows are not split. */
  302.  
  303.     if (n < 0 || n > 63 || bottom < 0 || bottom > 63)
  304.       return(-2);
  305.  
  306.     top = bottom + slots;        /* Calculate window top. */
  307.     if (top < 64 && n < top && n >= bottom)
  308.       return(0);            /* In current window. */
  309.  
  310.     prev = bottom - slots;        /* Bottom of previous window. */
  311.     if (prev > -1 && n < bottom && n > prev)
  312.       return(1);            /* In previous. */
  313.  
  314. /* Now consider the case where the current window is split. */
  315.  
  316.     if (top > 63) {            /* Wraparound... */
  317.     top -= 64;            /* Get modulo-64 sequence number */
  318.     if (n < top || n >= bottom) {
  319.         return(0);            /* In current window. */
  320.     } else {            /* Not in current window. */
  321.         if (n < bottom && n >= prev) /* Previous window can't be split. */
  322.           return(1);        /* In previous window. */
  323.         else
  324.           return(-1);        /* Not in previous window. */
  325.     }
  326.     }
  327.  
  328. /* Now the case where current window not split, but previous window is. */ 
  329.  
  330.     if (prev < 0) {            /* Is previous window split? */
  331.     prev += 64;            /* Yes. */
  332.     if (n < bottom || n >= prev)
  333.       return(1);            /* In previous window. */
  334.     } else {                /* Previous window not split. */
  335.     if (n < bottom && n >= prev)
  336.       return(1);            /* In previous window. */
  337.     }
  338.     
  339. /* It's not in the current window, and not in the previous window... */
  340.  
  341.     return(-1);                /* So it's not in any window. */
  342. }
  343.  
  344. dumpsbuf() {                /* Dump send-buffers */
  345.     int j;
  346.  
  347.     if (! deblog) return(0);
  348.     zsoutl(ZDFILE,"SEND BUFFERS:");
  349.     zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
  350.  
  351.     for ( j = 0; j < wslots; j++ ) {
  352.     sprintf(xbuf,"%4d%6d%10d%5d%6d%4c%5d%5d%6d\n",
  353.            j,
  354.            sbufuse[j],
  355.            s_pkt[j].bf_adr, 
  356.            s_pkt[j].bf_len,
  357.            s_pkt[j].pk_len,
  358.            s_pkt[j].pk_typ,
  359.            s_pkt[j].pk_seq,
  360.            s_pkt[j].pk_flg,
  361.            s_pkt[j].pk_rtr
  362.            );
  363.     zsout(ZDFILE,xbuf);
  364.     sprintf(xbuf,"[%s]\n",s_pkt[j].pk_adr);
  365.     zsout(ZDFILE,xbuf);
  366.     }
  367.     sprintf(xbuf,"free: %d, winlo: %d\n", sbufnum, winlo);
  368.     zsout(ZDFILE,xbuf);
  369.     return(0);
  370. }
  371. dumprbuf() {                /* Dump receive-buffers */
  372.     int j;
  373.     if (! deblog) return(0);
  374.     zsoutl(ZDFILE,"RECEIVE BUFFERS:");
  375.     zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
  376.     for ( j = 0; j < wslots; j++ ) {
  377.     sprintf(xbuf,"%4d%6d%10d%5d%6d%4c%5d%5d%6d\n",
  378.            j,
  379.            rbufuse[j],
  380.            r_pkt[j].bf_adr, 
  381.            r_pkt[j].bf_len,
  382.            r_pkt[j].pk_len,
  383.            r_pkt[j].pk_typ,
  384.            r_pkt[j].pk_seq,
  385.            r_pkt[j].pk_flg,
  386.            r_pkt[j].pk_rtr
  387.            );
  388.     zsout(ZDFILE,xbuf);
  389.     sprintf(xbuf,"[%s]\n",r_pkt[j].bf_adr);
  390.     zsout(ZDFILE,xbuf);
  391.     }
  392.     sprintf(xbuf,"free: %d, winlo: %d\n", rbufnum, winlo);
  393.     zsout(ZDFILE,xbuf);
  394.     return(0);
  395. }
  396.  
  397. /*** Some misc functions also moved here from the other ckcfn*.c modules ***/
  398. /*** to even out the module sizes. ***/
  399.  
  400.  
  401. /* Attribute Packets. */
  402.  
  403. /*
  404.   Call with xp == 0 if we're sending a real file (F packet),
  405.   or xp != 0 for screen data (X packet).
  406.   Returns 0 on success, -1 on failure.
  407. */
  408. sattr(xp) int xp; {            /* Send Attributes */
  409.     int i, j, k, aln;
  410.     char *tp;
  411.     struct zattr x;
  412.  
  413.     if (zsattr(&x) < 0) return(-1);    /* Get attributes or die trying */
  414.     nxtpkt();                /* Next packet number */
  415.     i = 0;                /* i = Data field character number */
  416.     data[i++] = '.';            /* System type */
  417.     data[i++] = tochar(x.systemid.len); /*  Copy from attribute structure */
  418.     for (j = 0; j < x.systemid.len; j++)
  419.       data[i++] = x.systemid.val[j];
  420.     data[i++] = '"';            /* File type */
  421.     if (binary) {            /*  Binary  */
  422.     data[i++] = tochar(2);        /*  Two characters */
  423.     data[i++] = 'B';        /*  B for Binary */
  424.     data[i++] = '8';        /*  8-bit bytes (note assumption...) */
  425.     } else {                /* Text */
  426.     data[i++] = tochar(3);        /*  Three characters */
  427.     data[i++] = 'A';        /*  A = (extended) ASCII with CRLFs */
  428.     data[i++] = 'M';        /*  M for carriage return */
  429.     data[i++] = 'J';        /*  J for linefeed */
  430.     tp = tcsinfo[tcharset].designator; /* Transfer character set */
  431.     if ((tp != NULL) && (aln = strlen(tp)) > 0) {
  432.         data[i++] = '*';        /* Encoding */
  433.         data[i++] = tochar(aln+1);    /*  Length of char set designator. */
  434.         data[i++] = 'C';        /*  Text in specified character set. */
  435.         for (j = 0; j < aln; j++)    /*  Designator from tcsinfo struct */
  436.           data[i++] = *tp++;    /*  Example: *&I2/100 */
  437.     }
  438.     }
  439.     if ((xp == 0) && (x.length > -1L)) { /* If it's a real file */
  440.  
  441.     if ((aln = x.date.len) > 0) {    /* Creation date, if any */
  442.         data[i++] = '#';
  443.         data[i++] = tochar(aln);
  444.         for (j = 0; j < aln; j++)
  445.           data[i++] = x.date.val[j];
  446.     }
  447.     data[i] = '!';            /* File length in K */
  448.     sprintf(&data[i+2],"%ld",x.lengthk);
  449.     aln = strlen(&data[i+2]);
  450.     data[i+1] = tochar(aln);
  451.     i += aln + 2;
  452.  
  453.     data[i] = '1';            /* File length in bytes */
  454.     sprintf(&data[i+2],"%ld",fsize);
  455.     aln = strlen(&data[i+2]);
  456.     data[i+1] = tochar(aln);
  457.     i += aln + 2;
  458.     }
  459.     if (rprintf || rmailf) {        /* MAIL, or REMOTE PRINT?  */
  460.     data[i++] = '+';        /* Disposition */
  461.         data[i++] = tochar(strlen(optbuf) + 1); /* Options, if any */
  462.     if (rprintf)
  463.       data[i++] = 'P';        /* P for Print */
  464.     else
  465.       data[i++] = 'M';        /* M for Mail */
  466.     for (j = 0; optbuf[j]; j++)    /* Copy any options */
  467.       data[i++] = optbuf[j];
  468.     }
  469.     data[i] = '\0';            /* Make sure it's null-terminated */
  470.     aln = strlen(data);            /* Get overall length of attributes */
  471.     if (aln > spsiz) {            /* Check length of result */
  472.     spack('A',pktnum,"",0);        /* send an empty attribute packet */
  473.     debug(F101,"sattr pkt too long","",aln); /* if too long */
  474.     debug(F101,"sattr spsiz","",spsiz);
  475.     } else {                /* Otherwise */
  476.     spack('A',pktnum,aln,data);    /* send the real thing. */
  477.     debug(F111,"sattr",data,aln);
  478.     }
  479.     /* Change this code to break attribute data up into multiple packets! */
  480.     return(0);
  481. }
  482.  
  483. rsattr(s) char *s; {            /* Read response to attribute packet */
  484.     debug(F111,"rsattr: ",s,*s);    /* If it's 'N' followed by anything */
  485.     if (*s == 'N') return(-1);        /* then other Kermit is refusing. */
  486.     return(0);
  487. }
  488.  
  489. gattr(s, yy) char *s; struct zattr *yy;{ /* Read incoming attribute packet */
  490.     char c;
  491.     int aln, i, x;
  492.     long l;
  493. #define ABUFL 100            /* Temporary buffer for conversions */
  494.     char abuf[ABUFL];
  495. #define FTBUFL 10            /* File type buffer */
  496.     static char ftbuf[FTBUFL];
  497. #define DTBUFL 24            /* File creation date */
  498.     static char dtbuf[DTBUFL];
  499. #define TSBUFL 10            /* Transfer syntax */
  500.     static char tsbuf[TSBUFL];
  501. #define IDBUFL 10            /* System ID */
  502.     static char idbuf[IDBUFL];
  503. #define DSBUFL 100            /* Disposition */
  504.     static char dsbuf[DSBUFL];
  505. #define SPBUFL 512            /* System-dependent parameters */
  506.     static char spbuf[SPBUFL];
  507. #define CSBUFL 10            /* Transfer syntax character set */
  508.     static char csbuf[CSBUFL];
  509. #define RPBUFL 20            /* Attribute reply */
  510.     static char rpbuf[RPBUFL];
  511.  
  512.     char *rp;                /* Pointer to reply buffer */
  513.     int retcode;            /* Return code */
  514.  
  515. /* fill in the attributes we have received */
  516.  
  517.     rp = rpbuf;                /* Initialize reply buffer */
  518.     *rp++ = 'N';            /* for negative reply. */
  519.     retcode = 0;            /* Initialize return code. */
  520.  
  521.     while (c = *s++) {            /* Get attribute tag */
  522.     aln = xunchar(*s++);        /* Length of attribute string */
  523.     switch (c) {
  524.       case '!':            /* file length in K */
  525.             /* It would be nice to be able to refuse a file that was */
  526.         /* bigger than the available disk space, but the method for */
  527.         /* finding this out in Unix is not obvious... */
  528.         for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
  529.           abuf[i] = *s++;
  530.         abuf[i] = '\0';        /* Terminate with null */
  531.         yy->lengthk = atol(abuf);    /* Convert to number */
  532.         break;
  533.  
  534.       case '"':            /* file type */
  535.         for (i = 0; (i < aln) && (i < FTBUFL); i++)
  536.           ftbuf[i] = *s++;        /* Copy it into a static string */
  537.         ftbuf[i] = '\0';
  538.         yy->type.val = ftbuf;    /* Pointer to string */
  539.         yy->type.len = i;        /* Length of string */
  540.         debug(F101,"gattr file type",tsbuf,i);
  541.         if (*ftbuf != 'A' && *ftbuf != 'B') { /* Reject unknown types */
  542.         retcode = -1;
  543.         *rp++ = c;
  544.         }        
  545.         break;
  546.  
  547.       case '#':            /* file creation date */
  548.         for (i = 0; (i < aln) && (i < DTBUFL); i++)
  549.           dtbuf[i] = *s++;        /* Copy it into a static string */
  550.         dtbuf[i] = '\0';
  551.         yy->date.val = dtbuf;    /* Pointer to string */
  552.         yy->date.len = i;        /* Length of string */
  553.         break;
  554.  
  555.       case '*':            /* encoding (transfer syntax) */
  556.         for (i = 0; (i < aln) && (i < TSBUFL); i++)
  557.           tsbuf[i] = *s++;        /* Copy it into a static string */
  558.         tsbuf[i] = '\0';
  559.         yy->encoding.val = tsbuf;    /* Pointer to string */
  560.         yy->encoding.len = i;    /* Length of string */
  561.         debug(F101,"gattr encoding",tsbuf,i);
  562.         switch (*tsbuf) {
  563.           case 'A':            /* Normal (maybe extended) ASCII */
  564.         tcharset = TC_USASCII;  /* Transparent, chars untranslated */
  565.         break;
  566.           case 'C':            /* Specified character set */
  567.         for (i = 0; i < ntcsets; i++) { 
  568.             if (!strcmp(tcsinfo[i].designator,tsbuf+1)) break;
  569.         }
  570.         debug(F101,"gattr xfer charset lookup","",i);
  571.         if (i == ntcsets) {    /* If unknown character set, */
  572.             debug(F110,"gattr: xfer charset unknown",tsbuf+1,0);
  573.             if (!unkcs) {    /* and SET UNKNOWN DISCARD, */
  574.             retcode = -1;    /* reject the file. */
  575.             *rp++ = c;
  576.             }
  577.         } else {
  578.             tcharset = tcsinfo[i].code;   /* if known, use it */
  579.             rx = xlr[tcharset][fcharset]; /* translation function */
  580.         }
  581.         debug(F101,"gattr tcharset","",tcharset);
  582.         break;
  583.           default:            /* Something else. */
  584.         debug(F110,"gattr unk encoding attribute",tsbuf,0);
  585.         if (!unkcs) {        /* If SET UNK DISC */
  586.             retcode = -1;    /* reject the file */
  587.             *rp++ = c;
  588.         }
  589.         break;
  590.         }
  591.         break;
  592.  
  593.       case '+':            /* disposition */
  594.         for (i = 0; (i < aln) && (i < DSBUFL); i++)
  595.           dsbuf[i] = *s++;        /* Copy it into a static string */
  596.         dsbuf[i] = '\0';
  597.         yy->disp.val = dsbuf;    /* Pointer to string */
  598.         yy->disp.len = i;        /* Length of string */
  599.         if (*dsbuf != 'M' && *dsbuf != 'P') {
  600.         retcode = -1;
  601.         *rp++ = c;
  602.         }
  603.         break;
  604.  
  605.       case '.':            /* sender's system ID */
  606.         for (i = 0; (i < aln) && (i < IDBUFL); i++)
  607.           idbuf[i] = *s++;        /* Copy it into a static string */
  608.         idbuf[i] = '\0';
  609.         yy->systemid.val = idbuf;    /* Pointer to string */
  610.         yy->systemid.len = i;    /* Length of string */
  611.         break;
  612.  
  613.       case '0':            /* system-dependent parameters */
  614.         for (i = 0; (i < aln) && (i < SPBUFL); i++)
  615.           spbuf[i] = *s++;        /* Copy it into a static string */
  616.         spbuf[i] = '\0';
  617.         yy->sysparam.val = spbuf;    /* Pointer to string */
  618.         yy->sysparam.len = i;    /* Length of string */
  619.         break;
  620.  
  621.       case '1':            /* file length in bytes */
  622.             /* It would be nice to be able to refuse a file that was */
  623.         /* bigger than the available disk space, but the method for */
  624.         /* finding this out in Unix is not obvious... */
  625.         for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
  626.           abuf[i] = *s++;
  627.         abuf[i] = '\0';        /* Terminate with null */
  628.         yy->length = atol(abuf);    /* Convert to number */
  629.         debug(F101,"gattr length","",(int) yy->length);
  630.         break;
  631.  
  632.       default:            /* Unknown attribute */
  633.         s += aln;            /* Just skip past it */
  634.         break;
  635.     }
  636.     }
  637.  
  638.     /* (PWP) show the info */
  639.     if (yy->length > 0) {        /* Let the user know the size */
  640.     fsize = yy->length;        
  641.     screen(SCR_QE,0,fsize," Size");
  642.     } else if (yy->lengthk > 0) {
  643.     fsize = yy->lengthk * 1024L;
  644.     screen(SCR_QE,0,fsize," Size");
  645.     }
  646. #ifdef CHECK_SIZE            /* PWP code not used (maybe on Mac) */
  647.     if ((l > 0) && ( l > zfree(filnam))) {
  648.     cxseen = 1 ;     /* Set to true so file will be deleted */
  649.     return(-1);    /* can't accept file */
  650.     }
  651. #endif
  652.     if (retcode == 0) rp = rpbuf;    /* Null reply string if accepted */
  653.     *rp = '\0';                /* End of reply string */
  654.     yy->reply.val = rpbuf;        /* Add it to attribute structure */
  655.     yy->reply.len = strlen(rpbuf);
  656.     debug(F111,"gattr",rpbuf,retcode);
  657.     return(retcode);
  658. }
  659.  
  660. /*  I N I T A T T R  --  Initialize file attribute structure  */
  661.  
  662. initattr(yy) struct zattr *yy; {
  663.     yy->lengthk = -1L;
  664.     yy->type.val = "";
  665.     yy->type.len = 0;
  666.     yy->date.val = "";
  667.     yy->date.len = 0;
  668.     yy->encoding.val = "";
  669.     yy->encoding.len = 0;
  670.     yy->disp.val = "";
  671.     yy->disp.len = 0;
  672.     yy->systemid.val = "";
  673.     yy->systemid.len = 0;
  674.     yy->sysparam.val = "";
  675.     yy->sysparam.len = 0;
  676.     yy->creator.val = "";
  677.     yy->creator.len = 0;
  678.     yy->account.val = "";
  679.     yy->account.len = 0;
  680.     yy->area.val = "";
  681.     yy->area.len = 0;
  682.     yy->passwd.val = "";
  683.     yy->passwd.len = 0;
  684.     yy->blksize = -1L;
  685.     yy->access.val = "";
  686.     yy->access.len = 0;
  687.     yy->lprotect.val = "";
  688.     yy->lprotect.len = 0;
  689.     yy->gprotect.val = "";
  690.     yy->gprotect.len = 0;
  691.     yy->recfm.val = "";
  692.     yy->recfm.len = 0;
  693.     yy->reply.val = "";
  694.     yy->reply.len = 0;
  695.     return(0);
  696. }
  697.  
  698. /*  A D E B U -- Write attribute packet info to debug log  */
  699.  
  700. adebu(f,zz) char *f; struct zattr *zz; {
  701. #ifdef DEBUG
  702.     if (deblog == 0) return(0);
  703.     debug(F110,"Attributes for incoming file ",f,0);
  704.     debug(F101," length in K","",(int) zz->lengthk);
  705.     debug(F111," file type",zz->type.val,zz->type.len);
  706.     debug(F111," creation date",zz->date.val,zz->date.len);
  707.     debug(F111," creator",zz->creator.val,zz->creator.len);
  708.     debug(F111," account",zz->account.val,zz->account.len);
  709.     debug(F111," area",zz->area.val,zz->area.len);
  710.     debug(F111," password",zz->passwd.val,zz->passwd.len);
  711.     debug(F101," blksize",(int) zz->blksize,0);
  712.     debug(F111," access",zz->access.val,zz->access.len);
  713.     debug(F111," encoding",zz->encoding.val,zz->encoding.len);
  714.     debug(F111," disposition",zz->disp.val,zz->disp.len);
  715.     debug(F111," lprotection",zz->lprotect.val,zz->lprotect.len);
  716.     debug(F111," gprotection",zz->gprotect.val,zz->gprotect.len);
  717.     debug(F111," systemid",zz->systemid.val,zz->systemid.len);
  718.     debug(F111," recfm",zz->recfm.val,zz->recfm.len);
  719.     debug(F111," sysparam",zz->sysparam.val,zz->sysparam.len);
  720.     debug(F101," length","",(int) zz->length);
  721.     debug(F110," reply",zz->reply.val,0);
  722. #endif /* DEBUG */
  723.     return(0);
  724. }
  725.  
  726. /*  O P E N A -- Open a file, with attributes.  */
  727. /*
  728.   This function tries to open a new file to put the arriving data in.
  729.   The filename is the one in the srvcmd buffer.  If warning is on and
  730.   a file of that name already exists, then a unique name is chosen.
  731. */
  732. opena(f,zz) char *f; struct zattr *zz; {
  733.     int x;
  734.  
  735.     adebu(f,zz);            /* Write attributes to debug log */
  736.  
  737.     ffc = 0;                /* Init file character counter */
  738.  
  739.     if (bsavef) {            /* If somehow file mode */
  740.     binary = bsave;            /* was saved but not restored, */
  741.     bsavef = 0;            /* restore it. */
  742.     debug(F101,"opena restoring binary","",binary);
  743.     }
  744.     if (x = openo(f,zz)) {        /* Try to open the file. */
  745.     tlog(F110," as",f,0l);        /* OK, open, record name. */
  746.     if (zz->type.val[0] == 'A') {    /* Check attributes */
  747.         bsave = binary;        /* Save global file type */
  748.         bsavef = 1;            /* ( restore it in clsof() ) */
  749.         binary = 0;
  750.         debug(F100,"opena attribute A = text","",binary);
  751.     } else if (zz->type.val[0] == 'B') {
  752.         bsave = binary;        /* Save global file type */
  753.         bsavef = 1;
  754.         binary = 1;
  755.         debug(F100,"opena attribute B = binary","",binary);
  756.     }
  757.     if (binary) {            /* Log file mode in transaction log */
  758.         tlog(F100," mode: binary","",0l);
  759.     } else {            /* If text mode, check character set */
  760.         tlog(F100," mode: text","",0l);
  761.         debug(F111," opena charset",zz->encoding.val,zz->encoding.len);
  762.     }
  763.     screen(SCR_AN,0,0l,f);
  764.     intmsg(filcnt);
  765.  
  766. #ifdef datageneral
  767. /* Need to turn on multi-tasking console interrupt task here, since multiple */
  768. /* files may be received. */
  769.         if ((local) && (!quiet))        /* Only do this if local & not quiet */
  770.             consta_mt();                /* Start the asynch read task */
  771. #endif
  772.  
  773.     } else {                /* Did not open file OK. */
  774.         tlog(F110,"Failure to open",f,0l);
  775.     screen(SCR_EM,0,0l,"Can't open file");
  776.     }
  777.     return(x);                /* Pass on return code from openo */
  778. }
  779.  
  780. /*  C A N N E D  --  Check if current file transfer cancelled */
  781.  
  782. canned(buf) char *buf; {
  783.     if (*buf == 'X') cxseen = 1;
  784.     if (*buf == 'Z') czseen = 1;
  785.     debug(F101,"canned: cxseen","",cxseen);
  786.     debug(F101," czseen","",czseen);
  787.     return((czseen || cxseen) ? 1 : 0);
  788. }
  789.  
  790.  
  791. /*  O P E N I  --  Open an existing file for input  */
  792.  
  793. openi(name) char *name; {
  794.     int x, filno;
  795.     if (memstr) return(1);        /* Just return if file is memory. */
  796.  
  797.     debug(F110,"openi",name,0);
  798.     debug(F101," sndsrc","",sndsrc);
  799.  
  800.     filno = (sndsrc == 0) ? ZSTDIO : ZIFILE;    /* ... */
  801.  
  802.     debug(F101," file number","",filno);
  803.  
  804.     if (zopeni(filno,name)) {        /* Otherwise, try to open it. */
  805.     debug(F110," ok",name,0);
  806.         return(1);
  807.     } else {                /* If not found, */
  808.     char xname[100];        /* convert the name */
  809.     zrtol(name,xname);        /* to local form and then */
  810.     x = zopeni(filno,xname);    /* try opening it again. */
  811.     debug(F101," zopeni","",x);
  812.     if (x) {
  813.         debug(F110," ok",xname,0);
  814.         return(1);            /* It worked. */
  815.         } else {
  816.         screen(SCR_EM,0,0l,"Can't open file");  /* It didn't work. */
  817.         tlog(F110,xname,"could not be opened",0l);
  818.         debug(F110," openi failed",xname,0);
  819.         return(0);
  820.         }
  821.     }
  822. }
  823.  
  824. /*  O P E N O  --  Open a new file for output.  */
  825.  
  826. /*  Returns actual name under which the file was opened in string 'name2'. */
  827.  
  828. openo(name,zz) char *name; struct zattr *zz; {
  829.  
  830.     if (stdouf)                /* Receiving to stdout? */
  831.     return(zopeno(ZSTDIO,"",zz));
  832.  
  833.     debug(F110,"openo: name",name,0);
  834.  
  835.     if (cxseen || czseen) {        /* If interrupted, get out before */
  836.     debug(F100," open cancelled","",0); /* destroying existing file. */
  837.     return(1);            /* Pretend to succeed. */
  838.     }
  839.     if (zopeno(ZOFILE,name,zz) == 0) {    /* Try to open the file */
  840.     debug(F110,"openo failed",name,0);
  841.     tlog(F110,"Failure to open",name,0l);
  842.     return(0);
  843.     } else {
  844.     debug(F110,"openo ok, name",name,0);
  845.     return(1);
  846.     }
  847. }
  848.  
  849. /*  O P E N T  --  Open the terminal for output, in place of a file  */
  850.  
  851. opent(zz) struct zattr *zz; {
  852.     ffc = tfc = 0;
  853.     return(zopeno(ZCTERM,"",zz));
  854. }
  855.  
  856. /*  C L S I F  --  Close the current input file. */
  857.  
  858. clsif() {
  859. #ifdef datageneral
  860.     if ((local) && (!quiet))    /* Only do this if local & not quiet */
  861.         if (nfils < 1)          /* More files to send ... leave it on! */
  862.             connoi_mt();
  863. #endif
  864.     if (memstr) {            /* If input was memory string, */
  865.     memstr = 0;            /* indicate no more. */
  866.     } else zclose(ZIFILE);        /* else close input file. */
  867.  
  868.     if (czseen || cxseen) 
  869.         screen(SCR_ST,ST_DISC,0l,"");
  870.     else
  871.         screen(SCR_ST,ST_OK,0l,"");
  872.     hcflg = 0;                /* Reset flags, */
  873.     *filnam = '\0';            /* and current file name */
  874.     n_len = -1;           /* (pwp) reinit packet encode-ahead length */
  875. }
  876.  
  877.  
  878. /*  C L S O F  --  Close an output file.  */
  879.  
  880. /*  Call with disp != 0 if file is to be discarded.  */
  881. /*  Returns -1 upon failure to close, 0 or greater on success. */
  882.  
  883. clsof(disp) int disp; {
  884.     int x;
  885.  
  886.     if (bsavef) {            /* If we saved global file type */
  887.     debug(F101,"clsof restoring binary","",binary);
  888.     binary = bsave;            /* restore it */
  889.     bsavef = 0;            /* only this once. */
  890.     }
  891. #ifdef datageneral
  892.     if ((local) && (!quiet))        /* Only do this if local & not quiet */
  893.         connoi_mt();
  894. #endif
  895.     if ((x = zclose(ZOFILE)) < 0) {    /* Try to close the file */
  896.     tlog(F100,"Failure to close",filnam,0l);
  897.     screen(SCR_ST,ST_ERR,0l,"");
  898.     } else if (disp && (keep == 0)) {    /* Delete it if interrupted, */
  899.     if (*filnam) zdelet(filnam);    /* and not keeping incomplete files */
  900.     debug(F100,"Discarded","",0);
  901.     tlog(F100,"Discarded","",0l);
  902.     screen(SCR_ST,ST_DISC,0l,"");
  903.     } else {                /* Nothing wrong, just keep it */
  904.     debug(F100,"Closed","",0);    /* and give comforting messages. */
  905.     screen(SCR_ST,ST_OK,0l,"");
  906.     }
  907.     return(x);                /* Send back zclose() return code. */
  908. }
  909.  
  910.