This is decode.c in view mode; [Download] [Up]
/* * Decode one or more uuencoded article back to binary form. * * UNIX/NN VERSION * This version cannot be used as a stand-alone uud! * This version is made: 16 June 1989. * * From the Berkeley original, modified by MSD, RDR, JPHD & WLS. */ #include "config.h" /* #define DEC_DEBUG /* never define this */ export char *decode_header_file = "Decode.Headers"; export int decode_skip_prefix = 2; #define MAXCHAR 256 #define LINELEN 256 #define NORMLEN 60 /* allows for 80 encoded chars per line */ #define SEQMAX 'z' #define SEQMIN 'a' static char seqc, partn; static int first, secnd, check; #define MAX_PREFIX 10 static int prefix_lgt, set_prefix; static char prefix_str[MAX_PREFIX]; static FILE *out; static char *target; static char blank; static int chtbl[MAXCHAR], cdlen[NORMLEN + 3]; static char ofname[FILENAME], arcname[FILENAME]; static int state, arcpart; #define NO_ADVANCE 0x10 #define DECODE_TEXT 1 #define FIND_BEGIN 2 #define FIND_BEGIN_AFTER_ERROR 3 #define FIND_BEGIN_AFTER_INCLUDE 4 #define NEW_BEGIN (5 | NO_ADVANCE) #define FOUND_END (6 | NO_ADVANCE) #define FOUND_INCLUDE (7 | NO_ADVANCE) #define SKIP_LEADING 8 #define SKIP_TRAILING (9 | NO_ADVANCE) #define DECODE_ERROR (10 | NO_ADVANCE) #define OTHER_ERROR (11 | NO_ADVANCE) #define MIN_DECODE_LEADING 8 /* lines to decode ok when doing skip-leading */ #ifdef DEC_DEBUG char *state_tbl[] = { "-", "decode", "find begin", "find a/error", "find a/include", "new begin", "found end", "found include", "skip leading", "skip trail", "error", "other error" }; #endif /* * decode one line, write on out file */ static strncmp_skip(buf, str, n) char *buf, *str; int n; { register int i; register char *line = buf; if (!set_prefix) return strncmp(line, str, n); if (decode_skip_prefix > MAX_PREFIX) decode_skip_prefix = MAX_PREFIX; for (i = 0; i <= decode_skip_prefix; i++, line++) { if (*line == NUL) break; if (*line == '#' || *line == ':') break; if (strncmp(line, str, n)) continue; prefix_lgt = i; if (i) strncpy(prefix_str, buf, i); set_prefix = 0; #ifdef DEC_DEBUG msg("match %s", str); user_delay(1); #endif return 0; } return 1; } static decode_line(buf, len, dont_write) char *buf; register int len; /* actual input line length */ int dont_write; /* doing leading check */ { char outl[LINELEN]; register char *bp, *ut; register int *trtbl = chtbl; register int n; register int blen; /* binary length (from decoded file) */ register int rlen; /* calculated input line length */ /* * Get the binary line length. */ if ((blen = trtbl[buf[0]]) < 0) { if (strncmp(buf, "begin", 5) == 0 || strncmp(buf, "table", 5) == 0) return NEW_BEGIN; if (state == SKIP_LEADING) return SKIP_LEADING; /* * end of uuencoded file ? */ if (strncmp(buf, "end", 3) == 0) return FOUND_END; /* * end of current file ? : get next one. */ if (strncmp(buf, "include", 7) == 0) return FOUND_INCLUDE; /* * trailing garbage */ return SKIP_TRAILING; } rlen = cdlen[blen]; if (len < rlen) goto d_err; if (len > (rlen + 2)) goto d_err; /* line too long */ /* * Is it the empty line before the end line ? */ if (blen == 0) return state; /* * Pad with blanks. */ for (bp = buf + len, n = rlen - len; --n >= 0; ) *bp++ = blank; /* * Verify */ for (n = rlen, bp = buf; --n >= 0; bp++) if (trtbl[*bp] < 0) { #ifdef DEC_DEBUG msg("%s - verify failed %d '%.30s'", state_tbl[state&0xf], rlen - n, buf); user_delay(2); #endif goto d_err; } /* * Check for uuencodes that append a 'z' to each line.... */ if (check) if (secnd) { secnd = 0; if (buf[rlen] == SEQMAX) check = 0; } else if (first) { first = 0; secnd = 1; if (buf[rlen] != SEQMAX) check = 0; } /* * There we check. */ if (check) { if (buf[rlen] != seqc) { #ifdef DEC_DEBUG msg("check failed %d != %d", buf[rlen], seqc); user_delay(1); #endif goto d_err; } if (--seqc < SEQMIN) seqc = SEQMAX; } if (dont_write) return DECODE_TEXT; /* * output a group of 3 bytes (4 input characters). */ ut = outl; n = blen; bp = &buf[1]; while (--n >= 0) { *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4; if (n > 0) { *(ut++) = (trtbl[bp[1]] << 4) | (trtbl[bp[2]] >> 2); n--; } if (n > 0) { *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]]; n--; } bp += 4; } if (fwrite(outl, 1, blen, out) <= 0) { msg("Error on writing decoded file"); return OTHER_ERROR; } return DECODE_TEXT; d_err: if (state == SKIP_LEADING) return SKIP_LEADING; return DECODE_ERROR; } /* * Install the table in memory for later use. */ static inittbls() { register int i, j; /* * Set up the default translation table. */ for (i = 0; i < ' '; i++) chtbl[i] = -1; for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j; for (i = ' ' + 64; i < MAXCHAR; i++) chtbl[i] = -1; chtbl['`'] = chtbl[' ']; /* common mutation */ chtbl['~'] = chtbl['^']; /* an other common mutation */ blank = ' '; /* * set up the line length table, to avoid computing lotsa * and / ... */ cdlen[0] = 1; for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4) cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j)); } static gettable(in) FILE *in; { char buf[LINELEN], *line; register int c, n = 0; register char *cpt; for (c = 0; c <= MAXCHAR; c++) chtbl[c] = -1; for (;;) { if (fgets(buf, sizeof buf, in) == NULL) { msg("EOF while in translation table."); return -1; } line = buf + prefix_lgt; if ((prefix_lgt > 0 && strncmp(buf, prefix_str, prefix_lgt)) || strncmp(line, "begin", 5) == 0) { msg("Incomplete translation table."); return -1; } cpt = line + strlen(line) - 1; *cpt = ' '; while (*(cpt) == ' ') { *cpt = 0; cpt--; } cpt = line; while (c = *cpt) { if (chtbl[c] != -1) { msg("Duplicate char in translation table."); return -1; } if (n == 0) blank = c; chtbl[c] = n++; if (n >= 64) return 0; cpt++; } } } static new_file() { out = NULL; seqc = SEQMAX; partn = 'a'; check = 1; first = 1; secnd = 0; state = FIND_BEGIN; prefix_lgt = 0; set_prefix = decode_skip_prefix; arcpart = 0; inittbls(); } uud_start(dir) char *dir; { target = dir; new_file(); } uud_end() { if (out != NULL) { fclose(out); msg("%s INCOMPLETE -- removed", arcname); unlink(ofname); out = NULL; } } uudecode(ah, in) register article_header *ah; FILE *in; { int mode, onedone, len, lead_check = 0; int ostate = 0; char buf[LINELEN], part[2], *line; off_t real_size, start_offset; long expect_size; onedone = 0; /* * search for header or translation table line. */ start_offset = ftell(in); for (;;) { if ((state & NO_ADVANCE) == 0) { if (ftell(in) >= ah->lpos) break; if (fgets(buf, sizeof buf, in) == NULL) break; } if (s_keyboard) return -1; len=strlen(buf); if (len > 0 && buf[len - 1] == NL) buf[--len] = NUL; #ifdef DEC_DEBUG if (state != ostate) { msg("%s->%s - '%.30s'", state_tbl[ostate&0xf], state_tbl[state&0xf], buf); user_delay(2); ostate = state; } #endif switch (state) { case NEW_BEGIN: if (out != NULL) { uud_end(); user_delay(5); } new_file(); /* fall thru */ case FIND_BEGIN: case FIND_BEGIN_AFTER_ERROR: case FIND_BEGIN_AFTER_INCLUDE: set_prefix = decode_skip_prefix; if (strncmp_skip(buf, "table", 5) == 0) { gettable(in); continue; } if (strncmp_skip(buf, "begin", 5)) continue; line = buf + prefix_lgt; if (state == FIND_BEGIN_AFTER_INCLUDE) { if(sscanf(line,"begin part %1s%s", part, arcname) != 2) { msg("Invalid 'begin' line after 'include'"); continue; } partn++; if (partn > 'z') partn = 'a'; if (part[0] != partn) { msg("PARTS NOT IN SEQUENCE: %s -- removed", arcname); user_delay(5); fclose(out); unlink(ofname); new_file(); state = FIND_BEGIN_AFTER_ERROR; goto err; } } else { if(sscanf(line,"begin%o%s", &mode, arcname) != 2) continue; if (target != NULL) sprintf(ofname, "%s%s", target, arcname); else strcpy(ofname, arcname); if ((out = open_file(ofname, OPEN_CREATE)) == NULL) { msg("Cannot create file: %s", ofname); goto err; } chmod(ofname, mode); if (decode_header_file) store_header(ah, in, target, decode_header_file); } state = DECODE_TEXT; continue; case SKIP_LEADING: if (len > prefix_lgt && (!prefix_lgt || strncmp(buf, prefix_str, prefix_lgt) == 0)) { state = decode_line(buf + prefix_lgt, len - prefix_lgt, 1); if (state == DECODE_TEXT) { if (++lead_check == MIN_DECODE_LEADING) { fseek(in, start_offset, 0); continue; } state = SKIP_LEADING; continue; } } else { set_prefix = decode_skip_prefix; if (strncmp_skip(buf, "begin", 5) == 0 || strncmp_skip(buf, "table", 5) == 0) state = NEW_BEGIN; } lead_check = 0; start_offset = ftell(in); continue; case DECODE_TEXT: if (len <= prefix_lgt || (prefix_lgt > 0 && strncmp(buf, prefix_str, prefix_lgt))) { state = SKIP_TRAILING; continue; } if (onedone == 0) { msg("Decoding%s: %s (part %d)", prefix_lgt ? " & Unsharing" : "", arcname, ++arcpart); onedone = 1; } state = decode_line(buf + prefix_lgt, len - prefix_lgt, 0); continue; case FOUND_END: real_size = ftell(out); fclose(out); if (ftell(in) >= ah->lpos || fgets(buf, sizeof buf, in) == NULL) { new_file(); break; } if ((!prefix_lgt || strncmp(buf, prefix_str, prefix_lgt) == 0) && sscanf(buf + prefix_lgt, "size%ld", &expect_size) == 1 && real_size != expect_size) { msg("%s decoded with wrong size %ld (exp. %ld)", arcname, real_size, expect_size); user_delay(3); } else { msg("%s complete", arcname); user_delay(1); } new_file(); state = NEW_BEGIN; continue; case FOUND_INCLUDE: state = FIND_BEGIN_AFTER_INCLUDE; return 0; case SKIP_TRAILING: state = SKIP_LEADING; return 0; case DECODE_ERROR: state = SKIP_TRAILING; continue; case OTHER_ERROR: fclose(out); new_file(); state = FIND_BEGIN_AFTER_ERROR; goto err; } break; /* break in switch => break in loop */ } if (onedone) { if (state == DECODE_TEXT) state = SKIP_LEADING; return 0; } if (state == FIND_BEGIN_AFTER_ERROR) return -1; msg("No 'begin' line"); err: user_delay(2); return -1; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.