/* unc.c: A reasonably junk-tolerant uudecoder by DWF. Current version 1/20/93. A mishmash of BSD uudecode and original code. BUGS If uuencoded file is broken into pieces such that the last piece does not contain at least one line starting with M, this won't work. */ #include #include #include #include #include #define DEC(c) (((c) - ' ') & 077) #define UU_LINE_LENGTH 61 /* M + 15 cells of 4 characters */ #define GARBLE_LINE_LENGTH 63 /* If line is this long, it is garbled. * Some uuencoders add an extra character. */ #define MAX_NO_M_LINES 3 /* Includes end. */ typedef char linrec [UU_LINE_LENGTH+1]; /* Globals */ linrec buffer; FILE *out; linrec hold[3]; int flag=0, holdcount=0, currh=0; /* flag: * 0 Waiting for begin. * 1 Cruising. * 2 Briefly interrupted. * 3 Less briefly interrupted. */ /* Just like getchar, but ignores carriage returns. */ int charget () { int status = 13; while ((status=getchar())==13); return status; } /* Get a line, saving only the first UU_LINE_LENGTH characters but returning the true length. Returns -1 on EOF or whatever. */ int getline (buffer) char *buffer; { int temp, len = 0; temp = charget (); while ((temp != EOF)&&(temp != 10)) { if (len < UU_LINE_LENGTH) buffer [len] = (char)temp; len++; temp = charget (); } if ((len==0)&&(temp == EOF)) return -1; if (len < UU_LINE_LENGTH) buffer [len] = (char)0; else buffer [UU_LINE_LENGTH] = (char)0; return len; } /* * output a group of 3 bytes (4 input characters). * the input chars are pointed to by p, they are to * be output to file f. n is used to tell us not to * output all of them at the end of the file. */ void outdec(p, f, n) char *p; FILE *f; { int c1, c2, c3; c1 = DEC(*p) << 2 | DEC(p[1]) >> 4; c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2; c3 = DEC(p[2]) << 6 | DEC(p[3]); if (n >= 1) putc(c1, f); if (n >= 2) putc(c2, f); if (n >= 3) putc(c3, f); } /* Get the next valid line. Works like fgets (NULL on EOF). */ char *mgets (string) char *string; { int len; if ((holdcount > 0)&&(currh != holdcount)) { strcpy (string, hold[currh++]); return string; } holdcount=0; currh=0; while (1) { len = getline (string); if (len == -1) return NULL; /* Shit. */ switch (flag) { case 0: /* search for header line */ if (strncmp (string, "begin ", 6) != 0) break; flag = 1; return string; case 1: /* Cruising */ if ((string[0] == 'M')&&(len >= GARBLE_LINE_LENGTH)) { puts ("UUENCODED FILE IS GARBLED!!!"); exit (0); } if ((string[0] == 'M') && (memcmp (string, "Message", 7) != 0)&& (abs(len-(DEC(string[0])*4/3+1)) < 3)) return string; /* printf ("1: %s\n", string); */ flag = 2; /* Fall through */ case 2: /* Interrupted */ if (holdcount < MAX_NO_M_LINES) { strcpy (hold[holdcount++], string); if (memcmp (string, "end", 3) == 0) return mgets (string); break; } flag = 3; holdcount=0; currh=0; /* Fall through */ case 3: /* Wait for the next M line. */ if ((string[0] == 'M') && (memcmp (string, "Message", 7) != 0)&& (abs(len-(DEC(string[0])*4/3+1)) < 3)&&(len < GARBLE_LINE_LENGTH)) { flag = 1; return string; } /* printf ("3: %s\n", string); */ break; } } } /* * copy from in to out, decoding as you go along. */ void decode(out) FILE *out; { char buf[80]; char *bp; int n; for (;;) { /* for each input line */ if (mgets(buf) == NULL) { printf("Short file\n"); exit(10); } n = DEC(buf[0]); if (n <= 0) break; bp = &buf[1]; while (n > 0) { outdec(bp, out, n); bp += 4; n -= 3; } } } main() { int mode; char dest[128]; if (mgets (buffer) == NULL) { fprintf(stderr, "No begin line\n"); exit(3); } (void)sscanf(buffer, "begin %o %s", &mode, dest); /* create output file */ out = fopen (dest, "wb"); if (out == NULL) { perror(dest); exit(4); } decode (out); fclose (out); return 0; }