home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / trn / part04 / uudecode.c < prev   
Encoding:
C/C++ Source or Header  |  1991-12-02  |  9.7 KB  |  466 lines

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