home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / trn_12.zip / src / uudecode.c < prev   
C/C++ Source or Header  |  1993-12-04  |  11KB  |  491 lines

  1. /* $Id: uudecode.c,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
  2.  *
  3.  * $Log: uudecode.c,v $
  4.  * Revision 4.4.3.1  1992/02/01  03:09:32  sob
  5.  * Release 4.4 Patchlevel 3
  6.  *
  7.  * Revision 4.4.2.1  1991/12/01  18:05:42  sob
  8.  * Patchlevel 2 changes
  9.  *
  10.  * Revision 4.4  1991/09/09  20:27:37  sob
  11.  * release 4.4
  12.  *
  13.  * 
  14.  * Decode one or more uuencoded articles back to binary form.
  15.  * Adapted to rn 4.4 by Stan Barber
  16.  * Trn version created by Wayne Davison.
  17.  * Adapted from the nn version by Kim Storm.
  18.  * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
  19.  */
  20. /*
  21.  * This software is Copyright 1991 by Stan Barber. 
  22.  *
  23.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  24.  * use this software as long as: there is no monetary profit gained
  25.  * specifically from the use or reproduction of this software, it is not
  26.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  27.  * included prominently in any copy made. 
  28.  *
  29.  * The author make no claims as to the fitness or correctness of this software
  30.  * for any use whatsoever, and it is provided as is. Any use of this software
  31.  * is at the user's own risk. 
  32.  */
  33.  
  34. #include "EXTERN.h"
  35. #include "common.h"
  36. #include "respond.h"
  37. #include "decode.h"
  38.  
  39. #define MAXCHAR 256
  40. #define NORMLEN 64    /* allows for 84 encoded chars per line */
  41.  
  42. #define SEQMAX 'z'
  43. #define SEQMIN 'a'
  44.  
  45. static char seqc;
  46. static int first, secnd, check, numl;
  47.  
  48. static char blank;
  49. static int chtbl[MAXCHAR], cdlen[NORMLEN + 3];
  50. static int state;
  51. static bool Xflag;
  52. static int expecting_part;
  53.  
  54. static int decode_line ANSI((char *));
  55. static void inittbls ANSI((void));
  56. static void gettable ANSI((FILE *));
  57.  
  58. #define    NO_ADVANCE        0x10
  59.  
  60. #define    FIND_BEGIN        0x01
  61. #define    AFTER_ERROR_FIND_BEGIN    0x02
  62. #define    DECODE_TEXT        0x03
  63. #define    SKIP_TRAILING           (0x04 | NO_ADVANCE)
  64. #define    SKIP_LEADING        0x05
  65. #define    FOUND_END           (0x06 | NO_ADVANCE)
  66. #define DECODE_ERROR           (0x07 | NO_ADVANCE)
  67. #define OTHER_ERROR           (0x08 | NO_ADVANCE)
  68. #define NEW_BEGIN           (0x09 | NO_ADVANCE)
  69.  
  70. void
  71. uud_start()
  72. {
  73.     Xflag = FALSE;
  74.     expecting_part = 0;
  75.     seqc = SEQMAX;
  76.     check = 1;
  77.     first = 1;
  78.     secnd = 0;
  79.     state = FIND_BEGIN;
  80. }
  81.  
  82. int
  83. uudecode(in)
  84. FILE *in;
  85. {
  86.     int mode, onedone, lens;
  87.     char buff[LBUFLEN];
  88.     int counter;    /** OS2-patch **/
  89.  
  90.     numl = onedone = 0;
  91.  
  92.     if (state == FIND_BEGIN)
  93.     inittbls();
  94.  
  95.     /*
  96.      * search for header or translation table line.
  97.      */
  98.  
  99.     while ((state & NO_ADVANCE) || fgets(buff, sizeof buff, in) != Nullch) {
  100.  
  101. /*** OS2: AAAAAAAAHHHHHHHHHHHH, ..... another problem with \r (^M)... **/
  102.  
  103.     for (counter = 0; counter <= strlen(buff); counter++)
  104.         if ((buff[counter] == '\r') &&
  105.             (buff[counter+1] == '\n')) {
  106.             for (; buff[counter] != '\0'; counter++)
  107.                 buff[counter] = buff[counter+1];
  108.         }
  109.  
  110.     numl++;
  111.  
  112.     switch (state) {
  113.      case NEW_BEGIN:
  114.         if (decode_fp != Nullfp) {
  115.         if (expecting_part) {
  116.             register int got_part = 0;
  117.  
  118.             if (strnEQ(buff + 6, "part ", 5)) {
  119.             register char *bp;
  120.  
  121.             for (bp = buff + 11; islower(*bp); bp++)
  122.                 got_part = got_part * 26 + *bp - 'a';
  123.             }
  124.             if (expecting_part == got_part) {
  125.             state = DECODE_TEXT;
  126.             break;
  127.             }
  128.             printf("Expecting part %d; got part %d.\n",
  129.              expecting_part + 1, got_part + 1);
  130.             if (got_part) {
  131.             state = SKIP_LEADING;
  132.             return -1;
  133.             }
  134.         }
  135.         decode_end();
  136.         sleep(2);
  137.         Xflag = FALSE;
  138.         expecting_part = 0;
  139.         }
  140.         state = FIND_BEGIN;
  141.         /* fall thru */
  142.  
  143.      case FIND_BEGIN:
  144.      case AFTER_ERROR_FIND_BEGIN:
  145.         if (strnEQ(buff, "table", 5)) {
  146.         gettable(in);
  147.         continue;
  148.         }
  149.  
  150.         if (strnEQ(buff, "begin ", 6)
  151.          || strnEQ(buff, "Xbegin ", 7)) {
  152.         lens = strlen(buff)-1;
  153.         if (buff[lens] == '\n')
  154.             buff[lens] = '\0';
  155.  
  156.         if(sscanf(buff+6,"%o%s", &mode, decode_fname) != 2) {
  157.             register char *bp = buff + 6;
  158.  
  159.             if (*bp == ' ')
  160.             bp++;
  161.             if (strnEQ(bp, "part ", 5)) {
  162.             register int got_part = 0;
  163.  
  164.             for (bp = bp + 5; islower(*bp); bp++)
  165.                 got_part = got_part * 26 + *bp - 'a';
  166.             printf("Expecting part 1; got part %d.\n",
  167.                 got_part + 1);
  168.             return -1;
  169.             }
  170.             continue;
  171.         }
  172.  
  173.         Xflag = (*buff == 'X');
  174.  
  175.         sprintf(decode_dest, "%s/%s", extractdest, decode_fname);
  176.  
  177.         if ((decode_fp = fos2open(decode_dest, FOPEN_WB)) == Nullfp) {
  178.             printf("Cannot create file: %s\n", decode_dest);
  179.             goto err;
  180.         }
  181.         chmod(decode_dest, mode);
  182.         printf("Decoding: %s\n", decode_fname);
  183.         state = DECODE_TEXT;
  184.         }
  185.         continue;
  186.  
  187.      case SKIP_LEADING:
  188.         state = decode_line(buff);
  189.         continue;
  190.  
  191.      case DECODE_TEXT:
  192.         state = decode_line(buff);
  193.         onedone = 1;
  194.         continue;
  195.  
  196.      case FOUND_END:
  197.         fclose(decode_fp);
  198.         decode_fp = Nullfp;
  199.         Xflag = FALSE;
  200.         expecting_part = 0;
  201.         state = FIND_BEGIN;
  202.         printf("Done.\n");
  203.         continue;
  204.  
  205.      case SKIP_TRAILING:
  206.         printf("(Continued)\n");
  207.         state = SKIP_LEADING;
  208.         return 0;
  209.  
  210.      case DECODE_ERROR:
  211.         state = SKIP_TRAILING;
  212.         continue;
  213.  
  214.      case OTHER_ERROR:
  215.         fclose(decode_fp);
  216.         decode_fp = Nullfp;
  217.         Xflag = FALSE;
  218.         expecting_part = 0;
  219.         state = AFTER_ERROR_FIND_BEGIN;
  220.         goto err;
  221.     }
  222.     }
  223.  
  224.     if (onedone) {
  225.     if (state == DECODE_TEXT) {
  226.         printf("(Continued)\n");
  227.         state = SKIP_LEADING;
  228.     }
  229.     return 0;
  230.     }
  231.  
  232.     if (state == AFTER_ERROR_FIND_BEGIN)
  233.     return -1;
  234.     printf("Couldn't find anything to decode.\n");
  235.  
  236.  err:
  237.     sleep(2);
  238.     return -1;
  239. }
  240.  
  241. /*
  242.  * decode one line and write it out using decode_fp
  243.  */
  244.  
  245. static int
  246. decode_line(buff)
  247. char *buff;
  248. {
  249.     char outl[LBUFLEN];
  250.     register char *bp, *ut;
  251.     register int *trtbl = chtbl;
  252.     register int n;
  253.     register int blen;        /* binary length (from decoded file) */
  254.     register int rlen;        /* calculated input line length */
  255.     register int len;        /* actual input line length */
  256.     register int dash;        /* number of '-'s encountered on a line */
  257.                 /* If it's too high, we reject the line */
  258.  
  259. #   define REJECT(buf,rlen,len) /* Comment for makedepend to     \
  260.                 ** ignore the backslash above */ \
  261.     ((*buf == 'M' && len > rlen + 5) \
  262.      || (*buf != 'M' && len != rlen && len != rlen+1) \
  263.      || (strnEQ(buf, "BEGIN", 5)) \
  264.      || (strnEQ(buf, "END", 3)))
  265.  
  266.     if (Xflag) {
  267.     if (*buff == 'X')
  268.         buff++;
  269.     else
  270.         *buff = 'x';    /* force a mis-parse of a non-x'ed line */
  271.     }
  272.     len = strlen(buff);
  273.     if (--len <= 0)
  274.     return state;
  275.  
  276.     buff[len] = '\0';
  277.  
  278.     /*
  279.      * Get the binary line length.
  280.      */
  281.     if ((blen = trtbl[buff[0]]) < 0) {
  282.     if (state == SKIP_LEADING) {
  283.         if (strnEQ(buff, "begin ", 6))
  284.         return NEW_BEGIN;
  285.  
  286.         return SKIP_LEADING;
  287.     }
  288.     /*
  289.      * end of uuencoded file ?
  290.      */
  291.     if (strnEQ(buff, "end", 3))
  292.         return FOUND_END;
  293.  
  294.     /*
  295.      * end of current file ? : get next one.
  296.      */
  297.     if (strnEQ(buff, "include ", 8)) {
  298.         for (bp = buff + 8; *bp; bp++) {
  299.         if (bp[0] == '.' && bp[1] == 'u') {
  300.             expecting_part = (bp[2] - 'a') * 26 + bp[3] - 'a';
  301.             break;
  302.         }
  303.         }
  304.     }
  305.  
  306.     /*
  307.      * trailing garbage
  308.      */
  309.     return SKIP_TRAILING;
  310.     }
  311.  
  312.     rlen = cdlen[blen];
  313.     if (state == SKIP_LEADING && REJECT(buff,rlen,len))
  314.     return SKIP_LEADING;
  315.  
  316.     /*
  317.      * Is it the empty line before the end line ?
  318.      */
  319.     if (blen == 0)
  320.     return state;
  321.  
  322.     if (REJECT(buff,rlen,len))
  323.     return SKIP_TRAILING;
  324.  
  325.     /*
  326.      * Pad with blanks.
  327.      */
  328.     for (bp = buff + len, n = rlen - len; --n >= 0; )
  329.     *bp++ = blank;
  330.  
  331.     /*
  332.      * Verify
  333.      */
  334.     for (n = rlen, bp = buff, dash = 0; --n >= 0; bp++) {
  335.     if (trtbl[*bp] < 0) {
  336.         if (state == SKIP_LEADING)
  337.         return SKIP_LEADING;
  338.         return DECODE_ERROR;
  339.     }
  340.     if (*bp == '-')
  341.         dash++;
  342.     }
  343.     if (dash * 100 / rlen > 33)        /* more than 1/3 dashes? */
  344.     if (state == SKIP_LEADING)
  345.         return SKIP_LEADING;    /* -> reject */
  346.     else
  347.         return SKIP_TRAILING;
  348.  
  349.     /*
  350.      * Check for uuencodes that append a 'z' to each line....
  351.      */
  352.     if (check)
  353.     if (secnd) {
  354.         secnd = 0;
  355.         if (buff[rlen] == SEQMAX)
  356.         check = 0;
  357.     } else if (first) {
  358.         first = 0;
  359.         secnd = 1;
  360.         if (buff[rlen] != SEQMAX)
  361.         check = 0;
  362.     }
  363.  
  364.     /*
  365.      * There we check.
  366.      */
  367.     if (check) {
  368.     if (buff[rlen] != seqc) {
  369.         if (state == SKIP_LEADING)
  370.         return SKIP_LEADING;
  371.         return DECODE_ERROR;
  372.     }
  373.  
  374.     if (--seqc < SEQMIN)
  375.         seqc = SEQMAX;
  376.     }
  377.  
  378.     /*
  379.      * output a group of 3 bytes (4 input characters).
  380.      * the input chars are pointed to by p, they are to
  381.      * be output to file f. blen is used to tell us not to
  382.      * output all of them at the end of the file.
  383.      */
  384.     ut = outl;
  385.     n = blen;
  386.     bp = &buff[1];
  387.     while (--n >= 0) {
  388.     *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
  389.     if (n > 0) {
  390.         *(ut++) = (trtbl[bp[1]] << 4) | (trtbl[bp[2]] >> 2);
  391.         n--;
  392.     }
  393.     if (n > 0) {
  394.         *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
  395.         n--;
  396.     }
  397.     bp += 4;
  398.     }
  399.     if (fwrite(outl, 1, blen, decode_fp) <= 0) {
  400.     printf("Error on writing decoded file\n");
  401.     return OTHER_ERROR;
  402.     }
  403.  
  404.     return DECODE_TEXT;
  405. }
  406.  
  407.  
  408.  
  409. /*
  410.  * Install the table in memory for later use.
  411.  */
  412. static void
  413. inittbls()
  414. {
  415.     register int i, j;
  416.  
  417.     /*
  418.      * Set up the default translation table.
  419.      */
  420.     for (i = 0; i < ' '; i++)
  421.     chtbl[i] = -1;
  422.     for (i = ' ', j = 0; i < ' ' + 64; i++, j++)
  423.     chtbl[i] = j;
  424.     for (i = ' ' + 64; i < MAXCHAR; i++)
  425.     chtbl[i] = -1;
  426.     chtbl['`'] = chtbl[' '];    /* common mutation */
  427.     chtbl['~'] = chtbl['^'];    /* another common mutation */
  428.     blank = ' ';
  429.     /*
  430.      * set up the line length table, to avoid computing lotsa * and / ...
  431.      */
  432.     cdlen[0] = 1;
  433.     for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
  434.     cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
  435. }
  436.  
  437. static void
  438. gettable(in)
  439. FILE *in;
  440. {
  441.     char buff[LBUFLEN];
  442.     register int c, n = 0;
  443.     register char *cpt;
  444.     int counter;  /*** OS2-patch **/
  445.  
  446.     for (c = 0; c < MAXCHAR; c++)
  447.     chtbl[c] = -1;
  448.  
  449.     for (;;) {
  450.     if (fgets(buff, sizeof buff, in) == Nullch) {
  451.         printf("EOF while in translation table.\n");
  452.         return;
  453.     }
  454.  
  455. /*** OS2: AAAAAAAAHHHHHHHHHHHH, ..... another problem with \r (^M)... **/
  456.  
  457.     for (counter = 0; counter <= strlen(buff); counter++)
  458.         if ((buff[counter] == '\r') &&
  459.             (buff[counter+1] == '\n')) {
  460.             for (; buff[counter] != '\0'; counter++)
  461.                 buff[counter] = buff[counter+1];
  462.         }
  463.  
  464.     numl++;
  465.     if (strnEQ(buff, "begin", 5)) {
  466.         printf("Incomplete translation table.\n");
  467.         return;
  468.     }
  469.     cpt = buff + strlen(buff) - 1;
  470.     *cpt = ' ';
  471.     while (*cpt == ' ') {
  472.         *cpt = 0;
  473.         cpt--;
  474.     }
  475.     cpt = buff;
  476.     while (c = *cpt) {
  477.         if (chtbl[c] != -1) {
  478.         printf("Duplicate char in translation table.\n");
  479.         return;
  480.         }
  481.         if (n == 0)
  482.         blank = c;
  483.         chtbl[c] = n++;
  484.         if (n >= 64)
  485.         return;
  486.         cpt++;
  487.     }
  488.     }
  489. }
  490.  
  491.