home *** CD-ROM | disk | FTP | other *** search
- /* (C) Copyright 1993 by John G. Myers
- * All Rights Reserved.
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of John G.
- * Myers not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. John G. Myers makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL JOHN G. MYERS BE LIABLE FOR ANY SPECIAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <stdio.h>
- #include <ctype.h>
- #include "xmalloc.h"
- #include "common.h"
-
- extern char *os_idtodir();
- extern FILE *os_newtypedfile();
-
- /*
- * Read an input file, looking for data in split-uuencode format
- */
- handleUuencode(infile, subject)
- FILE *infile;
- char *subject;
- {
- char *fname;
- int part = 0, nparts = 0;
- char *dir;
- char buf[1024];
- FILE *partfile;
-
- if (parseSubject(subject, &fname, &part, &nparts)) return 0;
-
- /* Create directory to store parts and copy this part there. */
- dir = os_idtodir(fname);
- if (!dir) return 1;
- sprintf(buf, "%s%d", dir, part);
- partfile = fopen(buf, "w");
- if (!partfile) {
- os_perror(buf);
- return 1;
- }
- while (fgets(buf, sizeof(buf), infile)) {
- fputs(buf, partfile);
- }
- fclose(partfile);
-
- /* Check to see if we have all parts. Start from the highest numbers
- * as we are more likely not to have them.
- */
- for (part = nparts; part; part--) {
- sprintf(buf, "%s%d", dir, part);
- partfile = fopen(buf, "r");
- if (partfile) {
- fclose(partfile);
- }
- else {
- return 0;
- }
- }
-
- return uudecodefiles(dir, nparts);
- }
-
- /*
- * Parse a Subject: header, looking for clues with which to decode
- * split-uuencoded data.
- */
- int
- parseSubject(subject, fnamep, partp, npartsp)
- char *subject;
- char **fnamep;
- int *partp;
- int *npartsp;
- {
- char *scan, *bak;
- int part = 0, nparts = 0;
-
- /* Skip leading whitespace and other garbage */
- scan = subject;
- while (isspace(*scan) || *scan == '-') scan++;
- if (!cistrncmp(scan, "repost", 6)) {
- for (scan += 6; isspace(*scan) || *scan == ':' || *scan == '-'; scan++);
- }
-
- /* Replies aren't usually data */
- if (!cistrncmp(scan, "re:", 3)) return 1;
-
- /* Get filename */
- *fnamep = scan;
- while (isalnum(*scan) || *scan == '-' || *scan == '+' || *scan == '&'
- || *scan == '_' || *scan == '.') scan++;
- if (*fnamep == scan || !*scan) return 1;
- *scan++ = '\0';
-
- /* Get part number */
- while (*scan) {
- /* look for "1/6" or "1 / 6" or "1 of 6" or "1o6" */
- if (isdigit(*scan) &&
- (scan[1] == '/'
- || (scan[1] == ' ' && scan[2] == '/')
- || (scan[1] == ' ' && scan[2] == 'o' && scan[3] == 'f')
- || (scan[1] == '-' && scan[2] == 'o' && scan[3] == 'f')
- || (scan[1] == 'o' && isdigit(scan[2])))) {
- while (isdigit(scan[-1])) scan--;
- part = 0;
- while (isdigit(*scan)) {
- part = part * 10 + *scan++ - '0';
- }
- while (scan != '\0' && !isdigit(*scan)) scan++;
- if (isdigit(*scan)) {
- nparts = 0;
- while (isdigit(*scan)) {
- nparts = nparts * 10 + *scan++ - '0';
- }
- }
- break;
- }
-
- /* look for "6 parts" or "part 1" */
- if (!cistrncmp("part", scan, 4)) {
- if (scan[4] == 's') {
- for (bak = scan; bak >= subject && !isdigit(*bak); bak--);
- if (bak > subject) {
- while (bak > subject && isdigit(bak[-1])) bak--;
- nparts = 0;
- while (isdigit(*bak)) {
- nparts = nparts * 10 + *bak++ - '0';
- }
- }
- } else {
- while (*scan != '\0' && !isdigit(*scan)) scan++;
- part = 0;
- while (isdigit(*scan)) {
- part = part * 10 + *scan++ - '0';
- }
- scan -= 2;
- }
- }
- scan++;
- }
-
- if (nparts == 0 || part == 0 || part > nparts) return 1;
- *partp = part;
- *npartsp = nparts;
- return 0;
- }
-
- /* Length of a normal uuencoded line, including newline */
- #define UULENGTH 62
-
- /*
- * Decode the uuencoded file that is in 'nparts' pieces in 'dir'.
- */
- int
- uudecodefiles(dir, nparts)
- char *dir;
- int nparts;
- {
- int part;
- enum {st_start, st_desc, st_inactive, st_decode, st_nextlast, st_last} state;
- FILE *infile;
- FILE *outfile;
- char buf[1024];
- char lastline[UULENGTH+1];
- char *fname, *p;
- char *contentType = "application/octet-stream";
-
- /* Create description filename */
- outfile = fopen(TEMPFILENAME, "w");
- state = outfile ? st_desc : st_start;
-
- /* Handle each part in order */
- for (part = 1; part <= nparts; part++) {
- sprintf(buf, "%s%d", dir, part);
- infile = fopen(buf, "r");
- if (!infile) {
- os_perror(buf);
- if (outfile) fclose(outfile);
- remove(TEMPFILENAME);
- return 1;
- }
-
- while (fgets(buf, sizeof(buf), infile)) {
- switch (state) {
- case st_desc: /* Copying description text */
- if (!strncmp(buf, "-----", 5) ||
- !strncmp(buf, "#!", 2) ||
- !cistrncmp(buf, "part=", 5) ||
- !cistrncmp(buf, "begin", 5)) {
- fclose(outfile);
- outfile = 0;
- state = st_start;
- }
- else {
- fputs(buf, outfile);
- break;
- }
- /* FALL THROUGH */
-
- case st_start: /* Looking for start of uuencoded file */
- if (strncmp(buf, "begin ", 6)) break;
- /* skip mode */
- p = buf + 6;
- while (*p && !isspace(*p)) p++;
- while (*p && isspace(*p)) p++;
- fname = p;
- while (*p && !isspace(*p)) p++;
- *p = '\0';
- if (!*fname) return 1;
-
- /* Guess the content-type of common filename extensions */
- if (strlen(fname) > 4) {
- p = fname + strlen(fname)-4;
- if (!cistrcmp(p, ".gif")) contentType = "image/gif";
- if (!cistrcmp(p, ".jpg")) contentType = "image/jpeg";
- if (!cistrcmp(p, ".jpeg")) contentType = "image/jpeg";
- if (!cistrcmp(p, ".mpg")) contentType = "video/mpeg";
- if (!cistrcmp(p, ".mpeg")) contentType = "video/mpeg";
- }
-
- /* Create output file and start decoding */
- outfile = os_newtypedfile(fname, contentType, 1);
- if (!outfile) {
- fclose(infile);
- return 1;
- }
- state = st_decode;
- break;
-
- case st_inactive: /* Looking for uuencoded data to resume */
- if (*buf != 'M' || strlen(buf) != UULENGTH) break;
- state = st_decode;
- /* FALL THROUGH */
- case st_decode: /* Decoding data */
- if (*buf == 'M' && strlen(buf) == UULENGTH) {
- uudecodeline(buf, outfile);
- break;
- }
- if (strlen(buf) > UULENGTH) {
- state = st_inactive;
- break;
- }
- /*
- * May be on nearing end of file.
- * Save this line in case we are.
- */
- strcpy(lastline, buf);
- if (*buf == ' ' || *buf == '`') {
- state = st_last;
- }
- else {
- state = st_nextlast;
- }
- break;
-
- case st_nextlast: /* May be nearing end of file */
- if (*buf == ' ' || *buf == '`') {
- state = st_last;
- }
- else {
- state = st_inactive;
- }
- break;
-
- case st_last: /* Should be at end of file */
- if (!strcmp(buf, "end\n")) {
- /* Handle that last line we saved */
- uudecodeline(lastline, outfile);
- fclose(infile);
- fclose(outfile);
- for (;part <= nparts; part++) {
- sprintf(buf, "%s%d", dir, part);
- remove(buf);
- }
- os_donewithdir(dir);
- return 0;
- }
- state = st_inactive;
- break;
- }
- }
- state = st_inactive;
- fclose(infile);
- sprintf(buf, "%s%d", dir, part);
- remove(buf);
- }
- if (outfile) fclose(outfile);
- os_donewithdir(dir);
- return 0;
- }
-
- #define DEC(c) (((c) - ' ') & 077)
-
- /*
- * Decode a uuencoded line to 'outfile'
- */
- uudecodeline(line, outfile)
- char *line;
- FILE *outfile;
- {
- int c, len;
-
- len = DEC(*line++);
- while (len) {
- c = DEC(*line) << 2 | DEC(line[1]) >> 4;
- putc(c, outfile);
- if (--len) {
- c = DEC(line[1]) << 4 | DEC(line[2]) >> 2;
- putc(c, outfile);
- if (--len) {
- c = DEC(line[2]) << 6 | DEC(line[3]);
- putc(c, outfile);
- len--;
- }
- }
- line += 4;
- }
- return;
- }
-
-
-