home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume23 / trn / part12 / uudecode.c < prev   
Encoding:
C/C++ Source or Header  |  1991-08-22  |  7.9 KB  |  412 lines

  1. /* $Header: uudecode.c,v 4.3.3.2 91/01/16 03:41:52 davison Trn $
  2. **
  3. ** $Log:    uudecode.c,v $
  4. ** Revision 4.3.3.2  91/01/16  03:41:52  davison
  5. ** Tweaked fopen for possible binary open mode.
  6. ** 
  7. ** Revision 4.3.3.1  90/06/20  22:48:21  davison
  8. ** Initial Trn Release
  9. ** 
  10. ** Decode one or more uuencoded articles back to binary form.
  11. **
  12. ** Trn version created by Wayne Davison.
  13. ** Adapted from the nn version by Kim Storm.
  14. ** From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
  15. */
  16.  
  17. #include "EXTERN.h"
  18. #include "common.h"
  19. #include "INTERN.h"
  20. #include "uudecode.h"
  21.  
  22. #if 000
  23. export char *decode_header_file = "Decode.Headers";
  24. #endif
  25.  
  26. #define MAXCHAR 256
  27. #define NORMLEN 60    /* allows for 80 encoded chars per line */
  28.  
  29. #define SEQMAX 'z'
  30. #define SEQMIN 'a'
  31.  
  32. static char seqc;
  33. static int first, secnd, check, numl;
  34.  
  35. static char *target;
  36. static char dest[MAXFILENAME];
  37. static char blank;
  38. static int chtbl[MAXCHAR], cdlen[NORMLEN + 3];
  39. static int state;
  40. static bool Xflag;
  41.  
  42. #define    NO_ADVANCE        0x10
  43.  
  44. #define    FIND_BEGIN        0x01
  45. #define    FIND_BEGIN_AFTER_ERROR    0x02
  46. #define    DECODE_TEXT        0x03
  47. #define    SKIP_TRAILING           (0x04 | NO_ADVANCE)
  48. #define    SKIP_LEADING        0x05
  49. #define    FOUND_END           (0x06 | NO_ADVANCE)
  50. #define DECODE_ERROR           (0x07 | NO_ADVANCE)
  51. #define OTHER_ERROR           (0x08 | NO_ADVANCE)
  52. #define NEW_BEGIN           (0x09 | NO_ADVANCE)
  53.  
  54. uud_start(dir)
  55. char *dir;
  56. {
  57.     target = dir;
  58.     uu_out = Nullfp;
  59.     Xflag = FALSE;
  60.     seqc = SEQMAX;
  61.     check = 1;
  62.     first = 1;
  63.     secnd = 0;
  64.     state = FIND_BEGIN;
  65. }
  66.  
  67. uud_end()
  68. {
  69.     if (uu_out != Nullfp) {
  70.     fclose(uu_out);
  71.     uu_out = Nullfp;
  72.     printf("\n%s INCOMPLETE -- removed\n", dest);
  73.     unlink(dest);
  74.     }
  75. }
  76.  
  77.  
  78. uudecode(in)
  79. FILE *in;
  80. {
  81.     int mode, onedone, lens;
  82.     char buff[LBUFLEN];
  83.  
  84.     numl = onedone = 0;
  85.  
  86.     if (state == FIND_BEGIN)
  87.     inittbls();
  88.  
  89.     /*
  90.      * search for header or translation table line.
  91.      */
  92.  
  93.     while ((state & NO_ADVANCE) || fgets(buff, sizeof buff, in) != Nullch) {
  94.     numl++;
  95.  
  96.     switch (state) {
  97.      case NEW_BEGIN:
  98.         if (uu_out != Nullfp) {
  99.         printf("INCOMPLETE FILE: %s -- removed\n", dest);
  100.         sleep(2);
  101.         fclose(uu_out);
  102.         uu_out = Nullfp;
  103.         Xflag = FALSE;
  104.         unlink(dest);
  105.         }
  106.         /* fall thru */
  107.  
  108.      case FIND_BEGIN:
  109.      case FIND_BEGIN_AFTER_ERROR:
  110.         if (strnEQ(buff, "table ", 6)) {
  111.         gettable(in);
  112.         continue;
  113.         }
  114.  
  115.         if (strnEQ(buff, "begin ", 6)
  116.          || strnEQ(buff, "Xbegin ", 7)) {
  117.         lens = strlen(buff)-1;
  118.         if (buff[lens] == '\n')
  119.             buff[lens] = '\0';
  120.  
  121.         if(sscanf(buff+6,"%o%s", &mode, uu_fname) != 2)
  122.             continue;
  123.  
  124.         Xflag = (*buff == 'X');
  125.  
  126.         if (target != Nullch)
  127.             sprintf(dest, "%s/%s", target, uu_fname);
  128.         else
  129.             strcpy(dest, uu_fname);
  130.  
  131.         if ((uu_out = fopen(dest, FOPEN_WB)) == Nullfp) {
  132.             printf("Cannot create file: %s\n", dest);
  133.             goto err;
  134.         }
  135.         chmod(dest, mode);
  136.  
  137. #if 000
  138.         if (decode_header_file)
  139.             store_header(ah, in, target, decode_header_file);
  140. #endif
  141.  
  142.         printf("Decoding: %s\n", uu_fname);
  143.         state = DECODE_TEXT;
  144.         }
  145.         continue;
  146.  
  147.      case SKIP_LEADING:
  148.         state = decode_line(buff);
  149.         continue;
  150.  
  151.      case DECODE_TEXT:
  152.         state = decode_line(buff);
  153.         onedone = 1;
  154.         continue;
  155.  
  156.      case FOUND_END:
  157.         fclose(uu_out);
  158.         uu_out = Nullfp;
  159.         Xflag = FALSE;
  160.         state = FIND_BEGIN;
  161.         printf("Done.\n");
  162.         continue;
  163.  
  164.      case SKIP_TRAILING:
  165.         printf("(Continued)\n");
  166.         state = SKIP_LEADING;
  167.         return 0;
  168.  
  169.      case DECODE_ERROR:
  170.         state = SKIP_TRAILING;
  171.         continue;
  172.  
  173.      case OTHER_ERROR:
  174.         fclose(uu_out);
  175.         uu_out = Nullfp;
  176.         Xflag = FALSE;
  177.         state = FIND_BEGIN_AFTER_ERROR;
  178.         goto err;
  179.     }
  180.     }
  181.  
  182.     if (onedone) {
  183.     if (state == DECODE_TEXT)
  184.         state = SKIP_LEADING;
  185.     return 0;
  186.     }
  187.  
  188.     if (state == FIND_BEGIN_AFTER_ERROR)
  189.     return -1;
  190.     printf("Couldn't find anything to decode.\n");
  191.  
  192.  err:
  193.     sleep(2);
  194.     return -1;
  195. }
  196.  
  197. /*
  198.  * decode one line, write on uu_out file
  199.  */
  200.  
  201. static decode_line(buff)
  202. char *buff;
  203. {
  204.     char outl[LBUFLEN];
  205.     register char *bp, *ut;
  206.     register int *trtbl = chtbl;
  207.     register int n;
  208.     register int blen;        /* binary length (from decoded file) */
  209.     register int rlen;        /* calculated input line length */
  210.     register int len;        /* actual input line length */
  211.  
  212.     if (Xflag) {
  213.     if (*buff == 'X')
  214.         buff++;
  215.     else
  216.         *buff = 'x';    /* force a mis-parse of a non-x'ed line */
  217.     }
  218.     len = strlen(buff);
  219.     if (--len < 0)
  220.     return state;
  221.  
  222.     buff[len] = '\0';
  223.  
  224.     /*
  225.      * Get the binary line length.
  226.      */
  227.     if ((blen = trtbl[buff[0]]) < 0) {
  228.     if (state == SKIP_LEADING) {
  229.         if (strnEQ(buff, "begin ", 6))
  230.         return NEW_BEGIN;
  231.  
  232.         return SKIP_LEADING;
  233.     }
  234.     /*
  235.      * end of uuencoded file ?
  236.      */
  237.     if (strnEQ(buff, "end", 3))
  238.         return FOUND_END;
  239.  
  240.     /*
  241.      * end of current file ? : get next one.
  242.      */
  243.     if (strnEQ(buff, "include", 7)) {
  244.         printf("Cannot handle 'include' lines -- unpack with uud\n");
  245.         return OTHER_ERROR;
  246.     }
  247.  
  248.     /*
  249.      * trailing garbage
  250.      */
  251.     return SKIP_TRAILING;
  252.     }
  253.  
  254.     rlen = cdlen[blen];
  255.     if (state == SKIP_LEADING && len != rlen && len != rlen+1)
  256.     return SKIP_LEADING;
  257.  
  258.     /*
  259.      * Is it the empty line before the end line ?
  260.      */
  261.     if (blen == 0)
  262.     return state;
  263.  
  264.     if (len > rlen + 5)
  265.     return SKIP_TRAILING;
  266.  
  267.     /*
  268.      * Pad with blanks.
  269.      */
  270.     for (bp = buff + len, n = rlen - len; --n >= 0; )
  271.     *bp++ = blank;
  272.  
  273.     /*
  274.      * Verify
  275.      */
  276.     for (n = rlen, bp = buff; --n >= 0; bp++)
  277.     if (trtbl[*bp] < 0) {
  278.         if (state == SKIP_LEADING)
  279.         return SKIP_LEADING;
  280.         return DECODE_ERROR;
  281.     }
  282.  
  283.     /*
  284.      * Check for uuencodes that append a 'z' to each line....
  285.      */
  286.     if (check)
  287.     if (secnd) {
  288.         secnd = 0;
  289.         if (buff[rlen] == SEQMAX)
  290.         check = 0;
  291.     } else if (first) {
  292.         first = 0;
  293.         secnd = 1;
  294.         if (buff[rlen] != SEQMAX)
  295.         check = 0;
  296.     }
  297.  
  298.     /*
  299.      * There we check.
  300.      */
  301.     if (check) {
  302.     if (buff[rlen] != seqc) {
  303.         if (state == SKIP_LEADING)
  304.         return SKIP_LEADING;
  305.         return DECODE_ERROR;
  306.     }
  307.  
  308.     if (--seqc < SEQMIN)
  309.         seqc = SEQMAX;
  310.     }
  311.  
  312.     /*
  313.      * output a group of 3 bytes (4 input characters).
  314.      * the input chars are pointed to by p, they are to
  315.      * be output to file f. blen is used to tell us not to
  316.      * output all of them at the end of the file.
  317.      */
  318.     ut = outl;
  319.     n = blen;
  320.     bp = &buff[1];
  321.     while (--n >= 0) {
  322.     *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
  323.     if (n > 0) {
  324.         *(ut++) = (trtbl[bp[1]] << 4) | (trtbl[bp[2]] >> 2);
  325.         n--;
  326.     }
  327.     if (n > 0) {
  328.         *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
  329.         n--;
  330.     }
  331.     bp += 4;
  332.     }
  333.     if (fwrite(outl, 1, blen, uu_out) <= 0) {
  334.     printf("Error on writing decoded file\n");
  335.     return OTHER_ERROR;
  336.     }
  337.  
  338.     return DECODE_TEXT;
  339. }
  340.  
  341.  
  342.  
  343. /*
  344.  * Install the table in memory for later use.
  345.  */
  346. static inittbls()
  347. {
  348.     register int i, j;
  349.  
  350.     /*
  351.      * Set up the default translation table.
  352.      */
  353.     for (i = 0; i < ' '; i++)
  354.     chtbl[i] = -1;
  355.     for (i = ' ', j = 0; i < ' ' + 64; i++, j++)
  356.     chtbl[i] = j;
  357.     for (i = ' ' + 64; i < MAXCHAR; i++)
  358.     chtbl[i] = -1;
  359.     chtbl['`'] = chtbl[' '];    /* common mutation */
  360.     chtbl['~'] = chtbl['^'];    /* another common mutation */
  361.     blank = ' ';
  362.     /*
  363.      * set up the line length table, to avoid computing lotsa * and / ...
  364.      */
  365.     cdlen[0] = 1;
  366.     for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
  367.     cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
  368. }
  369.  
  370. static gettable(in)
  371. FILE *in;
  372. {
  373.     char buff[LBUFLEN];
  374.     register int c, n = 0;
  375.     register char *cpt;
  376.  
  377.     for (c = 0; c <= MAXCHAR; c++)
  378.     chtbl[c] = -1;
  379.  
  380.     for (;;) {
  381.     if (fgets(buff, sizeof buff, in) == Nullch) {
  382.         printf("EOF while in translation table.\n");
  383.         return -1;
  384.     }
  385.     numl++;
  386.     if (strnEQ(buff, "begin", 5)) {
  387.         printf("Incomplete translation table.\n");
  388.         return -1;
  389.     }
  390.     cpt = buff + strlen(buff) - 1;
  391.     *cpt = ' ';
  392.     while (*cpt == ' ') {
  393.         *cpt = 0;
  394.         cpt--;
  395.     }
  396.     cpt = buff;
  397.     while (c = *cpt) {
  398.         if (chtbl[c] != -1) {
  399.         printf("Duplicate char in translation table.\n");
  400.         return -1;
  401.         }
  402.         if (n == 0)
  403.         blank = c;
  404.         chtbl[c] = n++;
  405.         if (n >= 64)
  406.         return 0;
  407.         cpt++;
  408.     }
  409.     }
  410. }
  411.  
  412.