uuencode.c

Go to the documentation of this file.
00001 /*
00002  * This file is part of uudeview, the simple and friendly multi-part multi-
00003  * file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may
00004  * be contacted at [email protected]
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014  * GNU General Public License for more details.
00015  */
00016 
00017 #ifdef HAVE_CONFIG_H
00018 #ifdef _MSC_VER
00019 #include "config.h.win32"
00020 #else
00021 #include "config.h"
00022 #endif
00023 #endif
00024 
00025 #ifdef SYSTEM_WINDLL
00026 #include 
00027 #endif
00028 #ifdef SYSTEM_OS2
00029 #include 
00030 #endif
00031 
00032 #include 
00033 #include 
00034 #include 
00035 #include 
00036 #include 
00037 
00038 #ifdef STDC_HEADERS
00039 #include 
00040 #include 
00041 #endif
00042 #ifdef HAVE_UNISTD_H
00043 #include 
00044 #endif
00045 #ifdef HAVE_ERRNO_H
00046 #include 
00047 #endif
00048 
00049 #include uudeview.h>
00050 #include uuint.h>
00051 #include fptools.h>
00052 #include uustring.h>
00053 #include crc32.h>
00054 
00055 /* for braindead systems */
00056 #ifndef SEEK_SET
00057 #ifdef L_BEGIN
00058 #define SEEK_SET L_BEGIN
00059 #else
00060 #define SEEK_SET 0
00061 #endif
00062 #endif
00063 
00064 char * uuencode_id = "$Id: uuencode.c 260 2007-05-04 23:32:54Z csk $";
00065 
00066 #if 0
00067 /*
00068  * the End-Of-Line string. MIME enforces CRLF, so that's what we use. Some
00069  * implementations of uudecode will complain about a missing end line, since
00070  * they look for "end^J" but find "end^J^M". We don't care - especially be-
00071  * cause they still decode the file properly despite this complaint.
00072  */
00073 
00074 #ifndef EOLSTRING
00075 #define EOLSTRING "\015\012"
00076 #endif
00077 
00078 #else
00079 
00080 /*
00081  * Argh. Some delivery software (inews) has problems with the CRLF
00082  * line termination. Let's try native EOL and see if we run into
00083  * any problems.
00084  * This involves opening output files in text mode instead of binary
00085  */
00086 
00087 #ifndef EOLSTRING
00088 #define EOLSTRING "\n"
00089 #endif
00090 
00091 #endif
00092 
00093 
00094 /*
00095  * =========================================================================
00096  * User-configurable settings end here. Don't spy below unless you know what
00097  * you're doing.
00098  * =========================================================================
00099  */
00100 
00101 /*
00102  * Define End-Of-Line sequence
00103  */
00104 
00105 #ifdef EOLSTRING
00106 static unsigned char *eolstring = (unsigned char *) EOLSTRING;
00107 #else
00108 static unsigned char *eolstring = (unsigned char *) "\012";
00109 #endif
00110 
00111 /*
00112  * Content-Transfer-Encoding types for non-MIME encodings
00113  */
00114 
00115 #define CTE_UUENC "x-uuencode"
00116 #define CTE_XXENC "x-xxencode"
00117 #define CTE_BINHEX "x-binhex"
00118 #define CTE_YENC "x-yenc"
00119 
00120 #define CTE_TYPE(y) (((y)==B64ENCODED) ? "Base64" : \
00121  ((y)==UU_ENCODED) ? CTE_UUENC : \
00122  ((y)==XX_ENCODED) ? CTE_XXENC : \
00123  ((y)==PT_ENCODED) ? "8bit" : \
00124  ((y)==QP_ENCODED) ? "quoted-printable" : \
00125  ((y)==BH_ENCODED) ? CTE_BINHEX : \
00126  ((y)==YENC_ENCODED) ? CTE_YENC : "x-oops")
00127 
00128 /*
00129  * encoding tables
00130  */
00131 
00132 unsigned char UUEncodeTable[64] = {
00133   '`', '!', '"', '#', '$', '%', '&', '\'',
00134   '(', ')', '*', '+', ',', '-', '.', '/',
00135   '0', '1', '2', '3', '4', '5', '6', '7',
00136   '8', '9', ':', ';', ', '=', '>', '?',
00137   '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
00138   'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
00139   'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
00140   'X', 'Y', 'Z', '[', '\\',']', '^', '_'
00141 };
00142   
00143 
00144 unsigned char B64EncodeTable[64] = {
00145   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
00146   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
00147   'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
00148   'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
00149   'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
00150   'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
00151   'w', 'x', 'y', 'z', '0', '1', '2', '3',
00152   '4', '5', '6', '7', '8', '9', '+', '/'
00153 };
00154 
00155 unsigned char XXEncodeTable[64] = {
00156   '+', '-', '0', '1', '2', '3', '4', '5',
00157   '6', '7', '8', '9', 'A', 'B', 'C', 'D',
00158   'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
00159   'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
00160   'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
00161   'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
00162   'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
00163   's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
00164 };
00165 
00166 unsigned char BHEncodeTable[64] = {
00167   '!', '"', '#', '$', '%', '&', '\'', '(',
00168   ')', '*', '+', ',', '-', '0', '1', '2',
00169   '3', '4', '5', '6', '8', '9', '@', 'A', 
00170   'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 
00171   'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 
00172   'S', 'T', 'U', 'V', 'X', 'Y', 'Z', '[', 
00173   '`', 'a', 'b', 'c', 'd', 'e', 'f', 'h', 
00174   'i', 'j', 'k', 'l', 'm', 'p', 'q', 'r'
00175 };
00176 
00177 unsigned char HexEncodeTable[16] = {
00178   '0', '1', '2', '3', '4', '5', '6', '7',
00179   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
00180 };
00181 
00182 typedef struct {
00183   char *extension;
00184   char *mimetype;
00185 } mimemap;
00186 
00187 /*
00188  * This table maps a file's extension into a Content-Type. The current
00189  * official list can be downloaded as
00190  * ftp://ftp.isi.edu/in-notes/iana/assignments/media-type
00191  * I haven't listed any text types since it doesn't make sense to encode
00192  * them. Everything not on the list gets mapped to application/octet-stream
00193  */
00194 
00195 static mimemap mimetable[] = {
00196         { "gif",  "image/gif"        }, /* Grafics Interchange Format */
00197         { "jpg",  "image/jpeg"       }, /* JFIF encoded files */
00198         { "jpeg", "image/jpeg"       },
00199         { "tif",  "image/tiff"       }, /* Tag Image File Format */
00200         { "tiff", "image/tiff"       },
00201         { "cgm",  "image/cgm"        }, /* Computer Graphics Metafile */
00202         { "au",   "audio/basic"      }, /* 8kHz ulaw audio data */
00203         { "mov",  "video/quicktime"  }, /* Apple Quicktime */
00204         { "qt",   "video/quicktime"  }, /* Also infrequently used */
00205         { "mpeg", "video/mpeg"       }, /* Motion Picture Expert Group */
00206         { "mpg",  "video/mpeg"       },
00207         { "mp2",  "video/mpeg"       }, /* dito, MPEG-2 encoded files */
00208         { "mp3",  "audio/mpeg"       }, /* dito, MPEG-3 encoded files */
00209         { "ps",   "application/postscript" }, /* Postscript Language */
00210         { "zip",  "application/zip"  }, /* ZIP archive */
00211         { "doc",  "application/msword"},/* assume Microsoft Word */
00212         { NULL,   NULL               }
00213 };
00214 
00215 /*
00216  * the order of the following two tables must match the
00217  * Encoding Types definition in uudeview.h
00218  */
00219 
00220 /*
00221  * encoded bytes per line
00222  */
00223 
00224 static int bpl[8] = { 0, 45, 57, 45, 45, 0, 0, 128 };
00225 
00226 /*
00227  * tables
00228  */
00229 
00230 static unsigned char *etables[5] = {
00231   NULL,
00232   UUEncodeTable,
00233   B64EncodeTable,
00234   XXEncodeTable,
00235   BHEncodeTable
00236 };
00237 
00238 /*
00239  * variables to malloc upon initialization
00240  */
00241 
00242 char *uuestr_itemp;
00243 char *uuestr_otemp;
00244 
00245 /*
00246  * Encode one part of the data stream
00247  */
00248 
00249 static int 
00250 UUEncodeStream (FILE *outfile, FILE *infile, int encoding, long linperfile, crc32_t *crc, crc32_t *pcrc)
00251 {
00252   unsigned char *itemp = (unsigned char *) uuestr_itemp;
00253   unsigned char *otemp = (unsigned char *) uuestr_otemp;
00254   unsigned char *optr, *table, *tptr;
00255   int index, count;
00256   long line=0;
00257   size_t llen;
00258 
00259   if (outfile==NULL || infile==NULL ||
00260       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
00261        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
00262     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
00263                uustring (S_PARM_CHECK), "UUEncodeStream()");
00264     return UURET_ILLVAL;
00265   }
00266 
00267   /*
00268  * Special handling for plain text and quoted printable. Text is
00269  * read line oriented.
00270  */
00271 
00272   if (encoding == PT_ENCODED || encoding == QP_ENCODED) {
00273     while (!feof (infile) && (linperfile 00274       if (_FP_fgets ((char*)itemp, 255, infile) == NULL) {
00275         break;
00276       }
00277 
00278       itemp[255] = '\0';
00279       count = strlen ((char*)itemp);
00280 
00281       llen = 0;
00282       optr = otemp;
00283 
00284       /*
00285  * Busy Callback
00286  */
00287       
00288       if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
00289         UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
00290                    uustring (S_ENCODE_CANCEL));
00291         return UURET_CANCEL;
00292       }
00293 
00294       if (encoding == PT_ENCODED) {
00295         /*
00296  * If there is a line feed, replace by eolstring
00297  */
00298         if (count > 0 && itemp[count-1] == '\n') {
00299           const size_t n = strlen ((char*) eolstring);
00300           itemp[--count] = '\0';
00301           if (fwrite (itemp, 1, count, outfile) != count ||
00302               fwrite ((char *) eolstring, 1, n, outfile) != n) {
00303             return UURET_IOERR;
00304           }
00305         }
00306         else {
00307           if (fwrite (itemp, 1, count, outfile) != llen) {
00308             return UURET_IOERR;
00309           }
00310         }
00311       }
00312       else if (encoding == QP_ENCODED) {
00313         for (index=0; index00314           if (llen == 0 && itemp[index] == '.') {
00315             /*
00316  * Special rule: encode '.' at the beginning of a line, so
00317  * that some mailers aren't confused.
00318  */
00319             *optr++ = '=';
00320             *optr++ = HexEncodeTable[itemp[index] >> 4];
00321             *optr++ = HexEncodeTable[itemp[index] & 0x0f];
00322             llen += 3;
00323           }
00324           else if ((itemp[index] >= 33 && itemp[index] 00325                    (itemp[index] >= 62 && itemp[index] 00326                    itemp[index] == 9 || itemp[index] == 32) {
00327             *optr++ = itemp[index];
00328             llen++;
00329           }
00330           else if (itemp[index] == '\n') {
00331             /*
00332  * If the last character before EOL was a space or tab,
00333  * we must encode it. If llen > 74, there's no space to do
00334  * that, so generate a soft line break instead.
00335  */
00336 
00337             if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32)) {
00338               *(optr-1) = '=';
00339               if (llen 00340                 *optr++ = HexEncodeTable[itemp[index-1] >> 4];
00341                 *optr++ = HexEncodeTable[itemp[index-1] & 0x0f];
00342                 llen += 2;
00343               }
00344             }
00345 
00346             if (fwrite (otemp, 1, llen, outfile) != llen ||
00347                 fwrite ((char *) eolstring, 1,
00348                         strlen((char*)eolstring), outfile) != strlen ((char*)eolstring)) {
00349               return UURET_IOERR;
00350             }
00351 
00352             /*
00353  * Fix the soft line break condition from above
00354  */
00355 
00356             if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32) &&
00357                 *(optr-1) == '=') {
00358               otemp[0] = '=';
00359               otemp[1] = HexEncodeTable[itemp[index-1] >> 4];
00360               otemp[2] = HexEncodeTable[itemp[index-1] & 0x0f];
00361 
00362               if (fwrite (otemp, 1, 3, outfile) != 3 ||
00363                   fwrite ((char *) eolstring, 1,
00364                           strlen((char*)eolstring), outfile) != strlen ((char*)eolstring)) {
00365                 return UURET_IOERR;
00366               }
00367             }
00368 
00369             optr = otemp;
00370             llen = 0;
00371           }
00372           else {
00373             *optr++ = '=';
00374             *optr++ = HexEncodeTable[itemp[index] >> 4];
00375             *optr++ = HexEncodeTable[itemp[index] & 0x0f];
00376             llen += 3;
00377           }
00378 
00379           /*
00380  * Lines must be shorter than 76 characters (not counting CRLF).
00381  * If the line grows longer than that, we must include a soft
00382  * line break.
00383  */
00384 
00385           if (itemp[index+1] != 0 && itemp[index+1] != '\n' &&
00386               (llen >= 75 ||
00387                (!((itemp[index+1] >= 33 && itemp[index+1] 00388                   (itemp[index+1] >= 62 && itemp[index+1] 00389                 llen >= 73))) {
00390 
00391             *optr++ = '=';
00392             llen++;
00393             
00394             if (fwrite (otemp, 1, llen, outfile) != llen ||
00395                 fwrite ((char *) eolstring, 1,
00396                         strlen((char*)eolstring), outfile) != strlen ((char*)eolstring)) {
00397               return UURET_IOERR;
00398             }
00399             
00400             optr = otemp;
00401             llen = 0;
00402           }
00403         }
00404       }
00405 
00406       line++;
00407     }
00408 
00409     return UURET_OK;
00410   }
00411 
00412   /*
00413  * Special handling for yEnc
00414  */
00415 
00416   if (encoding == YENC_ENCODED) {
00417     llen = 0;
00418     optr = otemp;
00419 
00420     while (!feof (infile) && (linperfile 00421       if ((count = fread (itemp, 1, 128, infile)) != 128) {
00422         if (count == 0) {
00423           break;
00424         }
00425         else if (ferror (infile)) {
00426           return UURET_IOERR;
00427         }
00428       }
00429 
00430       if (pcrc)
00431         *pcrc = crc32(*pcrc, itemp, count);
00432       if (crc)
00433         *crc = crc32(*crc, itemp, count);
00434 
00435       line++;
00436 
00437       /*
00438  * Busy Callback
00439  */
00440       
00441       if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
00442         UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
00443                    uustring (S_ENCODE_CANCEL));
00444         return UURET_CANCEL;
00445       }
00446 
00447       for (index=0; index00448         if (llen > 127) {
00449           if (fwrite (otemp, 1, llen, outfile) != llen ||
00450               fwrite ((char *) eolstring, 1,
00451                       strlen((char*)eolstring), outfile) != strlen ((char*)eolstring)) {
00452             return UURET_IOERR;
00453           }
00454           llen = 0;
00455           optr = otemp;
00456         }
00457 
00458         switch ((char) ((int) itemp[index] + 42)) {
00459         case '\0':
00460         case '\t':
00461         case '\n':
00462         case '\r':
00463         case '=':
00464         case '\033':
00465           *optr++ = '=';
00466           *optr++ = (char) ((int) itemp[index] + 42 + 64);
00467           llen += 2;
00468           break;
00469 
00470         case '.':
00471           if (llen == 0) {
00472             *optr++ = '=';
00473             *optr++ = (char) ((int) itemp[index] + 42 + 64);
00474             llen += 2;
00475           }
00476           else {
00477             *optr++ = (char) ((int) itemp[index] + 42);
00478             llen++;
00479           }
00480           break;
00481 
00482         default:
00483           *optr++ = (char) ((int) itemp[index] + 42);
00484           llen++;
00485           break;
00486         }
00487       }
00488     }
00489 
00490     /*
00491  * write last line
00492  */
00493 
00494     if (llen) {
00495       if (fwrite (otemp, 1, llen, outfile) != llen ||
00496           fwrite ((char *) eolstring, 1,
00497                   strlen((char*)eolstring), outfile) != strlen ((char*)eolstring)) {
00498         return UURET_IOERR;
00499       }
00500     }
00501 
00502     return UURET_OK;
00503   }
00504 
00505   /*
00506  * Handling for binary encodings
00507  */
00508 
00509   /*
00510  * select charset
00511  */
00512 
00513   table = etables[encoding];
00514 
00515   if (table==NULL || bpl[encoding]==0) {
00516     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
00517                uustring (S_PARM_CHECK), "UUEncodeStream()");
00518     return UURET_ILLVAL;
00519   }
00520 
00521   while (!feof (infile) && (linperfile 00522     if ((count = fread (itemp, 1, bpl[encoding], infile)) != bpl[encoding]) {
00523       if (count == 0)
00524         break;
00525       else if (ferror (infile))
00526         return UURET_IOERR;
00527     }
00528 
00529     optr = otemp;
00530     llen = 0;
00531 
00532     /*
00533  * Busy Callback
00534  */
00535 
00536     if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
00537       UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
00538                  uustring (S_ENCODE_CANCEL));
00539       return UURET_CANCEL;
00540     }
00541 
00542     /*
00543  * for UU and XX, encode the number of bytes as first character
00544  */
00545 
00546     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
00547       *optr++ = table[count];
00548       llen++;
00549     }
00550 
00551     /*
00552  * Main encoding
00553  */
00554 
00555     for (index=0; index00556       *optr++ = table[itemp[index] >> 2];
00557       *optr++ = table[((itemp[index  ] & 0x03) > 4)];
00558       *optr++ = table[((itemp[index+1] & 0x0f) > 6)];
00559       *optr++ = table[  itemp[index+2] & 0x3f];
00560     }
00561 
00562     /*
00563  * Special handling for incomplete lines
00564  */
00565 
00566     if (index != count) {
00567       if (encoding == B64ENCODED) {
00568         if (count - index == 2) {
00569           *optr++ = table[itemp[index] >> 2];
00570           *optr++ = table[((itemp[index  ] & 0x03) 00571                           ((itemp[index+1] & 0xf0) >> 4)];
00572           *optr++ = table[((itemp[index+1] & 0x0f) 00573           *optr++ = '=';
00574         }
00575         else if (count - index == 1) {
00576           *optr++ = table[ itemp[index] >> 2];
00577           *optr++ = table[(itemp[index] & 0x03) 00578           *optr++ = '=';
00579           *optr++ = '=';
00580         }
00581         llen += 4;
00582       }
00583       else if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
00584         if (count - index == 2) {
00585           *optr++ = table[itemp[index] >> 2];
00586           *optr++ = table[((itemp[index  ] & 0x03) 00587                           ( itemp[index+1] >> 4)];
00588           *optr++ = table[((itemp[index+1] & 0x0f) 00589           *optr++ = table[0];
00590         }
00591         else if (count - index == 1) {
00592           *optr++ = table[ itemp[index] >> 2];
00593           *optr++ = table[(itemp[index] & 0x03) 00594           *optr++ = table[0];
00595           *optr++ = table[0];
00596         }
00597         llen += 4;
00598       }
00599     }
00600 
00601     /*
00602  * end of line
00603  */
00604 
00605     tptr = eolstring;
00606 
00607     while (*tptr)
00608       *optr++ = *tptr++;
00609 
00610     *optr++ = '\0';
00611     llen   += strlen ((char *) eolstring);
00612 
00613     if (fwrite (otemp, 1, llen, outfile) != llen)
00614       return UURET_IOERR;
00615 
00616     line++;
00617   }
00618   return UURET_OK;
00619 }
00620 
00621 /*
00622  * Encode as MIME multipart/mixed sub-message.
00623  */
00624 
00625 int UUEXPORT
00626 UUEncodeMulti (FILE *outfile, FILE *infile, char *infname, int encoding,
00627                char *outfname, char *mimetype, int filemode)
00628 {
00629   mimemap *miter=mimetable;
00630   struct stat finfo;
00631   int res, themode;
00632   FILE *theifile;
00633   char *ptr;
00634   crc32_t crc;
00635   crc32_t *crcptr=NULL;
00636 
00637   if (outfile==NULL || 
00638       (infile == NULL && infname==NULL) ||
00639       (outfname==NULL && infname==NULL) ||
00640       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
00641        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
00642     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
00643                uustring (S_PARM_CHECK), "UUEncodeMulti()");
00644     return UURET_ILLVAL;
00645   }
00646 
00647   progress.action = 0;
00648 
00649   if (infile==NULL) {
00650     if (stat (infname, &finfo) == -1) {
00651       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
00652                  uustring (S_NOT_STAT_FILE),
00653                  infname, strerror (uu_errno=errno));
00654       return UURET_IOERR;
00655     }
00656     if ((theifile = fopen (infname, "rb")) == NULL) {
00657       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
00658                  uustring (S_NOT_OPEN_FILE),
00659                  infname, strerror (uu_errno=errno));
00660       return UURET_IOERR;
00661     }
00662     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
00663     progress.fsize = (long) finfo.st_size;
00664   }
00665   else {
00666     if (fstat (fileno (infile), &finfo) != 0) {
00667       themode  = (filemode)?filemode:0644;
00668       progress.fsize = -1;
00669     }
00670     else {
00671       themode = (int) finfo.st_mode & 0777;
00672       progress.fsize = (long) finfo.st_size;
00673     }
00674     theifile = infile;
00675   }
00676 
00677   if (progress.fsize 00678     progress.fsize = -1;
00679 
00680   _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
00681 
00682   progress.partno   = 1;
00683   progress.numparts = 1;
00684   progress.percent  = 0;
00685   progress.foffset  = 0;
00686   progress.action   = UUACT_ENCODING;
00687 
00688   /*
00689  * If not given from outside, select an appropriate Content-Type by
00690  * looking at the file's extension. If it is unknown, default to
00691  * Application/Octet-Stream
00692  */
00693 
00694   if (mimetype == NULL) {
00695     if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.'))) {
00696       while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
00697         miter++;
00698       mimetype = miter->mimetype;
00699     }
00700   }
00701 
00702   if (mimetype == NULL && (encoding == PT_ENCODED || encoding == QP_ENCODED)) {
00703     mimetype = "text/plain";
00704   }
00705 
00706   /*
00707  * print sub-header
00708  */
00709 
00710   if (encoding != YENC_ENCODED) {
00711     fprintf (outfile, "Content-Type: %s%s",
00712              (mimetype)?mimetype:"Application/Octet-Stream",
00713              eolstring);
00714     fprintf (outfile, "Content-Transfer-Encoding: %s%s",
00715              CTE_TYPE(encoding), eolstring);
00716     fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
00717              UUFNameFilter ((outfname)?outfname:infname), eolstring);
00718     fprintf (outfile, "%s", eolstring);
00719   }
00720 
00721   if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
00722     fprintf (outfile, "begin %o %s%s",
00723              (themode) ? themode : 0644,
00724              UUFNameFilter ((outfname)?outfname:infname), 
00725              eolstring);
00726   }
00727   else if (encoding == YENC_ENCODED) {
00728     crc = crc32(0L, Z_NULL, 0);
00729     crcptr = &crc;
00730     if (progress.fsize == -1) {
00731       fprintf (outfile, "=ybegin line=128 name=%s%s",
00732                UUFNameFilter ((outfname)?outfname:infname), 
00733                eolstring);
00734     }
00735     else {
00736       fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
00737                progress.fsize,
00738                UUFNameFilter ((outfname)?outfname:infname), 
00739                eolstring);
00740     }
00741   }
00742 
00743   if ((res = UUEncodeStream (outfile, theifile, encoding, 0, crcptr, NULL)) != UURET_OK) {
00744     if (res != UURET_CANCEL) {
00745       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
00746                  uustring (S_ERR_ENCODING),
00747                  UUFNameFilter ((infname)?infname:outfname),
00748                  (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
00749     }
00750     progress.action = 0;
00751     return res;
00752   }
00753 
00754   if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
00755     fprintf (outfile, "%c%s",    
00756              (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0], 
00757              eolstring);
00758     fprintf (outfile, "end%s", eolstring);
00759   }
00760   else if (encoding == YENC_ENCODED) {
00761     if (progress.fsize == -1) {
00762       fprintf (outfile, "=yend crc32=%08lx%s",
00763                crc,
00764                eolstring);
00765     }
00766     else {
00767       fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
00768                progress.fsize,
00769                crc,
00770                eolstring);
00771     }
00772   }
00773 
00774   /*
00775  * empty line at end does no harm
00776  */
00777 
00778   fprintf (outfile, "%s", eolstring);
00779 
00780   if (infile==NULL)
00781     fclose (theifile);
00782 
00783   progress.action = 0;
00784   return UURET_OK;
00785 }
00786 
00787 /*
00788  * Encode as MIME message/partial
00789  */
00790 
00791 int UUEXPORT
00792 UUEncodePartial (FILE *outfile, FILE *infile,
00793                  char *infname, int encoding,
00794                  char *outfname, char *mimetype,
00795                  int filemode, int partno, long linperfile,
00796                  crc32_t *crcptr)
00797 {
00798   mimemap *miter=mimetable;
00799   static FILE *theifile;
00800   int themode, numparts=1;
00801   struct stat finfo;
00802   long thesize;
00803   char *ptr;
00804   int res;
00805   crc32_t pcrc;
00806   crc32_t *pcrcptr=NULL;
00807 
00808   if ((outfname==NULL&&infname==NULL) || partno00809       (infile == NULL&&infname==NULL) || outfile==NULL ||
00810       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
00811        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
00812     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
00813                uustring (S_PARM_CHECK), "UUEncodePartial()");
00814     return UURET_ILLVAL;
00815   }
00816 
00817   /*
00818  * The first part needs a set of headers
00819  */
00820 
00821   progress.action = 0;
00822 
00823   if (partno == 1) {
00824     if (infile==NULL) {
00825       if (stat (infname, &finfo) == -1) {
00826         UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
00827                    uustring (S_NOT_STAT_FILE),
00828                    infname, strerror (uu_errno=errno));
00829         return UURET_IOERR;
00830       }
00831       if ((theifile = fopen (infname, "rb")) == NULL) {
00832         UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
00833                    uustring (S_NOT_OPEN_FILE),
00834                    infname, strerror (uu_errno=errno));
00835         return UURET_IOERR;
00836       }
00837       if (linperfile 00838         numparts = 1;
00839       else 
00840         numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
00841                           (linperfile*bpl[encoding]));
00842 
00843       themode  = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
00844       thesize  = (long) finfo.st_size;
00845     }
00846     else {
00847       if (fstat (fileno (infile), &finfo) != 0) {
00848         UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
00849                    uustring (S_STAT_ONE_PART));
00850         numparts = 1;
00851         themode  = (filemode)?filemode:0644;
00852         thesize  = -1;
00853       }
00854       else {
00855         if (linperfile 00856           numparts = 1;
00857         else
00858           numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
00859                             (linperfile*bpl[encoding]));
00860 
00861         themode =  (int) finfo.st_mode & 0777;
00862         thesize = (long) finfo.st_size;
00863       }
00864       theifile = infile;
00865     }
00866 
00867     _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
00868 
00869     progress.totsize  = (thesize>=0) ? thesize : -1;
00870     progress.partno   = 1;
00871     progress.numparts = numparts;
00872     progress.percent  = 0;
00873     progress.foffset  = 0;
00874 
00875     /*
00876  * If not given from outside, select an appropriate Content-Type by
00877  * looking at the file's extension. If it is unknown, default to
00878  * Application/Octet-Stream
00879  */
00880 
00881     if (mimetype == NULL) {
00882       if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.'))) {
00883         while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
00884           miter++;
00885         mimetype = miter->mimetype;
00886       }
00887     }
00888 
00889     if (mimetype == NULL && (encoding==PT_ENCODED || encoding==QP_ENCODED)) {
00890       mimetype = "text/plain";
00891     }
00892 
00893     /*
00894  * print sub-header
00895  */
00896 
00897     if (encoding != YENC_ENCODED) {
00898       fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
00899       fprintf (outfile, "Content-Type: %s%s",
00900                (mimetype)?mimetype:"Application/Octet-Stream",
00901                eolstring);
00902       fprintf (outfile, "Content-Transfer-Encoding: %s%s",
00903                CTE_TYPE(encoding), eolstring);
00904       fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
00905                UUFNameFilter ((outfname)?outfname:infname), eolstring);
00906     }
00907 
00908     fprintf (outfile, "%s", eolstring);
00909     
00910     /*
00911  * for the first part of UU or XX messages, print a begin line
00912  */
00913 
00914     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
00915       fprintf (outfile, "begin %o %s%s",
00916                (themode) ? themode : ((filemode)?filemode:0644),
00917                UUFNameFilter ((outfname)?outfname:infname), eolstring);
00918     }
00919   }
00920   if (encoding == YENC_ENCODED) {
00921     pcrc = crc32(0L, Z_NULL, 0);
00922     pcrcptr = &pcrc;
00923     if (numparts != 1) {
00924       if (progress.totsize == -1) {
00925         fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
00926                  partno,
00927                  UUFNameFilter ((outfname)?outfname:infname), 
00928                  eolstring);
00929       }
00930       else {
00931         fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
00932                  partno,
00933                  progress.totsize,
00934                  UUFNameFilter ((outfname)?outfname:infname), 
00935                  eolstring);
00936       }
00937 
00938       fprintf (outfile, "=ypart begin=%ld end=%ld%s",
00939                (partno-1)*linperfile*128+1,
00940                (partno*linperfile*128) progress.totsize ? 
00941                (partno*linperfile*128) : progress.totsize,
00942                eolstring);
00943     }
00944     else {
00945       if (progress.totsize == -1) {
00946         fprintf (outfile, "=ybegin line=128 name=%s%s",
00947                  UUFNameFilter ((outfname)?outfname:infname), 
00948                  eolstring);
00949       }
00950       else {
00951         fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
00952                  progress.totsize,
00953                  UUFNameFilter ((outfname)?outfname:infname), 
00954                  eolstring);
00955       }
00956     }
00957   }
00958 
00959   /*
00960  * update progress information
00961  */
00962 
00963   progress.partno  = partno;
00964   progress.percent = 0;
00965   progress.foffset = ftell (theifile);
00966 
00967   if (progress.totsize 00968     progress.fsize = -1;
00969   else if (linperfile 00970     progress.fsize = progress.totsize;
00971   else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
00972     progress.fsize = progress.totsize - progress.foffset;
00973   else
00974     progress.fsize = linperfile*bpl[encoding];
00975 
00976   progress.action  = UUACT_ENCODING;
00977 
00978   if ((res = UUEncodeStream (outfile, theifile, encoding, linperfile,
00979                              crcptr, pcrcptr)) != UURET_OK) {
00980     if (infile==NULL) fclose (theifile);
00981     if (res != UURET_CANCEL) {
00982       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
00983                  uustring (S_ERR_ENCODING),
00984                  UUFNameFilter ((outfname)?outfname:infname),
00985                  (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
00986     }
00987     progress.action = 0;
00988     return res;
00989   }
00990 
00991   /*
00992  * print end line
00993  */
00994 
00995   if (feof (theifile) &&
00996       (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
00997     fprintf (outfile, "%c%s",    
00998              (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0], 
00999              eolstring);
01000     fprintf (outfile, "end%s", eolstring);
01001   }
01002   else if (encoding == YENC_ENCODED) {
01003     if (numparts != 1) {
01004       fprintf (outfile, "=yend size=%ld part=%d pcrc32=%08lx",
01005                (partno*linperfile*128) progress.totsize ? 
01006                linperfile*128 : (progress.totsize-(partno-1)*linperfile*128),
01007                partno,
01008                pcrc);
01009     }
01010     else {
01011       fprintf (outfile, "=yend size=%ld",
01012                progress.totsize);
01013     }
01014     if (feof (theifile))
01015       fprintf (outfile, " crc32=%08lx", *crcptr);
01016     fprintf (outfile, "%s", eolstring);
01017   }
01018 
01019   /*
01020  * empty line at end does no harm
01021  */
01022 
01023   if (encoding != PT_ENCODED && encoding != QP_ENCODED) {
01024     fprintf (outfile, "%s", eolstring);
01025   }
01026 
01027   if (infile==NULL) {
01028     if (res != UURET_OK) {
01029       progress.action = 0;
01030       fclose (theifile);
01031       return res;
01032     }
01033     if (feof (theifile)) {
01034       progress.action = 0;
01035       fclose (theifile);
01036       return UURET_OK;
01037     }
01038     return UURET_CONT;
01039   }
01040 
01041   /*
01042  * leave progress.action as-is
01043  */
01044 
01045   return UURET_OK;
01046 }
01047 
01048 /*
01049  * send output to a stream, don't do any headers at all
01050  */
01051 
01052 int UUEXPORT
01053 UUEncodeToStream (FILE *outfile, FILE *infile,
01054                   char *infname, int encoding,
01055                   char *outfname, int filemode)
01056 {
01057   struct stat finfo;
01058   FILE *theifile;
01059   int themode;
01060   int res;
01061   crc32_t crc;
01062   crc32_t *crcptr=NULL;
01063 
01064   if (outfile==NULL ||
01065       (infile == NULL&&infname==NULL) ||
01066       (outfname==NULL&&infname==NULL) ||
01067       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
01068        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
01069     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01070                uustring (S_PARM_CHECK), "UUEncodeToStream()");
01071     return UURET_ILLVAL;
01072   }
01073 
01074   progress.action = 0;
01075 
01076   if (infile==NULL) {
01077     if (stat (infname, &finfo) == -1) {
01078       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01079                  uustring (S_NOT_STAT_FILE),
01080                  infname, strerror (uu_errno=errno));
01081       return UURET_IOERR;
01082     }
01083     if ((theifile = fopen (infname, "rb")) == NULL) {
01084       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01085                  uustring (S_NOT_OPEN_FILE),
01086                  infname, strerror (uu_errno=errno));
01087       return UURET_IOERR;
01088     }
01089     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
01090     progress.fsize = (long) finfo.st_size;
01091   }
01092   else {
01093     if (fstat (fileno (infile), &finfo) == -1) {
01094       /* gotta live with it */
01095       themode = 0644;
01096       progress.fsize = -1;
01097     }
01098     else {
01099       themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
01100       progress.fsize = (long) finfo.st_size;
01101     }
01102     theifile = infile;
01103   }
01104 
01105   if (progress.fsize 01106     progress.fsize = -1;
01107 
01108   _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
01109 
01110   progress.partno   = 1;
01111   progress.numparts = 1;
01112   progress.percent  = 0;
01113   progress.foffset  = 0;
01114   progress.action   = UUACT_ENCODING;
01115 
01116   if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
01117     fprintf (outfile, "begin %o %s%s",
01118              (themode) ? themode : 0644,
01119              UUFNameFilter ((outfname)?outfname:infname), 
01120              eolstring);
01121   }
01122   else if (encoding == YENC_ENCODED) {
01123     crc = crc32(0L, Z_NULL, 0);
01124     crcptr = &crc;
01125     if (progress.fsize == -1) {
01126       fprintf (outfile, "=ybegin line=128 name=%s%s",
01127                UUFNameFilter ((outfname)?outfname:infname), 
01128                eolstring);
01129     }
01130     else {
01131       fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
01132                progress.fsize,
01133                UUFNameFilter ((outfname)?outfname:infname), 
01134                eolstring);
01135     }
01136   }
01137 
01138   if ((res = UUEncodeStream (outfile, theifile, encoding, 0, crcptr, NULL)) != UURET_OK) {
01139     if (res != UURET_CANCEL) {
01140       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01141                  uustring (S_ERR_ENCODING),
01142                  UUFNameFilter ((infname)?infname:outfname), 
01143                  (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
01144     }
01145     progress.action = 0;
01146     return res;
01147   }
01148 
01149   if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
01150     fprintf (outfile, "%c%s",    
01151              (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0], 
01152              eolstring);
01153     fprintf (outfile, "end%s", eolstring);
01154   }
01155   else if (encoding == YENC_ENCODED) {
01156     if (progress.fsize == -1) {
01157       fprintf (outfile, "=yend crc32=%08lx%s",
01158                crc,
01159                eolstring);
01160     }
01161     else {
01162       fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
01163                progress.fsize,
01164                crc,
01165                eolstring);
01166     }
01167   }
01168 
01169   /*
01170  * empty line at end does no harm
01171  */
01172 
01173   fprintf (outfile, "%s", eolstring);
01174 
01175   if (infile==NULL) fclose (theifile);
01176   progress.action = 0;
01177 
01178   return UURET_OK;
01179 }
01180 
01181 /*
01182  * Encode to files on disk, don't generate any headers
01183  */
01184 
01185 int UUEXPORT
01186 UUEncodeToFile (FILE *infile, char *infname, int encoding,
01187                 char *outfname, char *diskname, long linperfile)
01188 {
01189   int part, numparts, len, filemode, res;
01190   char *oname=NULL, *optr, *ptr;
01191   FILE *theifile, *outfile;
01192   struct stat finfo;
01193   crc32_t pcrc, crc;
01194   crc32_t *pcrcptr=NULL, *crcptr=NULL;
01195 
01196   if ((diskname==NULL&&infname==NULL) ||
01197       (outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
01198       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
01199        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
01200     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01201                uustring (S_PARM_CHECK), "UUEncodeToFile()");
01202     return UURET_ILLVAL;
01203   }
01204 
01205   if (diskname) {
01206     if ((ptr = strchr (diskname, '/')) == NULL)
01207       ptr = strchr (diskname, '\\');
01208     if (ptr) {
01209       len = strlen (diskname) + ((uuencodeext)?strlen(uuencodeext):3) + 5;
01210 
01211       if ((oname = malloc (len)) == NULL) {
01212         UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01213                    uustring (S_OUT_OF_MEMORY), len);
01214         return UURET_NOMEM;
01215       }
01216       sprintf (oname, "%s", diskname);
01217     }
01218     else {
01219       len = ((uusavepath)?strlen(uusavepath):0) + strlen (diskname) 
01220         + ((uuencodeext)?strlen(uuencodeext):0) + 5;
01221 
01222       if ((oname = malloc (len)) == NULL) {
01223         UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01224                    uustring (S_OUT_OF_MEMORY), len);
01225         return UURET_NOMEM;
01226       }
01227       sprintf (oname, "%s%s", (uusavepath)?uusavepath:"", diskname);
01228     }
01229   }
01230   else {
01231     len = ((uusavepath) ? strlen (uusavepath) : 0) + 
01232       strlen(UUFNameFilter(infname)) +
01233         ((uuencodeext)?strlen(uuencodeext):0) + 5;
01234 
01235     if ((oname = malloc (len)) == NULL) {
01236       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01237                  uustring (S_OUT_OF_MEMORY), len);
01238       return UURET_NOMEM;
01239     }
01240     optr = UUFNameFilter (infname);
01241     sprintf (oname, "%s%s", 
01242              (uusavepath)?uusavepath:"",
01243              (*optr=='.')?optr+1:optr);
01244   }
01245 
01246   /*
01247  * optr points after the last dot, so that we can print the part number
01248  * there.
01249  */
01250 
01251   optr = _FP_strrchr (oname, '.');
01252   if (optr==NULL || strchr (optr, '/')!=NULL || strchr (optr, '\\')!=NULL) {
01253     optr = oname + strlen (oname);
01254     *optr++ = '.';
01255   }
01256   else if (optr==oname || *(optr-1)=='/' || *(optr-1)=='\\') {
01257     optr = oname + strlen (oname);
01258     *optr++ = '.';
01259   }
01260   else
01261     optr++;
01262 
01263   progress.action = 0;
01264 
01265   if (infile==NULL) {
01266     if (stat (infname, &finfo) == -1) {
01267       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01268                  uustring (S_NOT_STAT_FILE),
01269                  infname, strerror (uu_errno=errno));
01270       _FP_free (oname);
01271       return UURET_IOERR;
01272     }
01273     if ((theifile = fopen (infname, "rb")) == NULL) {
01274       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01275                  uustring (S_NOT_OPEN_FILE),
01276                  infname, strerror (uu_errno=errno));
01277       _FP_free (oname);
01278       return UURET_IOERR;
01279     }
01280     if (linperfile 01281       numparts = 1;
01282     else 
01283       numparts = (int) (((long)finfo.st_size + (linperfile*bpl[encoding]-1)) /
01284                         (linperfile*bpl[encoding]));
01285 
01286     filemode = (int) finfo.st_mode & 0777;
01287     progress.totsize = (long) finfo.st_size;
01288   }
01289   else {
01290     if (fstat (fileno (infile), &finfo) == -1) {
01291       /* gotta live with it */
01292       filemode = 0644;
01293       numparts = -1;
01294       progress.totsize = -1;
01295     }
01296     else {
01297       if (linperfile 01298         numparts = 1;
01299       else
01300         numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
01301                           (linperfile*bpl[encoding]));
01302 
01303       filemode = (int) finfo.st_mode & 0777;
01304       progress.totsize = -1;
01305     }
01306     theifile = infile;
01307   }
01308 
01309   _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
01310 
01311   progress.totsize  = (progress.totsizeprogress.totsize;
01312   progress.numparts = numparts;
01313 
01314   for (part=1; !feof (theifile); part++) {
01315     /*
01316  * Attach extension
01317  */
01318     if (progress.numparts==1 && progress.totsize!=-1 && uuencodeext!=NULL)
01319       strcpy  (optr, uuencodeext);
01320     else 
01321       sprintf (optr, "%03d", part);
01322 
01323     /*
01324  * check if target file exists
01325  */
01326 
01327     if (!uu_overwrite) {
01328       if (stat (oname, &finfo) == 0) {
01329         UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01330                    uustring (S_TARGET_EXISTS), oname);
01331         if (infile==NULL) fclose (theifile);
01332         progress.action = 0;
01333         free (oname);
01334         return UURET_EXISTS;
01335       }
01336     }
01337 
01338     /*
01339  * update progress information
01340  */
01341 
01342     progress.action  = 0;
01343     progress.partno  = part;
01344     progress.percent = 0;
01345     progress.foffset = ftell (theifile);
01346 
01347     if (progress.totsize == -1)
01348       progress.fsize = -1;
01349     else if (linperfile 01350       progress.fsize = progress.totsize;
01351     else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
01352       progress.fsize = progress.totsize - progress.foffset;
01353     else
01354       progress.fsize = linperfile*bpl[encoding];
01355 
01356     progress.action  = UUACT_ENCODING;
01357 
01358     if ((outfile = fopen (oname, "w")) == NULL) {
01359       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01360                  uustring (S_NOT_OPEN_TARGET),
01361                  oname, strerror (uu_errno = errno));
01362       if (infile==NULL) fclose (theifile);
01363       progress.action = 0;
01364       free (oname);
01365       return UURET_IOERR;
01366     }
01367 
01368     if (encoding != YENC_ENCODED) {
01369       fprintf (outfile, "%s", eolstring);
01370       fprintf (outfile, "_=_ %s", eolstring);
01371       if (numparts == -1)
01372         fprintf (outfile, "_=_ Part %03d of file %s%s",
01373                  part, UUFNameFilter ((outfname)?outfname:infname),
01374                  eolstring);
01375       else
01376         fprintf (outfile, "_=_ Part %03d of %03d of file %s%s",
01377                  part, numparts,
01378                  UUFNameFilter ((outfname)?outfname:infname),
01379                  eolstring);
01380       fprintf (outfile, "_=_ %s", eolstring);
01381       fprintf (outfile, "%s", eolstring);
01382     }
01383 
01384     if (part==1 && (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
01385       fprintf (outfile, "begin %o %s%s",
01386                (filemode)?filemode : 0644,
01387                UUFNameFilter ((outfname)?outfname:infname), 
01388                eolstring);
01389     }
01390     else if (encoding == YENC_ENCODED) {
01391       if (!crcptr) {
01392         crc = crc32(0L, Z_NULL, 0);
01393         crcptr = &crc;
01394       }
01395       pcrc = crc32(0L, Z_NULL, 0);
01396       pcrcptr = &pcrc;
01397       if (numparts != 1) {
01398         if (progress.totsize == -1) {
01399           fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
01400                    part,
01401                    UUFNameFilter ((outfname)?outfname:infname), 
01402                    eolstring);
01403         }
01404         else {
01405           fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
01406                    part,
01407                    progress.totsize,
01408                    UUFNameFilter ((outfname)?outfname:infname), 
01409                    eolstring);
01410         }
01411 
01412         fprintf (outfile, "=ypart begin=%ld end=%ld%s",
01413                  (part-1)*linperfile*128+1,
01414                  (part*linperfile*128) progress.totsize ? 
01415                  (part*linperfile*128) : progress.totsize,
01416                  eolstring);
01417       }
01418       else {
01419         if (progress.totsize == -1) {
01420           fprintf (outfile, "=ybegin line=128 name=%s%s",
01421                    UUFNameFilter ((outfname)?outfname:infname), 
01422                    eolstring);
01423         }
01424         else {
01425           fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
01426                    progress.totsize,
01427                    UUFNameFilter ((outfname)?outfname:infname), 
01428                    eolstring);
01429         }
01430       }
01431     }
01432 
01433     if ((res = UUEncodeStream (outfile, theifile,
01434                                encoding, linperfile, crcptr, pcrcptr)) != UURET_OK) {
01435       if (res != UURET_CANCEL) {
01436         UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01437                    uustring (S_ERR_ENCODING),
01438                    UUFNameFilter ((infname)?infname:outfname),   
01439                    (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
01440       }
01441       if (infile==NULL) fclose (theifile);
01442       progress.action = 0;
01443       fclose (outfile);
01444       unlink (oname);
01445       _FP_free (oname);
01446       return res;
01447     }
01448 
01449     if (feof (theifile) &&
01450         (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
01451       fprintf (outfile, "%c%s",    
01452                (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0], 
01453                eolstring);
01454       fprintf (outfile, "end%s", eolstring);
01455     }
01456     else if (encoding == YENC_ENCODED) {
01457       if (numparts != 1) {
01458         fprintf (outfile, "=yend size=%ld part=%d pcrc32=%08lx",
01459                  (part*linperfile*128) progress.totsize ? 
01460                  linperfile*128 : (progress.totsize-(part-1)*linperfile*128),
01461                  part,
01462                  pcrc);
01463       }
01464       else {
01465         fprintf (outfile, "=yend size=%ld",
01466                  progress.totsize);
01467       }
01468       if (feof (theifile))
01469         fprintf (outfile, " crc32=%08lx", crc); 
01470       fprintf (outfile, "%s", eolstring);
01471     }
01472 
01473     /*
01474  * empty line at end does no harm
01475  */
01476 
01477     fprintf (outfile, "%s", eolstring);
01478     fclose  (outfile);
01479   }
01480 
01481   if (infile==NULL) fclose (theifile);
01482   progress.action = 0;
01483   _FP_free (oname);
01484   return UURET_OK;
01485 }
01486 
01487 /*
01488  * Encode a MIME Mail message or Newsgroup posting and send to a
01489  * stream. Still needs a somewhat smart MDA, since we only gene-
01490  * rate a minimum set of headers.
01491  */
01492 
01493 int UUEXPORT
01494 UUE_PrepSingle (FILE *outfile, FILE *infile,
01495                 char *infname, int encoding,
01496                 char *outfname, int filemode,
01497                 char *destination, char *from,
01498                 char *subject, int isemail)
01499 {
01500   return UUE_PrepSingleExt (outfile, infile,
01501                             infname, encoding,
01502                             outfname, filemode,
01503                             destination, from,
01504                             subject, NULL,
01505                             isemail);
01506 }
01507 
01508 int UUEXPORT
01509 UUE_PrepSingleExt (FILE *outfile, FILE *infile,
01510                    char *infname, int encoding,
01511                    char *outfname, int filemode,
01512                    char *destination, char *from,
01513                    char *subject, char *replyto,
01514                    int isemail)
01515 {
01516   mimemap *miter=mimetable;
01517   char *subline, *oname;
01518   char *mimetype, *ptr;
01519   int res, len;
01520 
01521   if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
01522       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
01523        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
01524     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01525                uustring (S_PARM_CHECK), "UUE_PrepSingle()");
01526     return UURET_ILLVAL;
01527   }
01528 
01529   oname = UUFNameFilter ((outfname)?outfname:infname);
01530   len   = ((subject)?strlen(subject):0) + strlen(oname) + 40;
01531 
01532   if ((ptr = _FP_strrchr (oname, '.'))) {
01533     while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
01534       miter++;
01535     mimetype = miter->mimetype;
01536   }
01537   else
01538     mimetype = NULL;
01539 
01540   if (mimetype == NULL && (encoding == PT_ENCODED || encoding == QP_ENCODED)) {
01541     mimetype = "text/plain";
01542   }
01543 
01544   if ((subline = (char *) malloc (len)) == NULL) {
01545     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01546                uustring (S_OUT_OF_MEMORY), len);
01547     return UURET_NOMEM;
01548   }
01549 
01550   if (encoding == YENC_ENCODED) {
01551     if (subject)
01552       sprintf (subline, "- %s - %s (001/001)", oname, subject);
01553     else
01554       sprintf (subline, "- %s - (001/001)", oname);
01555   }
01556   else {
01557     if (subject)
01558       sprintf (subline, "%s (001/001) - [ %s ]", subject, oname);
01559     else
01560       sprintf (subline, "[ %s ] (001/001)", oname);
01561   }
01562 
01563   if (from) {
01564     fprintf (outfile, "From: %s%s", from, eolstring);
01565   }
01566   if (destination) {
01567     fprintf (outfile, "%s: %s%s",
01568              (isemail)?"To":"Newsgroups",
01569              destination, eolstring);
01570   }
01571 
01572   fprintf (outfile, "Subject: %s%s", subline, eolstring);
01573 
01574   if (replyto) {
01575     fprintf (outfile, "Reply-To: %s%s", replyto, eolstring);
01576   }
01577 
01578   if (encoding != YENC_ENCODED) {
01579     fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
01580     fprintf (outfile, "Content-Type: %s; name=\"%s\"%s",
01581              (mimetype)?mimetype:"Application/Octet-Stream",
01582              UUFNameFilter ((outfname)?outfname:infname),
01583              eolstring);
01584     fprintf (outfile, "Content-Transfer-Encoding: %s%s",
01585              CTE_TYPE(encoding), eolstring);
01586   }
01587 
01588   fprintf (outfile, "%s", eolstring);
01589 
01590   res = UUEncodeToStream (outfile, infile, infname, encoding,
01591                           outfname, filemode);
01592   
01593   _FP_free (subline);
01594   return res;
01595 }
01596 
01597 int UUEXPORT
01598 UUE_PrepPartial (FILE *outfile, FILE *infile,
01599                  char *infname, int encoding,
01600                  char *outfname, int filemode,
01601                  int partno, long linperfile, long filesize,
01602                  char *destination, char *from, char *subject,
01603                  int isemail)
01604 {
01605   return UUE_PrepPartialExt (outfile, infile,
01606                              infname, encoding,
01607                              outfname, filemode,
01608                              partno, linperfile, filesize,
01609                              destination,
01610                              from, subject, NULL,
01611                              isemail);
01612 }
01613 
01614 int UUEXPORT
01615 UUE_PrepPartialExt (FILE *outfile, FILE *infile,
01616                     char *infname, int encoding,
01617                     char *outfname, int filemode,
01618                     int partno, long linperfile, long filesize,
01619                     char *destination,
01620                     char *from, char *subject, char *replyto,
01621                     int isemail)
01622 {
01623   static int numparts, themode;
01624   static char mimeid[64];
01625   static FILE *theifile;
01626   struct stat finfo;
01627   char *subline, *oname;
01628   long thesize;
01629   int res, len;
01630   static crc32_t crc;
01631   crc32_t *crcptr=NULL;
01632 
01633   if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
01634       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
01635        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
01636     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01637                uustring (S_PARM_CHECK), "UUE_PrepPartial()");
01638     return UURET_ILLVAL;
01639   }
01640 
01641   oname = UUFNameFilter ((outfname)?outfname:infname);
01642   len   = ((subject)?strlen(subject):0) + strlen (oname) + 40;
01643 
01644   /*
01645  * if first part, get information about the file
01646  */
01647 
01648   if (partno == 1) {
01649     if (infile==NULL) {
01650       if (stat (infname, &finfo) == -1) {
01651         UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01652                    uustring (S_NOT_STAT_FILE),
01653                    infname, strerror (uu_errno=errno));
01654         return UURET_IOERR;
01655       }
01656       if ((theifile = fopen (infname, "rb")) == NULL) {
01657         UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01658                    uustring (S_NOT_OPEN_FILE),
01659                    infname, strerror (uu_errno=errno));
01660         return UURET_IOERR;
01661       }
01662       if (linperfile 01663         numparts = 1;
01664       else 
01665         numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
01666                           (linperfile*bpl[encoding]));
01667 
01668       themode  = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
01669       thesize  = (long) finfo.st_size;
01670     }
01671     else {
01672       if (fstat (fileno (infile), &finfo) != 0) {
01673         if (filesize 01674           UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
01675                      uustring (S_STAT_ONE_PART));
01676           numparts = 1;
01677           themode  = (filemode)?filemode:0644;
01678           thesize  = -1;
01679         }
01680         else {
01681           if (linperfile 01682             numparts = 1;
01683           else
01684             numparts = (int) ((filesize+(linperfile*bpl[encoding]-1))/
01685                               (linperfile*bpl[encoding]));
01686 
01687           themode  = (filemode)?filemode:0644;
01688           thesize  = filesize;
01689         }
01690       }
01691       else {
01692         if (linperfile 01693           numparts = 1;
01694         else
01695           numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
01696                             (linperfile*bpl[encoding]));
01697 
01698         filemode = (int) finfo.st_mode & 0777;
01699         thesize  = (long) finfo.st_size;
01700       }
01701       theifile = infile;
01702     }
01703 
01704     /*
01705  * if there's one part only, don't use Message/Partial
01706  */
01707 
01708     if (numparts == 1) {
01709       if (infile==NULL) fclose (theifile);
01710       return UUE_PrepSingleExt (outfile, infile, infname, encoding,
01711                                 outfname, filemode, destination,
01712                                 from, subject, replyto, isemail);
01713     }
01714 
01715     /*
01716  * we also need a unique ID
01717  */
01718 
01719     sprintf (mimeid, "UUDV-%ld.%ld.%s",
01720              (long) time(NULL), thesize,
01721              (strlen(oname)>16)?"oops":oname);
01722   }
01723 
01724   if ((subline = (char *) malloc (len)) == NULL) {
01725     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
01726                uustring (S_OUT_OF_MEMORY), len);
01727     if (infile==NULL) fclose (theifile);
01728     return UURET_NOMEM;
01729   }
01730 
01731 
01732   if (encoding == YENC_ENCODED) {
01733     if (partno == 1)
01734       crc = crc32(0L, Z_NULL, 0);
01735     crcptr = &crc;
01736     if (subject)
01737       sprintf (subline, "- %s - %s (%03d/%03d)", oname, subject,
01738                partno, numparts);
01739     else
01740       sprintf (subline, "- %s - (%03d/%03d)", oname,
01741                partno, numparts);
01742   }
01743   else {
01744     if (subject)
01745       sprintf (subline, "%s (%03d/%03d) - [ %s ]", 
01746                subject, partno, numparts, oname);
01747     else
01748       sprintf (subline, "[ %s ] (%03d/%03d)",
01749                oname, partno, numparts);
01750   }
01751 
01752   if (from) {
01753     fprintf (outfile, "From: %s%s", from, eolstring);
01754   }
01755 
01756   if (destination) {
01757     fprintf (outfile, "%s: %s%s",
01758              (isemail)?"To":"Newsgroups",
01759              destination, eolstring);
01760   }
01761 
01762   fprintf (outfile, "Subject: %s%s", subline, eolstring);
01763 
01764   if (replyto) {
01765     fprintf (outfile, "Reply-To: %s%s", replyto, eolstring);
01766   }
01767 
01768   if (encoding != YENC_ENCODED) {
01769     fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
01770     fprintf (outfile, "Content-Type: Message/Partial; number=%d; total=%d;%s",
01771              partno, numparts, eolstring);
01772     fprintf (outfile, "\tid=\"%s\"%s",
01773              mimeid, eolstring);
01774   }
01775     
01776   fprintf (outfile, "%s", eolstring);
01777 
01778   res = UUEncodePartial (outfile, theifile,
01779                          infname, encoding,
01780                          (outfname)?outfname:infname, NULL,
01781                          themode, partno, linperfile, crcptr);
01782 
01783   _FP_free (subline);
01784 
01785   if (infile==NULL) {
01786     if (res != UURET_OK) {
01787       fclose (theifile);
01788       return res;
01789     }
01790     if (feof (theifile)) {
01791       fclose (theifile);
01792       return UURET_OK;
01793     }
01794     return UURET_CONT;
01795   }
01796 
01797   return res;
01798 }

Generated on Sun Oct 12 01:45:30 2008 for NNTPGrab by  1.5.4