home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / packer / uugrab / uudecode.c next >
C/C++ Source or Header  |  1990-08-22  |  11KB  |  444 lines

  1. /* #ifndef lint
  2. static char sccsid[] = "@(#)uudecode.c  5.3-1 (Berkeley) 9/1/87";
  3. #endif */
  4.  
  5. /* Written by Mark Horton */
  6. /* Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums */
  7. /* Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for
  8.    compatibility */
  9. /* Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix a misleading
  10.    error message on the Amiga port, to fix a bug that prevented decoding
  11.    certain files, to work even if trailing spaces have been removed from a
  12.    file, to check the filesize (if present), to add some error checking, to
  13.    loop for multiple decodes from a single file, and to handle common
  14.    BITNET mangling.  Also kludged around a missing string function in Aztec
  15.    C */
  16. /* Modified by drw (Dale Worley, drw@math.mit.edu) to add the -f switch, which
  17.    forces the output to be on stdout.  This makes uudecode into a filter, and
  18.    frees the user from perversions in the file name and mode given in the
  19.    input file. These changes Copyright (C) 1987 Dale R. Worley, and are hereby
  20.    put in the public domain. */
  21. /* Modified by art (Art Dederick, {trwrb,oliveb,hplabs}!felix!art) to scan
  22.    for sectionized encoded files created by Richard Marks' v2.13 UUDECODE
  23.    program.  Cat all sections in the proper order then pass to uudecode.
  24.    Added a more manageable method for assigning exit error codes. */
  25.  
  26. /*
  27.  * uudecode [-f] [input]
  28.  *
  29.  * Decode a file encoded with uuencode.  WIll extract multiple encoded
  30.  * modules from a single file.    Can deal with most mangled files, including
  31.  * BITNET.  Will handle sectioned encoded files also.
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include <ctype.h>
  36.  
  37. #ifdef AMIGA
  38. #define AMIGA_LATTICE        /* Set for Amiga Lattice C */
  39. #define MCH_AMIGA
  40. #define MPU68000
  41. #endif
  42.  
  43. #ifdef unix
  44. #include <pwd.h>
  45. #include <sys/types.h>
  46. #include <sys/stat.h>
  47. #endif
  48.  
  49. /* Exit error codes */
  50. #define err_ok            0
  51. #define err_dest_open        1
  52. #define err_dest_write        2
  53. #define err_eof            3
  54. #define err_in_open        4
  55. #define err_no_begin        5
  56. #define err_no_end        6
  57. #define err_no_user        7
  58. #define err_out_close        8
  59. #define err_sect_seq        9
  60. #define err_sect_size        10
  61. #define err_size        11
  62. #define err_tilda_user        12
  63. #define err_usage        13
  64.  
  65. char section_str[] = "======= [ remove this line";
  66. #define section_str_sz (sizeof(section_str) - 1)
  67.  
  68. int    section = 0;    /* section flag and next section to get */
  69. long    written_size;    /* number of bytes written to output, used instead of
  70.                ftell, because ftell doesn't work with -f */
  71.  
  72. #define SUMSIZE 64
  73. #define DEC(c)    (((c) - ' ') & 077)    /* single character decode */
  74.  
  75. main(argc, argv)
  76. char **argv;
  77. {
  78. FILE    *in, *out;
  79. int    through_loop=0; /* Dejavu indicator */
  80. int    mode;        /* file's mode (from header) */
  81. long    filesize;    /* theoretical file size (from header) */
  82. char    dest[128];
  83. char    buf[80];
  84. int    f_option = 0;    /* set to 1 if -f option is present */
  85.  
  86. #ifdef AMIGA_LATTICE
  87. extern    int Enable_Abort;
  88.     Enable_Abort=1;
  89. #endif
  90.  
  91.     /* First, check for the -f option */
  92.     if (argc >= 2 && strcmp(argv[1], "-f") == 0)
  93.         {
  94.         f_option = 1;
  95.         argc--; argv++;
  96.         }
  97.  
  98.     /* A filename can be specified to be uudecoded, or nothing can
  99.     be specified, and the input will come from STDIN */
  100.  
  101.     switch (argc)
  102.     {
  103.     case 1:
  104.         if ( isatty(fileno(stdin)) )
  105.         {
  106.             fprintf(stderr, "\n\Usage: %s [-f] [infile]\n", argv[0]);
  107.             exit(err_usage);
  108.         }    
  109.     in=stdin;
  110.     break;
  111.  
  112.     case 2:
  113.         if ( stricmp(argv[1],"-h")==0 )
  114.             {
  115.             fprintf(stderr, "\n\Usage: %s [-f] [infile]\n", argv[0]);
  116.             exit(err_usage);
  117.             }
  118.     if ((in = fopen(argv[1], "rb")) == NULL)
  119.         {
  120.         fprintf(stderr, "\nError: can't find %s\n", argv[1]);
  121.         fprintf(stderr, "Usage: %s [-f] [infile]\n", argv[0]);
  122.         exit(err_in_open);
  123.         }
  124.     break;
  125.  
  126.     default:
  127.     fprintf(stderr, "\nUsage: %s [-f] [infile]\n", argv[0]);
  128.     exit(err_usage);
  129.     break;
  130.     }
  131.  
  132.     /* Loop through file, searching for headers.  Decode anything with a
  133.        header, complain if there where no headers. */
  134.  
  135. for (;;)
  136. {
  137.     /* search file for header line */
  138.     for (;;)
  139.     {
  140.     if (fgets(buf, sizeof buf, in) == NULL)
  141.         {
  142.         if (!through_loop)
  143.         {
  144.         fprintf(stderr, "ERROR: no `begin' line!\n");
  145.         exit(err_no_begin);
  146.         }
  147.         else
  148.         {
  149.         exit(err_ok);
  150.         }
  151.         }
  152.     if (strncmp(buf, "section 1 of uuencode", 21) == 0)
  153.         section = 1;
  154.     else if (strncmp(buf, "begin ", 6) == 0)
  155.         break;
  156.     }
  157.     sscanf(buf, "begin %o %s", &mode, dest);
  158.  
  159.     /* set up the output file */
  160.     if (f_option)
  161.         {
  162.         /* the -f option is used, so use stdout */
  163.     out = stdout;
  164.         }
  165.     else
  166.         {
  167.         /* the -f option is not used, so use the filename (and mode) in the
  168.          * begin line */
  169. #ifdef unix
  170.     /* handle ~user/file format */
  171.     if (dest[0] == '~')
  172.         {
  173.         char *sl;
  174.         struct passwd *getpwnam();
  175.         char *index();
  176.         struct passwd *user;
  177.         char dnbuf[100];
  178.  
  179.         sl = index(dest, '/');
  180.         if (sl == NULL)
  181.         {
  182.         fprintf(stderr, "Illegal ~user\n");
  183.             exit(err_tilda_user);
  184.         }
  185.         *sl++ = 0;
  186.         user = getpwnam(dest+1);
  187.         if (user == NULL)
  188.         {
  189.         fprintf(stderr, "No such user as %s\n", dest);
  190.         exit(err_no_user);
  191.         }
  192.         strcpy(dnbuf, user->pw_dir);
  193.         strcat(dnbuf, "/");
  194.         strcat(dnbuf, sl);
  195.         strcpy(dest, dnbuf);
  196.         }
  197. #endif
  198.  
  199.     /* create output file */
  200.     if ((out = fopen(dest, "wb")) == NULL)
  201.         {
  202.         fprintf(stderr, "ERROR: can't open output file %s\n", dest);
  203.         exit(err_dest_open);
  204.         }
  205. #ifdef unix
  206.     chmod(dest, mode);
  207. #endif
  208.        }
  209.  
  210.     /* actually decode the data */
  211.     decode(in, out, dest);
  212.  
  213.     if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3))
  214.     {           /* don't be overly picky about newline ^ */
  215.     fprintf(stderr, "ERROR: no `end' line\n");
  216.     exit(err_no_end);
  217.     }
  218.  
  219.     if (section) {
  220.     /* suck up the section trailer before the size line */
  221.     if (fgets(buf,sizeof buf,in) == NULL) {
  222.         fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  223.         exit(err_eof);
  224.     }
  225.     }
  226.     if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3)))
  227.     {
  228.     sscanf(buf, "size %ld", &filesize);
  229.     if (written_size != filesize)
  230.         {
  231.         fprintf(stderr,
  232.         "ERROR: file should have been %ld bytes long but was %ld.\n",
  233.         filesize, written_size);
  234.         exit(err_size);
  235.         }
  236.     }
  237.  
  238.     /* close the output file */
  239.     if (!f_option)
  240.         if (fclose(out) != 0)
  241.             {
  242.         fprintf(stderr, "ERROR: error closing file %s.\n", dest);
  243.         exit(err_out_close);
  244.         }
  245.  
  246.     through_loop = 1;
  247. }   /* forever */
  248. }   /* main */
  249.  
  250. /*
  251.  * Copy from in to out, decoding as you go.
  252.  * If a return or newline is encountered too early in a line, it is
  253.  * assumed that means that some editor has truncated trailing spaces.
  254.  */
  255. decode(in, out, dest)
  256. FILE *in;
  257. FILE *out;
  258. char *dest;
  259. {
  260. char buf[81];
  261. char *bp;
  262. int nosum=0;
  263. #ifndef unix
  264. extern errno;
  265. #endif
  266. int j;
  267. register int n;
  268. int checksum, line, section_size;
  269.  
  270.     /* zero the byte count and initial section size*/
  271.     section_size = written_size = 0;
  272.  
  273.     for (line = 1; ; line++)    /* for each input line */
  274.     {
  275.     if (fgets(buf, sizeof buf, in) == NULL)
  276.         {
  277.         fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  278.         exit(err_eof);
  279.         }
  280.  
  281.     /* Is this section finished? */
  282.     if (section &&
  283.         ((strncmp(buf, section_str, section_str_sz) == 0)
  284.         || buf[0] == '\n' || buf[0] == '\r')) {
  285.         long size;
  286.  
  287.         /* Scan for section size */
  288.         do {
  289.         line++;
  290.             if (fgets(buf, sizeof buf, in) == NULL) {
  291.             fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  292.             exit(err_eof);
  293.             }
  294.         n = sscanf(buf, "section size %ld", &size);
  295.         } while (n != 1);
  296.         line++;
  297.         if (section_size != size) {
  298.         fprintf(stderr, "ERROR: section size wrong!\n");
  299.         exit(err_sect_size);
  300.         }
  301.         section_size = 0;
  302.         section++;
  303.         /* Scan for start of next section */
  304.         for (n = 0; n != 1;) {
  305.         line++;
  306.         if (fgets(buf, sizeof buf, in) == NULL) {
  307.             fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  308.             exit(err_eof);
  309.         }
  310.         n = sscanf(buf, "section %d of uuencode", &j);
  311.         }
  312.         if (section != j) {
  313.         fprintf(stderr, "ERROR: section %d out of sequence!\n", j);
  314.         exit(err_sect_seq);
  315.         }
  316.         while (buf[0] != 'M') {
  317.         line++;
  318.         if (fgets(buf, sizeof buf, in) == NULL) {
  319.             fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  320.             exit(err_eof);
  321.         }
  322.         }
  323.     }
  324.     /* Pad end of lines in case some editor truncated trailing
  325.        spaces */
  326.  
  327.     for (n=0;n<79;n++)  /* search for first \r, \n or \000 */
  328.         {
  329.         if (buf[n]=='\176')     /* If BITNET made a twiddle, */
  330.         buf[n]='\136';     /* we make a caret           */
  331.         if (buf[n]=='\r'||buf[n]=='\n'||buf[n]=='\000')
  332.         break;
  333.         }
  334.     for (;n<79;n++)     /* when found, fill rest of line with space */
  335.         {
  336.         buf[n]=' ';
  337.         }
  338.     buf[79]=0;        /* terminate new string */
  339.  
  340.     checksum = 0;
  341.     n = DEC(buf[0]);
  342.     if (n <= 0)
  343.         break;    /* 0 bytes on a line??    Must be the last line */
  344.  
  345.     bp = &buf[1];
  346.  
  347.     /* FOUR input characters go into each THREE output characters */
  348.  
  349.     while (n >= 4)
  350.         {
  351.         j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
  352.         putc(j, out);
  353.         checksum += j;
  354.         written_size++;
  355.         section_size++;
  356.  
  357.         j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
  358.         putc(j, out);
  359.         checksum += j;
  360.         written_size++;
  361.         section_size++;
  362.  
  363.         j = DEC(bp[2]) << 6 | DEC(bp[3]);
  364.         putc(j, out);
  365.         checksum += j;
  366.         written_size++;
  367.         section_size++;
  368.  
  369.         checksum = checksum % SUMSIZE;
  370.         bp += 4;
  371.         n -= 3;
  372.         }
  373.  
  374.         j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
  375.         checksum += j;
  376.         if (n >= 1)
  377.             {
  378.             putc(j, out);
  379.             written_size++;
  380.             section_size++;
  381.             }
  382.         j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
  383.         checksum += j;
  384.         if (n >= 2)
  385.             {
  386.             putc(j, out);
  387.             written_size++;
  388.             section_size++;
  389.             }
  390.         j = DEC(bp[2]) << 6 | DEC(bp[3]);
  391.         checksum += j;
  392.         if (n >= 3)
  393.             {
  394.             putc(j, out);
  395.             written_size++;
  396.             section_size++;
  397.             }
  398.         checksum = checksum % SUMSIZE;
  399.         bp += 4;
  400.         n -= 3;
  401.  
  402. #ifndef unix
  403.      /* Error checking under UNIX??? You must be kidding... */
  404.      /* Check if an error occured while writing to that last line */
  405.     if (errno)
  406.         {
  407.         fprintf(stderr, "ERROR: error writing to %s\n",dest);
  408.         exit(err_dest_write);
  409.         }
  410. #endif
  411.  
  412.     /* The line has been decoded; now check that sum */
  413.  
  414.     nosum |= !isspace(*bp);
  415.     if (nosum && !section)            /* Is there a checksum at all?? */
  416.         {
  417.         if (checksum != DEC(*bp))    /* Does that checksum match? */
  418.         {
  419.         fprintf(stderr, "ERROR: checksum mismatch decoding %s, line %d.\n",dest, line);
  420.         }
  421.         }    /* sum */
  422.     }    /* line */
  423. }   /* function */
  424.  
  425. #ifdef unix
  426. /*
  427.  * Return the ptr in sp at which the character c appears;
  428.  * 0 if not found
  429.  */
  430. char *
  431. index(sp, c)
  432. register char *sp, c;
  433. {
  434.     do
  435.     {
  436.     if (*sp == c)
  437.         return(sp);
  438.     }
  439.     while (*sp++);
  440.  
  441.     return(0);
  442. }
  443. #endif
  444.