home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / MPack1_2_1.lha / MPack / src / uudecode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-05  |  8.2 KB  |  335 lines

  1. /* (C) Copyright 1993 by John G. Myers
  2.  * All Rights Reserved.
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software
  5.  * and its documentation for any purpose is hereby granted without
  6.  * fee, provided that the above copyright notice appear in all copies
  7.  * and that both that copyright notice and this permission notice
  8.  * appear in supporting documentation, and that the name of John G.
  9.  * Myers not be used in advertising or publicity pertaining to
  10.  * distribution of the software without specific, written prior
  11.  * permission.  John G. Myers makes no representations about the
  12.  * suitability of this software for any purpose.  It is provided "as
  13.  * is" without express or implied warranty.
  14.  *
  15.  * JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  16.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17.  * FITNESS, IN NO EVENT SHALL JOHN G. MYERS BE LIABLE FOR ANY SPECIAL,
  18.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  19.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
  21.  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  */
  23. #include <stdio.h>
  24. #include <ctype.h>
  25. #include "xmalloc.h"
  26. #include "common.h"
  27.  
  28. extern char *os_idtodir();
  29. extern FILE *os_newtypedfile();
  30.  
  31. /*
  32.  * Read an input file, looking for data in split-uuencode format
  33.  */
  34. handleUuencode(infile, subject)
  35. FILE *infile;
  36. char *subject;
  37. {
  38.     char *fname;
  39.     int part = 0, nparts = 0;
  40.     char *dir;
  41.     char buf[1024];
  42.     FILE *partfile;
  43.  
  44.     if (parseSubject(subject, &fname, &part, &nparts)) return 0;
  45.  
  46.     /* Create directory to store parts and copy this part there. */
  47.     dir = os_idtodir(fname);
  48.     if (!dir) return 1;
  49.     sprintf(buf, "%s%d", dir, part);
  50.     partfile = fopen(buf, "w");
  51.         if (!partfile) {
  52.     os_perror(buf);
  53.     return 1;
  54.     }
  55.     while (fgets(buf, sizeof(buf), infile)) {
  56.     fputs(buf, partfile);
  57.     }
  58.     fclose(partfile);
  59.  
  60.     /* Check to see if we have all parts.  Start from the highest numbers
  61.      * as we are more likely not to have them.
  62.      */
  63.     for (part = nparts; part; part--) {
  64.     sprintf(buf, "%s%d", dir, part);
  65.     partfile = fopen(buf, "r");
  66.     if (partfile) {
  67.         fclose(partfile);
  68.     }
  69.     else {
  70.         return 0;
  71.     }
  72.     }
  73.  
  74.     return uudecodefiles(dir, nparts);
  75. }
  76.  
  77. /*
  78.  * Parse a Subject: header, looking for clues with which to decode
  79.  * split-uuencoded data.
  80.  */
  81. int
  82. parseSubject(subject, fnamep, partp, npartsp)
  83. char *subject;
  84. char **fnamep;
  85. int *partp;
  86. int *npartsp;
  87. {
  88.     char *scan, *bak;
  89.     int part = 0, nparts = 0;
  90.  
  91.     /* Skip leading whitespace and other garbage */
  92.     scan = subject;
  93.     while (isspace(*scan) || *scan == '-') scan++;
  94.     if (!cistrncmp(scan, "repost", 6)) {
  95.     for (scan += 6; isspace(*scan) || *scan == ':' || *scan == '-'; scan++);
  96.     }
  97.  
  98.     /* Replies aren't usually data */
  99.     if (!cistrncmp(scan, "re:", 3)) return 1;
  100.  
  101.     /* Get filename */
  102.     *fnamep = scan;
  103.     while (isalnum(*scan) || *scan == '-' || *scan == '+' || *scan == '&'
  104.        || *scan == '_' || *scan == '.') scan++;
  105.     if (*fnamep == scan || !*scan) return 1;
  106.     *scan++ = '\0';
  107.  
  108.     /* Get part number */
  109.     while (*scan) {
  110.     /* look for "1/6" or "1 / 6" or "1 of 6" or "1o6" */
  111.     if (isdigit(*scan) &&
  112.         (scan[1] == '/'
  113.          || (scan[1] == ' ' && scan[2] == '/')
  114.          || (scan[1] == ' ' && scan[2] == 'o' && scan[3] == 'f')
  115.          || (scan[1] == '-' && scan[2] == 'o' && scan[3] == 'f')
  116.          || (scan[1] == 'o' && isdigit(scan[2])))) {
  117.         while (isdigit(scan[-1])) scan--;
  118.         part = 0;
  119.         while (isdigit(*scan)) {
  120.         part = part * 10 + *scan++ - '0';
  121.         }
  122.         while (scan != '\0' && !isdigit(*scan)) scan++;
  123.         if (isdigit(*scan)) {
  124.         nparts = 0;
  125.         while (isdigit(*scan)) {
  126.             nparts = nparts * 10 + *scan++ - '0';
  127.         }
  128.         }
  129.         break;
  130.     }
  131.  
  132.     /* look for "6 parts" or "part 1" */
  133.     if (!cistrncmp("part", scan, 4)) {
  134.         if (scan[4] == 's') {
  135.         for (bak = scan; bak >= subject && !isdigit(*bak); bak--);
  136.         if (bak > subject) {
  137.             while (bak > subject && isdigit(bak[-1])) bak--;
  138.             nparts = 0;
  139.             while (isdigit(*bak)) {
  140.             nparts = nparts * 10 + *bak++ - '0';
  141.             }
  142.         }
  143.         } else {
  144.         while (*scan != '\0' && !isdigit(*scan)) scan++;
  145.         part = 0;
  146.         while (isdigit(*scan)) {
  147.             part = part * 10 + *scan++ - '0';
  148.         }
  149.         scan -= 2;
  150.         }
  151.     }
  152.     scan++;
  153.     }
  154.  
  155.     if (nparts == 0 || part == 0 || part > nparts) return 1;
  156.     *partp = part;
  157.     *npartsp = nparts;
  158.     return 0;
  159. }
  160.  
  161. /* Length of a normal uuencoded line, including newline */
  162. #define UULENGTH 62
  163.  
  164. /*
  165.  * Decode the uuencoded file that is in 'nparts' pieces in 'dir'.
  166.  */
  167. int
  168. uudecodefiles(dir, nparts)
  169. char *dir;
  170. int nparts;
  171. {
  172.     int part;
  173.     enum {st_start, st_desc, st_inactive, st_decode, st_nextlast, st_last} state;
  174.     FILE *infile;
  175.     FILE *outfile;
  176.     char buf[1024];
  177.     char lastline[UULENGTH+1];
  178.     char *fname, *p;
  179.     char *contentType = "application/octet-stream";
  180.  
  181.     /* Create description filename */
  182.     outfile = fopen(TEMPFILENAME, "w");
  183.     state = outfile ? st_desc : st_start;
  184.  
  185.     /* Handle each part in order */
  186.     for (part = 1; part <= nparts; part++) {
  187.     sprintf(buf, "%s%d", dir, part);
  188.     infile = fopen(buf, "r");
  189.     if (!infile) {
  190.         os_perror(buf);
  191.         if (outfile) fclose(outfile);
  192.         remove(TEMPFILENAME);
  193.         return 1;
  194.     }
  195.  
  196.     while (fgets(buf, sizeof(buf), infile)) {
  197.         switch (state) {
  198.         case st_desc:    /* Copying description text */
  199.         if (!strncmp(buf, "-----", 5) ||
  200.             !strncmp(buf, "#!", 2) ||
  201.             !cistrncmp(buf, "part=", 5) ||
  202.             !cistrncmp(buf, "begin", 5)) {
  203.             fclose(outfile);
  204.             outfile = 0;
  205.             state = st_start;
  206.         }
  207.         else {
  208.             fputs(buf, outfile);
  209.             break;
  210.         }
  211.         /* FALL THROUGH */
  212.  
  213.         case st_start:    /* Looking for start of uuencoded file */
  214.         if (strncmp(buf, "begin ", 6)) break;
  215.         /* skip mode */
  216.         p = buf + 6;
  217.         while (*p && !isspace(*p)) p++;
  218.         while (*p && isspace(*p)) p++;
  219.         fname = p;
  220.         while (*p && !isspace(*p)) p++;
  221.         *p = '\0';
  222.         if (!*fname) return 1;
  223.  
  224.         /* Guess the content-type of common filename extensions */
  225.         if (strlen(fname) > 4) {
  226.             p = fname + strlen(fname)-4;
  227.             if (!cistrcmp(p, ".gif")) contentType = "image/gif";
  228.             if (!cistrcmp(p, ".jpg")) contentType = "image/jpeg";
  229.             if (!cistrcmp(p, ".jpeg")) contentType = "image/jpeg";
  230.             if (!cistrcmp(p, ".mpg")) contentType = "video/mpeg";
  231.             if (!cistrcmp(p, ".mpeg")) contentType = "video/mpeg";
  232.         }
  233.  
  234.         /* Create output file and start decoding */
  235.         outfile = os_newtypedfile(fname, contentType, 1);
  236.         if (!outfile) {
  237.             fclose(infile);
  238.             return 1;
  239.         }
  240.         state = st_decode;
  241.         break;
  242.  
  243.         case st_inactive:    /* Looking for uuencoded data to resume */
  244.         if (*buf != 'M' || strlen(buf) != UULENGTH) break;
  245.         state = st_decode;
  246.         /* FALL THROUGH */
  247.         case st_decode:    /* Decoding data */
  248.         if (*buf == 'M' && strlen(buf) == UULENGTH) {
  249.             uudecodeline(buf, outfile);
  250.             break;
  251.         }
  252.         if (strlen(buf) > UULENGTH) {
  253.             state = st_inactive;
  254.             break;
  255.         }
  256.         /*
  257.          * May be on nearing end of file.
  258.          * Save this line in case we are.
  259.          */
  260.         strcpy(lastline, buf);
  261.         if (*buf == ' ' || *buf == '`') {
  262.             state = st_last;
  263.         }
  264.         else {
  265.             state = st_nextlast;
  266.         }
  267.         break;
  268.  
  269.         case st_nextlast:    /* May be nearing end of file */
  270.         if (*buf == ' ' || *buf == '`') {
  271.             state = st_last;
  272.         }
  273.         else {
  274.             state = st_inactive;
  275.         }
  276.         break;
  277.  
  278.         case st_last:    /* Should be at end of file */
  279.         if (!strcmp(buf, "end\n")) {
  280.             /* Handle that last line we saved */
  281.             uudecodeline(lastline, outfile);
  282.             fclose(infile);
  283.             fclose(outfile);
  284.             for (;part <= nparts; part++) {
  285.             sprintf(buf, "%s%d", dir, part);
  286.             remove(buf);
  287.             }
  288.             os_donewithdir(dir);
  289.             return 0;
  290.         }
  291.         state = st_inactive;
  292.         break;
  293.         }
  294.     }
  295.     state = st_inactive;
  296.     fclose(infile);
  297.     sprintf(buf, "%s%d", dir, part);
  298.     remove(buf);
  299.     }
  300.     if (outfile) fclose(outfile);
  301.     os_donewithdir(dir);
  302.     return 0;
  303. }
  304.  
  305. #define DEC(c)    (((c) - ' ') & 077)
  306.  
  307. /*
  308.  * Decode a uuencoded line to 'outfile'
  309.  */
  310. uudecodeline(line, outfile)
  311. char *line;
  312. FILE *outfile;
  313. {
  314.     int c, len;
  315.  
  316.     len = DEC(*line++);
  317.     while (len) {
  318.     c = DEC(*line) << 2 | DEC(line[1]) >> 4;
  319.     putc(c, outfile);
  320.     if (--len) {
  321.         c = DEC(line[1]) << 4 | DEC(line[2]) >> 2;
  322.         putc(c, outfile);
  323.         if (--len) {
  324.         c = DEC(line[2]) << 6 | DEC(line[3]);
  325.         putc(c, outfile);
  326.         len--;
  327.         }
  328.     }
  329.     line += 4;
  330.     }
  331.     return;
  332. }
  333.  
  334.     
  335.