1 /*
2  * This file is part of uudeview, the simple and friendly multi-part multi-
3  * file uudecoder  program  (c) 1994-2001 by Frank Pilhofer. The author may
4  * be contacted at fp@fpx.de
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #ifdef SYSTEM_WINDLL
22 #include <windows.h>
23 #endif
24 #ifdef SYSTEM_OS2
25 #include <os2.h>
26 #endif
27 
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <time.h>
33 
34 #ifdef STDC_HEADERS
35 #include <stdlib.h>
36 #include <string.h>
37 #endif
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #ifdef HAVE_ERRNO_H
42 #include <errno.h>
43 #endif
44 
45 #include <uudeview.h>
46 #include <uuint.h>
47 #include <fptools.h>
48 #include <uustring.h>
49 #include <crc32.h>
50 
51 /* for braindead systems */
52 #ifndef SEEK_SET
53 #ifdef L_BEGIN
54 #define SEEK_SET L_BEGIN
55 #else
56 #define SEEK_SET 0
57 #endif
58 #endif
59 
60 char * uuencode_id = "$Id: uuencode.c,v 1.22 2002/04/02 10:04:52 fp Exp $";
61 
62 #if 0
63 /*
64  * the End-Of-Line string. MIME enforces CRLF, so that's what we use. Some
65  * implementations of uudecode will complain about a missing end line, since
66  * they look for "end^J" but find "end^J^M". We don't care - especially be-
67  * cause they still decode the file properly despite this complaint.
68  */
69 
70 #ifndef EOLSTRING
71 #define EOLSTRING	"\015\012"
72 #endif
73 
74 #else
75 
76 /*
77  * Argh. Some delivery software (inews) has problems with the CRLF
78  * line termination. Let's try native EOL and see if we run into
79  * any problems.
80  * This involves opening output files in text mode instead of binary
81  */
82 
83 #ifndef EOLSTRING
84 #define EOLSTRING	"\n"
85 #endif
86 
87 #endif
88 
89 
90 /*
91  * =========================================================================
92  * User-configurable settings end here. Don't spy below unless you know what
93  * you're doing.
94  * =========================================================================
95  */
96 
97 /*
98  * Define End-Of-Line sequence
99  */
100 
101 #ifdef EOLSTRING
102 static unsigned char *eolstring = (unsigned char *) EOLSTRING;
103 #else
104 static unsigned char *eolstring = (unsigned char *) "\012";
105 #endif
106 
107 /*
108  * Content-Transfer-Encoding types for non-MIME encodings
109  */
110 
111 #define CTE_UUENC	"x-uuencode"
112 #define CTE_XXENC	"x-xxencode"
113 #define CTE_BINHEX	"x-binhex"
114 #define CTE_YENC	"x-yenc"
115 
116 #define CTE_TYPE(y)	(((y)==B64ENCODED) ? "Base64"  : \
117 			 ((y)==UU_ENCODED) ? CTE_UUENC : \
118 			 ((y)==XX_ENCODED) ? CTE_XXENC : \
119                          ((y)==PT_ENCODED) ? "8bit" : \
120                          ((y)==QP_ENCODED) ? "quoted-printable" : \
121 			 ((y)==BH_ENCODED) ? CTE_BINHEX : \
122 			 ((y)==YENC_ENCODED) ? CTE_YENC : "x-oops")
123 
124 /*
125  * encoding tables
126  */
127 
128 unsigned char UUEncodeTable[64] = {
129   '`', '!', '"', '#', '$', '%', '&', '\'',
130   '(', ')', '*', '+', ',', '-', '.', '/',
131   '0', '1', '2', '3', '4', '5', '6', '7',
132   '8', '9', ':', ';', '<', '=', '>', '?',
133   '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
134   'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
135   'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
136   'X', 'Y', 'Z', '[', '\\',']', '^', '_'
137 };
138 
139 
140 unsigned char B64EncodeTable[64] = {
141   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
142   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
143   'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
144   'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
145   'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
146   'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
147   'w', 'x', 'y', 'z', '0', '1', '2', '3',
148   '4', '5', '6', '7', '8', '9', '+', '/'
149 };
150 
151 unsigned char XXEncodeTable[64] = {
152   '+', '-', '0', '1', '2', '3', '4', '5',
153   '6', '7', '8', '9', 'A', 'B', 'C', 'D',
154   'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
155   'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
156   'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
157   'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
158   'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
159   's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
160 };
161 
162 unsigned char BHEncodeTable[64] = {
163   '!', '"', '#', '$', '%', '&', '\'', '(',
164   ')', '*', '+', ',', '-', '0', '1', '2',
165   '3', '4', '5', '6', '8', '9', '@', 'A',
166   'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
167   'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
168   'S', 'T', 'U', 'V', 'X', 'Y', 'Z', '[',
169   '`', 'a', 'b', 'c', 'd', 'e', 'f', 'h',
170   'i', 'j', 'k', 'l', 'm', 'p', 'q', 'r'
171 };
172 
173 unsigned char HexEncodeTable[16] = {
174   '0', '1', '2', '3', '4', '5', '6', '7',
175   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
176 };
177 
178 typedef struct {
179   char *extension;
180   char *mimetype;
181 } mimemap;
182 
183 /*
184  * This table maps a file's extension into a Content-Type. The current
185  * official list can be downloaded as
186  *   ftp://ftp.isi.edu/in-notes/iana/assignments/media-type
187  * I haven't listed any text types since it doesn't make sense to encode
188  * them. Everything not on the list gets mapped to application/octet-stream
189  */
190 
191 static mimemap mimetable[] = {
192 	{ "gif",  "image/gif"        }, /* Grafics Interchange Format  */
193 	{ "jpg",  "image/jpeg"       }, /* JFIF encoded files          */
194 	{ "jpeg", "image/jpeg"       },
195 	{ "tif",  "image/tiff"       }, /* Tag Image File Format       */
196 	{ "tiff", "image/tiff"       },
197 	{ "cgm",  "image/cgm"        }, /* Computer Graphics Metafile  */
198 	{ "au",   "audio/basic"      }, /* 8kHz ulaw audio data        */
199 	{ "mov",  "video/quicktime"  }, /* Apple Quicktime             */
200 	{ "qt",   "video/quicktime"  }, /* Also infrequently used      */
201 	{ "mpeg", "video/mpeg"       }, /* Motion Picture Expert Group */
202 	{ "mpg",  "video/mpeg"       },
203 	{ "mp2",  "video/mpeg"       }, /* dito, MPEG-2 encoded files  */
204 	{ "mp3",  "audio/mpeg"       }, /* dito, MPEG-3 encoded files  */
205 	{ "ps",   "application/postscript" }, /* Postscript Language   */
206 	{ "zip",  "application/zip"  }, /* ZIP archive                 */
207 	{ "doc",  "application/msword"},/* assume Microsoft Word       */
208 	{ NULL,   NULL               }
209 };
210 
211 /*
212  * the order of the following two tables must match the
213  * Encoding Types definition in uudeview.h
214  */
215 
216 /*
217  * encoded bytes per line
218  */
219 
220 static int bpl[8] = { 0, 45, 57, 45, 45, 0, 0, 128 };
221 
222 /*
223  * tables
224  */
225 
226 static unsigned char *etables[5] = {
227   NULL,
228   UUEncodeTable,
229   B64EncodeTable,
230   XXEncodeTable,
231   BHEncodeTable
232 };
233 
234 /*
235  * variables to malloc upon initialization
236  */
237 
238 char *uuestr_itemp;
239 char *uuestr_otemp;
240 
241 /*
242  * Encode one part of the data stream
243  */
244 
245 static int
UUEncodeStream(FILE * outfile,FILE * infile,int encoding,long linperfile,crc32_t * crc,crc32_t * pcrc)246 UUEncodeStream (FILE *outfile, FILE *infile, int encoding, long linperfile, crc32_t *crc, crc32_t *pcrc)
247 {
248   unsigned char *itemp = (char *) uuestr_itemp;
249   unsigned char *otemp = (char *) uuestr_otemp;
250   unsigned char *optr, *table, *tptr;
251   int index, count;
252   long line=0;
253   size_t llen;
254 
255   if (outfile==NULL || infile==NULL ||
256       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
257        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
258     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
259 	       uustring (S_PARM_CHECK), "UUEncodeStream()");
260     return UURET_ILLVAL;
261   }
262 
263   /*
264    * Special handling for plain text and quoted printable. Text is
265    * read line oriented.
266    */
267 
268   if (encoding == PT_ENCODED || encoding == QP_ENCODED) {
269     while (!feof (infile) && (linperfile <= 0 || line < linperfile)) {
270       if (_FP_fgets (itemp, 255, infile) == NULL) {
271 	break;
272       }
273 
274       itemp[255] = '\0';
275       count = strlen (itemp);
276 
277       llen = 0;
278       optr = otemp;
279 
280       /*
281        * Busy Callback
282        */
283 
284       if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
285 	UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
286 		   uustring (S_ENCODE_CANCEL));
287 	return UURET_CANCEL;
288       }
289 
290       if (encoding == PT_ENCODED) {
291 	/*
292 	 * If there is a line feed, replace by eolstring
293 	 */
294 	if (count > 0 && itemp[count-1] == '\n') {
295 	  itemp[--count] = '\0';
296 	  if (fwrite (itemp, 1, count, outfile) != count ||
297 	      fwrite ((char *) eolstring, 1,
298 		      strlen(eolstring), outfile) != strlen (eolstring)) {
299 	    return UURET_IOERR;
300 	  }
301 	}
302 	else {
303 	  if (fwrite (itemp, 1, count, outfile) != llen) {
304 	    return UURET_IOERR;
305 	  }
306 	}
307       }
308       else if (encoding == QP_ENCODED) {
309 	for (index=0; index<count; index++) {
310 	  if (llen == 0 && itemp[index] == '.') {
311 	    /*
312 	     * Special rule: encode '.' at the beginning of a line, so
313 	     * that some mailers aren't confused.
314 	     */
315 	    *optr++ = '=';
316 	    *optr++ = HexEncodeTable[itemp[index] >> 4];
317 	    *optr++ = HexEncodeTable[itemp[index] & 0x0f];
318 	    llen += 3;
319 	  }
320 	  else if ((itemp[index] >= 33 && itemp[index] <= 60) ||
321 		   (itemp[index] >= 62 && itemp[index] <= 126) ||
322 		   itemp[index] == 9 || itemp[index] == 32) {
323 	    *optr++ = itemp[index];
324 	    llen++;
325 	  }
326 	  else if (itemp[index] == '\n') {
327 	    /*
328 	     * If the last character before EOL was a space or tab,
329 	     * we must encode it. If llen > 74, there's no space to do
330 	     * that, so generate a soft line break instead.
331 	     */
332 
333 	    if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32)) {
334 	      *(optr-1) = '=';
335 	      if (llen <= 74) {
336 		*optr++ = HexEncodeTable[itemp[index-1] >> 4];
337 		*optr++ = HexEncodeTable[itemp[index-1] & 0x0f];
338 		llen += 2;
339 	      }
340 	    }
341 
342 	    if (fwrite (otemp, 1, llen, outfile) != llen ||
343 		fwrite ((char *) eolstring, 1,
344 			strlen(eolstring), outfile) != strlen (eolstring)) {
345 	      return UURET_IOERR;
346 	    }
347 
348 	    /*
349 	     * Fix the soft line break condition from above
350 	     */
351 
352 	    if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32) &&
353 		*(optr-1) == '=') {
354 	      otemp[0] = '=';
355 	      otemp[1] = HexEncodeTable[itemp[index-1] >> 4];
356 	      otemp[2] = HexEncodeTable[itemp[index-1] & 0x0f];
357 
358 	      if (fwrite (otemp, 1, 3, outfile) != 3 ||
359 		  fwrite ((char *) eolstring, 1,
360 			  strlen(eolstring), outfile) != strlen (eolstring)) {
361 		return UURET_IOERR;
362 	      }
363 	    }
364 
365 	    optr = otemp;
366 	    llen = 0;
367 	  }
368 	  else {
369 	    *optr++ = '=';
370 	    *optr++ = HexEncodeTable[itemp[index] >> 4];
371 	    *optr++ = HexEncodeTable[itemp[index] & 0x0f];
372 	    llen += 3;
373 	  }
374 
375 	  /*
376 	   * Lines must be shorter than 76 characters (not counting CRLF).
377 	   * If the line grows longer than that, we must include a soft
378 	   * line break.
379 	   */
380 
381 	  if (itemp[index+1] != 0 && itemp[index+1] != '\n' &&
382 	      (llen >= 75 ||
383 	       (!((itemp[index+1] >= 33 && itemp[index+1] <= 60) ||
384 		  (itemp[index+1] >= 62 && itemp[index+1] <= 126)) &&
385 		llen >= 73))) {
386 
387 	    *optr++ = '=';
388 	    llen++;
389 
390 	    if (fwrite (otemp, 1, llen, outfile) != llen ||
391 		fwrite ((char *) eolstring, 1,
392 			strlen(eolstring), outfile) != strlen (eolstring)) {
393 	      return UURET_IOERR;
394 	    }
395 
396 	    optr = otemp;
397 	    llen = 0;
398 	  }
399 	}
400       }
401 
402       line++;
403     }
404 
405     return UURET_OK;
406   }
407 
408   /*
409    * Special handling for yEnc
410    */
411 
412   if (encoding == YENC_ENCODED) {
413     llen = 0;
414     optr = otemp;
415 
416     while (!feof (infile) && (linperfile <= 0 || line < linperfile)) {
417       if ((count = fread (itemp, 1, 128, infile)) != 128) {
418 	if (count == 0) {
419 	  break;
420 	}
421 	else if (ferror (infile)) {
422 	  return UURET_IOERR;
423 	}
424       }
425 
426       if (pcrc)
427 	*pcrc = crc32(*pcrc, itemp, count);
428       if (crc)
429 	*crc = crc32(*crc, itemp, count);
430 
431       line++;
432 
433       /*
434        * Busy Callback
435        */
436 
437       if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
438 	UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
439 		   uustring (S_ENCODE_CANCEL));
440 	return UURET_CANCEL;
441       }
442 
443       for (index=0; index<count; index++) {
444 	if (llen > 127) {
445 	  if (fwrite (otemp, 1, llen, outfile) != llen ||
446 	      fwrite ((char *) eolstring, 1,
447 		      strlen(eolstring), outfile) != strlen (eolstring)) {
448 	    return UURET_IOERR;
449 	  }
450 	  llen = 0;
451 	  optr = otemp;
452 	}
453 
454 	switch ((char) ((int) itemp[index] + 42)) {
455 	case '\0':
456 	case '\t':
457 	case '\n':
458 	case '\r':
459 	case '=':
460 	case '\033':
461 	  *optr++ = '=';
462 	  *optr++ = (char) ((int) itemp[index] + 42 + 64);
463 	  llen += 2;
464 	  break;
465 
466 	case '.':
467 	  if (llen == 0) {
468 	    *optr++ = '=';
469 	    *optr++ = (char) ((int) itemp[index] + 42 + 64);
470 	    llen += 2;
471 	  }
472 	  else {
473 	    *optr++ = (char) ((int) itemp[index] + 42);
474 	    llen++;
475 	  }
476 	  break;
477 
478 	default:
479 	  *optr++ = (char) ((int) itemp[index] + 42);
480 	  llen++;
481 	  break;
482 	}
483       }
484     }
485 
486     /*
487      * write last line
488      */
489 
490     if (llen) {
491       if (fwrite (otemp, 1, llen, outfile) != llen ||
492 	  fwrite ((char *) eolstring, 1,
493 		  strlen(eolstring), outfile) != strlen (eolstring)) {
494 	return UURET_IOERR;
495       }
496     }
497 
498     return UURET_OK;
499   }
500 
501   /*
502    * Handling for binary encodings
503    */
504 
505   /*
506    * select charset
507    */
508 
509   table = etables[encoding];
510 
511   if (table==NULL || bpl[encoding]==0) {
512     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
513                uustring (S_PARM_CHECK), "UUEncodeStream()");
514     return UURET_ILLVAL;
515   }
516 
517   while (!feof (infile) && (linperfile <= 0 || line < linperfile)) {
518     if ((count = fread (itemp, 1, bpl[encoding], infile)) != bpl[encoding]) {
519       if (count == 0)
520 	break;
521       else if (ferror (infile))
522 	return UURET_IOERR;
523     }
524 
525     optr = otemp;
526     llen = 0;
527 
528     /*
529      * Busy Callback
530      */
531 
532     if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
533       UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
534 		 uustring (S_ENCODE_CANCEL));
535       return UURET_CANCEL;
536     }
537 
538     /*
539      * for UU and XX, encode the number of bytes as first character
540      */
541 
542     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
543       *optr++ = table[count];
544       llen++;
545     }
546 
547     /*
548      * Main encoding
549      */
550 
551     for (index=0; index<=count-3; index+=3, llen+=4) {
552       *optr++ = table[itemp[index] >> 2];
553       *optr++ = table[((itemp[index  ] & 0x03) << 4)|(itemp[index+1] >> 4)];
554       *optr++ = table[((itemp[index+1] & 0x0f) << 2)|(itemp[index+2] >> 6)];
555       *optr++ = table[  itemp[index+2] & 0x3f];
556     }
557 
558     /*
559      * Special handling for incomplete lines
560      */
561 
562     if (index != count) {
563       if (encoding == B64ENCODED) {
564 	if (count - index == 2) {
565 	  *optr++ = table[itemp[index] >> 2];
566 	  *optr++ = table[((itemp[index  ] & 0x03) << 4) |
567 			  ((itemp[index+1] & 0xf0) >> 4)];
568 	  *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
569 	  *optr++ = '=';
570 	}
571 	else if (count - index == 1) {
572 	  *optr++ = table[ itemp[index] >> 2];
573 	  *optr++ = table[(itemp[index] & 0x03) << 4];
574 	  *optr++ = '=';
575 	  *optr++ = '=';
576 	}
577 	llen += 4;
578       }
579       else if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
580 	if (count - index == 2) {
581 	  *optr++ = table[itemp[index] >> 2];
582 	  *optr++ = table[((itemp[index  ] & 0x03) << 4) |
583 			  ( itemp[index+1] >> 4)];
584 	  *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
585 	  *optr++ = table[0];
586 	}
587 	else if (count - index == 1) {
588 	  *optr++ = table[ itemp[index] >> 2];
589 	  *optr++ = table[(itemp[index] & 0x03) << 4];
590 	  *optr++ = table[0];
591 	  *optr++ = table[0];
592 	}
593 	llen += 4;
594       }
595     }
596 
597     /*
598      * end of line
599      */
600 
601     tptr = eolstring;
602 
603     while (*tptr)
604       *optr++ = *tptr++;
605 
606     *optr++ = '\0';
607     llen   += strlen ((char *) eolstring);
608 
609     if (fwrite (otemp, 1, llen, outfile) != llen)
610       return UURET_IOERR;
611 
612     line++;
613   }
614   return UURET_OK;
615 }
616 
617 /*
618  * Encode as MIME multipart/mixed sub-message.
619  */
620 
621 int UUEXPORT
UUEncodeMulti(FILE * outfile,FILE * infile,char * infname,int encoding,char * outfname,char * mimetype,int filemode)622 UUEncodeMulti (FILE *outfile, FILE *infile, char *infname, int encoding,
623 	       char *outfname, char *mimetype, int filemode)
624 {
625   mimemap *miter=mimetable;
626   struct stat finfo;
627   int res, themode;
628   FILE *theifile;
629   char *ptr;
630   crc32_t crc;
631   crc32_t *crcptr=NULL;
632 
633   if (outfile==NULL ||
634       (infile == NULL && infname==NULL) ||
635       (outfname==NULL && infname==NULL) ||
636       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
637        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
638     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
639 	       uustring (S_PARM_CHECK), "UUEncodeMulti()");
640     return UURET_ILLVAL;
641   }
642 
643   progress.action = 0;
644 
645   if (infile==NULL) {
646     if (stat (infname, &finfo) == -1) {
647       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
648 		 uustring (S_NOT_STAT_FILE),
649 		 infname, strerror (uu_errno=errno));
650       return UURET_IOERR;
651     }
652     if ((theifile = fopen (infname, "rb")) == NULL) {
653       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
654 		 uustring (S_NOT_OPEN_FILE),
655 		 infname, strerror (uu_errno=errno));
656       return UURET_IOERR;
657     }
658     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
659     progress.fsize = (long) finfo.st_size;
660   }
661   else {
662     if (fstat (fileno (infile), &finfo) != 0) {
663       themode  = (filemode)?filemode:0644;
664       progress.fsize = -1;
665     }
666     else {
667       themode = (int) finfo.st_mode & 0777;
668       progress.fsize = (long) finfo.st_size;
669     }
670     theifile = infile;
671   }
672 
673   if (progress.fsize < 0)
674     progress.fsize = -1;
675 
676   _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
677 
678   progress.partno   = 1;
679   progress.numparts = 1;
680   progress.percent  = 0;
681   progress.foffset  = 0;
682   progress.action   = UUACT_ENCODING;
683 
684   /*
685    * If not given from outside, select an appropriate Content-Type by
686    * looking at the file's extension. If it is unknown, default to
687    * Application/Octet-Stream
688    */
689 
690   if (mimetype == NULL) {
691     if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.'))) {
692       while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
693 	miter++;
694       mimetype = miter->mimetype;
695     }
696   }
697 
698   if (mimetype == NULL && (encoding == PT_ENCODED || encoding == QP_ENCODED)) {
699     mimetype = "text/plain";
700   }
701 
702   /*
703    * print sub-header
704    */
705 
706   if (encoding != YENC_ENCODED) {
707     fprintf (outfile, "Content-Type: %s%s",
708 	     (mimetype)?mimetype:"Application/Octet-Stream",
709 	     eolstring);
710     fprintf (outfile, "Content-Transfer-Encoding: %s%s",
711 	     CTE_TYPE(encoding), eolstring);
712     fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
713 	     UUFNameFilter ((outfname)?outfname:infname), eolstring);
714     fprintf (outfile, "%s", eolstring);
715   }
716 
717   if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
718     fprintf (outfile, "begin %o %s%s",
719 	     (themode) ? themode : 0644,
720 	     UUFNameFilter ((outfname)?outfname:infname),
721 	     eolstring);
722   }
723   else if (encoding == YENC_ENCODED) {
724     crc = crc32(0L, Z_NULL, 0);
725     crcptr = &crc;
726     if (progress.fsize == -1) {
727       fprintf (outfile, "=ybegin line=128 name=%s%s",
728 	       UUFNameFilter ((outfname)?outfname:infname),
729 	       eolstring);
730     }
731     else {
732       fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
733 	       progress.fsize,
734 	       UUFNameFilter ((outfname)?outfname:infname),
735 	       eolstring);
736     }
737   }
738 
739   if ((res = UUEncodeStream (outfile, theifile, encoding, 0, crcptr, NULL)) != UURET_OK) {
740     if (res != UURET_CANCEL) {
741       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
742 		 uustring (S_ERR_ENCODING),
743 		 UUFNameFilter ((infname)?infname:outfname),
744 		 (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
745     }
746     progress.action = 0;
747     return res;
748   }
749 
750   if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
751     fprintf (outfile, "%c%s",
752 	     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
753 	     eolstring);
754     fprintf (outfile, "end%s", eolstring);
755   }
756   else if (encoding == YENC_ENCODED) {
757     if (progress.fsize == -1) {
758       fprintf (outfile, "=yend crc32=%08lx%s",
759 	       crc,
760 	       eolstring);
761     }
762     else {
763       fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
764 	       progress.fsize,
765 	       crc,
766 	       eolstring);
767     }
768   }
769 
770   /*
771    * empty line at end does no harm
772    */
773 
774   fprintf (outfile, "%s", eolstring);
775 
776   if (infile==NULL)
777     fclose (theifile);
778 
779   progress.action = 0;
780   return UURET_OK;
781 }
782 
783 /*
784  * Encode as MIME message/partial
785  */
786 
787 int UUEXPORT
UUEncodePartial(FILE * outfile,FILE * infile,char * infname,int encoding,char * outfname,char * mimetype,int filemode,int partno,long linperfile,crc32_t * crcptr)788 UUEncodePartial (FILE *outfile, FILE *infile,
789 		 char *infname, int encoding,
790 		 char *outfname, char *mimetype,
791 		 int filemode, int partno, long linperfile,
792 		 crc32_t *crcptr)
793 {
794   mimemap *miter=mimetable;
795   static FILE *theifile;
796   int themode, numparts;
797   struct stat finfo;
798   long thesize;
799   char *ptr;
800   int res;
801   crc32_t pcrc;
802   crc32_t *pcrcptr=NULL;
803 
804   if ((outfname==NULL&&infname==NULL) || partno<=0 ||
805       (infile == NULL&&infname==NULL) || outfile==NULL ||
806       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
807        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
808     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
809 	       uustring (S_PARM_CHECK), "UUEncodePartial()");
810     return UURET_ILLVAL;
811   }
812 
813   /*
814    * The first part needs a set of headers
815    */
816 
817   progress.action = 0;
818 
819   if (partno == 1) {
820     if (infile==NULL) {
821       if (stat (infname, &finfo) == -1) {
822 	UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
823 		   uustring (S_NOT_STAT_FILE),
824 		   infname, strerror (uu_errno=errno));
825 	return UURET_IOERR;
826       }
827       if ((theifile = fopen (infname, "rb")) == NULL) {
828 	UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
829 		   uustring (S_NOT_OPEN_FILE),
830 		   infname, strerror (uu_errno=errno));
831 	return UURET_IOERR;
832       }
833       if (linperfile <= 0)
834 	numparts = 1;
835       else
836 	numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
837 			  (linperfile*bpl[encoding]));
838 
839       themode  = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
840       thesize  = (long) finfo.st_size;
841     }
842     else {
843       if (fstat (fileno (infile), &finfo) != 0) {
844 	UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
845 		   uustring (S_STAT_ONE_PART));
846 	numparts = 1;
847 	themode  = (filemode)?filemode:0644;
848 	thesize  = -1;
849       }
850       else {
851 	if (linperfile <= 0)
852 	  numparts = 1;
853 	else
854 	  numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
855 			    (linperfile*bpl[encoding]));
856 
857 	themode =  (int) finfo.st_mode & 0777;
858 	thesize = (long) finfo.st_size;
859       }
860       theifile = infile;
861     }
862 
863     _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
864 
865     progress.totsize  = (thesize>=0) ? thesize : -1;
866     progress.partno   = 1;
867     progress.numparts = numparts;
868     progress.percent  = 0;
869     progress.foffset  = 0;
870 
871     /*
872      * If not given from outside, select an appropriate Content-Type by
873      * looking at the file's extension. If it is unknown, default to
874      * Application/Octet-Stream
875      */
876 
877     if (mimetype == NULL) {
878       if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.'))) {
879 	while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
880 	  miter++;
881 	mimetype = miter->mimetype;
882       }
883     }
884 
885     if (mimetype == NULL && (encoding==PT_ENCODED || encoding==QP_ENCODED)) {
886       mimetype = "text/plain";
887     }
888 
889     /*
890      * print sub-header
891      */
892 
893     if (encoding != YENC_ENCODED) {
894       fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
895       fprintf (outfile, "Content-Type: %s%s",
896 	       (mimetype)?mimetype:"Application/Octet-Stream",
897 	       eolstring);
898       fprintf (outfile, "Content-Transfer-Encoding: %s%s",
899 	       CTE_TYPE(encoding), eolstring);
900       fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
901 	       UUFNameFilter ((outfname)?outfname:infname), eolstring);
902     }
903 
904     fprintf (outfile, "%s", eolstring);
905 
906     /*
907      * for the first part of UU or XX messages, print a begin line
908      */
909 
910     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
911       fprintf (outfile, "begin %o %s%s",
912 	       (themode) ? themode : ((filemode)?filemode:0644),
913 	       UUFNameFilter ((outfname)?outfname:infname), eolstring);
914     }
915   }
916   if (encoding == YENC_ENCODED) {
917     pcrc = crc32(0L, Z_NULL, 0);
918     pcrcptr = &pcrc;
919     if (numparts != 1) {
920       if (progress.totsize == -1) {
921 	fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
922 		 partno,
923 		 UUFNameFilter ((outfname)?outfname:infname),
924 		 eolstring);
925       }
926       else {
927 	fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
928 		 partno,
929 		 progress.totsize,
930 		 UUFNameFilter ((outfname)?outfname:infname),
931 		 eolstring);
932       }
933 
934       fprintf (outfile, "=ypart begin=%d end=%d%s",
935 	       (partno-1)*linperfile*128+1,
936 	       (partno*linperfile*128) < progress.totsize ?
937 	       (partno*linperfile*128) : progress.totsize,
938 	       eolstring);
939     }
940     else {
941       if (progress.totsize == -1) {
942 	fprintf (outfile, "=ybegin line=128 name=%s%s",
943 		 UUFNameFilter ((outfname)?outfname:infname),
944 		 eolstring);
945       }
946       else {
947 	fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
948 		 progress.totsize,
949 		 UUFNameFilter ((outfname)?outfname:infname),
950 		 eolstring);
951       }
952     }
953   }
954 
955   /*
956    * update progress information
957    */
958 
959   progress.partno  = partno;
960   progress.percent = 0;
961   progress.foffset = ftell (theifile);
962 
963   if (progress.totsize <= 0)
964     progress.fsize = -1;
965   else if (linperfile <= 0)
966     progress.fsize = progress.totsize;
967   else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
968     progress.fsize = progress.totsize - progress.foffset;
969   else
970     progress.fsize = linperfile*bpl[encoding];
971 
972   progress.action  = UUACT_ENCODING;
973 
974   if ((res = UUEncodeStream (outfile, theifile, encoding, linperfile,
975 			     crcptr, pcrcptr)) != UURET_OK) {
976     if (infile==NULL) fclose (theifile);
977     if (res != UURET_CANCEL) {
978       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
979 		 uustring (S_ERR_ENCODING),
980 		 UUFNameFilter ((outfname)?outfname:infname),
981 		 (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
982     }
983     progress.action = 0;
984     return res;
985   }
986 
987   /*
988    * print end line
989    */
990 
991   if (feof (theifile) &&
992       (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
993     fprintf (outfile, "%c%s",
994 	     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
995 	     eolstring);
996     fprintf (outfile, "end%s", eolstring);
997   }
998   else if (encoding == YENC_ENCODED) {
999     if (numparts != 1) {
1000       fprintf (outfile, "=yend size=%d part=%d pcrc32=%08lx",
1001 	       (partno*linperfile*128) < progress.totsize ?
1002 	       linperfile*128 : (progress.totsize-(partno-1)*linperfile*128),
1003 	       partno,
1004 	       pcrc);
1005     }
1006     else {
1007       fprintf (outfile, "=yend size=%d",
1008 	       progress.totsize);
1009     }
1010     if (feof (theifile))
1011       fprintf (outfile, " crc32=%08lx", *crcptr);
1012     fprintf (outfile, "%s", eolstring);
1013   }
1014 
1015   /*
1016    * empty line at end does no harm
1017    */
1018 
1019   if (encoding != PT_ENCODED && encoding != QP_ENCODED) {
1020     fprintf (outfile, "%s", eolstring);
1021   }
1022 
1023   if (infile==NULL) {
1024     if (res != UURET_OK) {
1025       progress.action = 0;
1026       fclose (theifile);
1027       return res;
1028     }
1029     if (feof (theifile)) {
1030       progress.action = 0;
1031       fclose (theifile);
1032       return UURET_OK;
1033     }
1034     return UURET_CONT;
1035   }
1036 
1037   /*
1038    * leave progress.action as-is
1039    */
1040 
1041   return UURET_OK;
1042 }
1043 
1044 /*
1045  * send output to a stream, don't do any headers at all
1046  */
1047 
1048 int UUEXPORT
UUEncodeToStream(FILE * outfile,FILE * infile,char * infname,int encoding,char * outfname,int filemode)1049 UUEncodeToStream (FILE *outfile, FILE *infile,
1050 		  char *infname, int encoding,
1051 		  char *outfname, int filemode)
1052 {
1053   struct stat finfo;
1054   FILE *theifile;
1055   int themode;
1056   int res;
1057   crc32_t crc;
1058   crc32_t *crcptr=NULL;
1059 
1060   if (outfile==NULL ||
1061       (infile == NULL&&infname==NULL) ||
1062       (outfname==NULL&&infname==NULL) ||
1063       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
1064        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
1065     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1066 	       uustring (S_PARM_CHECK), "UUEncodeToStream()");
1067     return UURET_ILLVAL;
1068   }
1069 
1070   progress.action = 0;
1071 
1072   if (infile==NULL) {
1073     if (stat (infname, &finfo) == -1) {
1074       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1075 		 uustring (S_NOT_STAT_FILE),
1076 		 infname, strerror (uu_errno=errno));
1077       return UURET_IOERR;
1078     }
1079     if ((theifile = fopen (infname, "rb")) == NULL) {
1080       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1081 		 uustring (S_NOT_OPEN_FILE),
1082 		 infname, strerror (uu_errno=errno));
1083       return UURET_IOERR;
1084     }
1085     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
1086     progress.fsize = (long) finfo.st_size;
1087   }
1088   else {
1089     if (fstat (fileno (infile), &finfo) == -1) {
1090       /* gotta live with it */
1091       themode = 0644;
1092       progress.fsize = -1;
1093     }
1094     else {
1095       themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
1096       progress.fsize = (long) finfo.st_size;
1097     }
1098     theifile = infile;
1099   }
1100 
1101   if (progress.fsize < 0)
1102     progress.fsize = -1;
1103 
1104   _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
1105 
1106   progress.partno   = 1;
1107   progress.numparts = 1;
1108   progress.percent  = 0;
1109   progress.foffset  = 0;
1110   progress.action   = UUACT_ENCODING;
1111 
1112   if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
1113     fprintf (outfile, "begin %o %s%s",
1114 	     (themode) ? themode : 0644,
1115 	     UUFNameFilter ((outfname)?outfname:infname),
1116 	     eolstring);
1117   }
1118   else if (encoding == YENC_ENCODED) {
1119     crc = crc32(0L, Z_NULL, 0);
1120     crcptr = &crc;
1121     if (progress.fsize == -1) {
1122       fprintf (outfile, "=ybegin line=128 name=%s%s",
1123 	       UUFNameFilter ((outfname)?outfname:infname),
1124 	       eolstring);
1125     }
1126     else {
1127       fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
1128 	       progress.fsize,
1129 	       UUFNameFilter ((outfname)?outfname:infname),
1130 	       eolstring);
1131     }
1132   }
1133 
1134   if ((res = UUEncodeStream (outfile, theifile, encoding, 0, crcptr, NULL)) != UURET_OK) {
1135     if (res != UURET_CANCEL) {
1136       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1137 		 uustring (S_ERR_ENCODING),
1138 		 UUFNameFilter ((infname)?infname:outfname),
1139 		 (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
1140     }
1141     progress.action = 0;
1142     return res;
1143   }
1144 
1145   if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
1146     fprintf (outfile, "%c%s",
1147 	     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
1148 	     eolstring);
1149     fprintf (outfile, "end%s", eolstring);
1150   }
1151   else if (encoding == YENC_ENCODED) {
1152     if (progress.fsize == -1) {
1153       fprintf (outfile, "=yend crc32=%08lx%s",
1154 	       crc,
1155 	       eolstring);
1156     }
1157     else {
1158       fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
1159 	       progress.fsize,
1160 	       crc,
1161 	       eolstring);
1162     }
1163   }
1164 
1165   /*
1166    * empty line at end does no harm
1167    */
1168 
1169   fprintf (outfile, "%s", eolstring);
1170 
1171   if (infile==NULL) fclose (theifile);
1172   progress.action = 0;
1173 
1174   return UURET_OK;
1175 }
1176 
1177 /*
1178  * Encode to files on disk, don't generate any headers
1179  */
1180 
1181 int UUEXPORT
UUEncodeToFile(FILE * infile,char * infname,int encoding,char * outfname,char * diskname,long linperfile)1182 UUEncodeToFile (FILE *infile, char *infname, int encoding,
1183 		char *outfname, char *diskname, long linperfile)
1184 {
1185   int part, numparts, len, filemode, res;
1186   char *oname=NULL, *optr, *ptr;
1187   FILE *theifile, *outfile;
1188   struct stat finfo;
1189   crc32_t pcrc, crc;
1190   crc32_t *pcrcptr=NULL, *crcptr=NULL;
1191 
1192   if ((diskname==NULL&&infname==NULL) ||
1193       (outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
1194       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
1195        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
1196     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1197 	       uustring (S_PARM_CHECK), "UUEncodeToFile()");
1198     return UURET_ILLVAL;
1199   }
1200 
1201   if (diskname) {
1202     if ((ptr = strchr (diskname, '/')) == NULL)
1203       ptr = strchr (diskname, '\\');
1204     if (ptr) {
1205       len = strlen (diskname) + ((uuencodeext)?strlen(uuencodeext):3) + 5;
1206 
1207       if ((oname = malloc (len)) == NULL) {
1208 	UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1209 		   uustring (S_OUT_OF_MEMORY), len);
1210 	return UURET_NOMEM;
1211       }
1212       sprintf (oname, "%s", diskname);
1213     }
1214     else {
1215       len = ((uusavepath)?strlen(uusavepath):0) + strlen (diskname)
1216 	+ ((uuencodeext)?strlen(uuencodeext):0) + 5;
1217 
1218       if ((oname = malloc (len)) == NULL) {
1219 	UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1220 		   uustring (S_OUT_OF_MEMORY), len);
1221 	return UURET_NOMEM;
1222       }
1223       sprintf (oname, "%s%s", (uusavepath)?uusavepath:"", diskname);
1224     }
1225   }
1226   else {
1227     len = ((uusavepath) ? strlen (uusavepath) : 0) +
1228       strlen(UUFNameFilter(infname)) +
1229 	((uuencodeext)?strlen(uuencodeext):0) + 5;
1230 
1231     if ((oname = malloc (len)) == NULL) {
1232       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1233 		 uustring (S_OUT_OF_MEMORY), len);
1234       return UURET_NOMEM;
1235     }
1236     optr = UUFNameFilter (infname);
1237     sprintf (oname, "%s%s",
1238 	     (uusavepath)?uusavepath:"",
1239 	     (*optr=='.')?optr+1:optr);
1240   }
1241 
1242   /*
1243    * optr points after the last dot, so that we can print the part number
1244    * there.
1245    */
1246 
1247   optr = _FP_strrchr (oname, '.');
1248   if (optr==NULL || strchr (optr, '/')!=NULL || strchr (optr, '\\')!=NULL) {
1249     optr = oname + strlen (oname);
1250     *optr++ = '.';
1251   }
1252   else if (optr==oname || *(optr-1)=='/' || *(optr-1)=='\\') {
1253     optr = oname + strlen (oname);
1254     *optr++ = '.';
1255   }
1256   else
1257     optr++;
1258 
1259   progress.action = 0;
1260 
1261   if (infile==NULL) {
1262     if (stat (infname, &finfo) == -1) {
1263       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1264 		 uustring (S_NOT_STAT_FILE),
1265 		 infname, strerror (uu_errno=errno));
1266       _FP_free (oname);
1267       return UURET_IOERR;
1268     }
1269     if ((theifile = fopen (infname, "rb")) == NULL) {
1270       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1271 		 uustring (S_NOT_OPEN_FILE),
1272 		 infname, strerror (uu_errno=errno));
1273       _FP_free (oname);
1274       return UURET_IOERR;
1275     }
1276     if (linperfile <= 0)
1277       numparts = 1;
1278     else
1279       numparts = (int) (((long)finfo.st_size + (linperfile*bpl[encoding]-1)) /
1280 			(linperfile*bpl[encoding]));
1281 
1282     filemode = (int) finfo.st_mode & 0777;
1283     progress.totsize = (long) finfo.st_size;
1284   }
1285   else {
1286     if (fstat (fileno (infile), &finfo) == -1) {
1287       /* gotta live with it */
1288       filemode = 0644;
1289       numparts = -1;
1290       progress.totsize = -1;
1291     }
1292     else {
1293       if (linperfile <= 0)
1294 	numparts = 1;
1295       else
1296 	numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
1297 			  (linperfile*bpl[encoding]));
1298 
1299       filemode = (int) finfo.st_mode & 0777;
1300       progress.totsize = -1;
1301     }
1302     theifile = infile;
1303   }
1304 
1305   _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
1306 
1307   progress.totsize  = (progress.totsize<0) ? -1 : progress.totsize;
1308   progress.numparts = numparts;
1309 
1310   for (part=1; !feof (theifile); part++) {
1311     /*
1312      * Attach extension
1313      */
1314     if (progress.numparts==1 && progress.totsize!=-1 && uuencodeext!=NULL)
1315       strcpy  (optr, uuencodeext);
1316     else
1317       sprintf (optr, "%03d", part);
1318 
1319     /*
1320      * check if target file exists
1321      */
1322 
1323     if (!uu_overwrite) {
1324       if (stat (oname, &finfo) == 0) {
1325 	UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1326 		   uustring (S_TARGET_EXISTS), oname);
1327 	if (infile==NULL) fclose (theifile);
1328 	progress.action = 0;
1329 	free (oname);
1330 	return UURET_EXISTS;
1331       }
1332     }
1333 
1334     /*
1335      * update progress information
1336      */
1337 
1338     progress.action  = 0;
1339     progress.partno  = part;
1340     progress.percent = 0;
1341     progress.foffset = ftell (theifile);
1342 
1343     if (progress.totsize == -1)
1344       progress.fsize = -1;
1345     else if (linperfile <= 0)
1346       progress.fsize = progress.totsize;
1347     else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
1348       progress.fsize = progress.totsize - progress.foffset;
1349     else
1350       progress.fsize = linperfile*bpl[encoding];
1351 
1352     progress.action  = UUACT_ENCODING;
1353 
1354     if ((outfile = fopen (oname, "w")) == NULL) {
1355       UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1356 		 uustring (S_NOT_OPEN_TARGET),
1357 		 oname, strerror (uu_errno = errno));
1358       if (infile==NULL) fclose (theifile);
1359       progress.action = 0;
1360       free (oname);
1361       return UURET_IOERR;
1362     }
1363 
1364     if (encoding != YENC_ENCODED) {
1365       fprintf (outfile, "%s", eolstring);
1366       fprintf (outfile, "_=_ %s", eolstring);
1367       if (numparts == -1)
1368 	fprintf (outfile, "_=_ Part %03d of file %s%s",
1369 		 part, UUFNameFilter ((outfname)?outfname:infname),
1370 		 eolstring);
1371       else
1372 	fprintf (outfile, "_=_ Part %03d of %03d of file %s%s",
1373 		 part, numparts,
1374 		 UUFNameFilter ((outfname)?outfname:infname),
1375 		 eolstring);
1376       fprintf (outfile, "_=_ %s", eolstring);
1377       fprintf (outfile, "%s", eolstring);
1378     }
1379 
1380     if (part==1 && (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
1381       fprintf (outfile, "begin %o %s%s",
1382 	       (filemode)?filemode : 0644,
1383 	       UUFNameFilter ((outfname)?outfname:infname),
1384 	       eolstring);
1385     }
1386     else if (encoding == YENC_ENCODED) {
1387       if (!crcptr) {
1388         crc = crc32(0L, Z_NULL, 0);
1389         crcptr = &crc;
1390       }
1391       pcrc = crc32(0L, Z_NULL, 0);
1392       pcrcptr = &pcrc;
1393       if (numparts != 1) {
1394 	if (progress.totsize == -1) {
1395 	  fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
1396 		   part,
1397 		   UUFNameFilter ((outfname)?outfname:infname),
1398 		   eolstring);
1399 	}
1400 	else {
1401 	  fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
1402 		   part,
1403 		   progress.totsize,
1404 		   UUFNameFilter ((outfname)?outfname:infname),
1405 		   eolstring);
1406 	}
1407 
1408 	fprintf (outfile, "=ypart begin=%d end=%d%s",
1409 		 (part-1)*linperfile*128+1,
1410 		 (part*linperfile*128) < progress.totsize ?
1411 		 (part*linperfile*128) : progress.totsize,
1412 		 eolstring);
1413       }
1414       else {
1415 	if (progress.totsize == -1) {
1416 	  fprintf (outfile, "=ybegin line=128 name=%s%s",
1417 		   UUFNameFilter ((outfname)?outfname:infname),
1418 		   eolstring);
1419 	}
1420 	else {
1421 	  fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
1422 		   progress.totsize,
1423 		   UUFNameFilter ((outfname)?outfname:infname),
1424 		   eolstring);
1425 	}
1426       }
1427     }
1428 
1429     if ((res = UUEncodeStream (outfile, theifile,
1430 			       encoding, linperfile, crcptr, pcrcptr)) != UURET_OK) {
1431       if (res != UURET_CANCEL) {
1432 	UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1433 		   uustring (S_ERR_ENCODING),
1434 		   UUFNameFilter ((infname)?infname:outfname),
1435 		   (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
1436       }
1437       if (infile==NULL) fclose (theifile);
1438       progress.action = 0;
1439       fclose (outfile);
1440       unlink (oname);
1441       _FP_free (oname);
1442       return res;
1443     }
1444 
1445     if (feof (theifile) &&
1446 	(encoding == UU_ENCODED || encoding == XX_ENCODED)) {
1447       fprintf (outfile, "%c%s",
1448 	       (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
1449 	       eolstring);
1450       fprintf (outfile, "end%s", eolstring);
1451     }
1452     else if (encoding == YENC_ENCODED) {
1453       if (numparts != 1) {
1454 	fprintf (outfile, "=yend size=%d part=%d pcrc32=%08lx",
1455 		 (part*linperfile*128) < progress.totsize ?
1456 		 linperfile*128 : (progress.totsize-(part-1)*linperfile*128),
1457 		 part,
1458 		 pcrc);
1459       }
1460       else {
1461 	fprintf (outfile, "=yend size=%d",
1462 		 progress.totsize);
1463       }
1464       if (feof (theifile))
1465 	fprintf (outfile, " crc32=%08lx", crc);
1466       fprintf (outfile, "%s", eolstring);
1467     }
1468 
1469     /*
1470      * empty line at end does no harm
1471      */
1472 
1473     fprintf (outfile, "%s", eolstring);
1474     fclose  (outfile);
1475   }
1476 
1477   if (infile==NULL) fclose (theifile);
1478   progress.action = 0;
1479   _FP_free (oname);
1480   return UURET_OK;
1481 }
1482 
1483 /*
1484  * Encode a MIME Mail message or Newsgroup posting and send to a
1485  * stream. Still needs a somewhat smart MDA, since we only gene-
1486  * rate a minimum set of headers.
1487  */
1488 
1489 int UUEXPORT
UUE_PrepSingle(FILE * outfile,FILE * infile,char * infname,int encoding,char * outfname,int filemode,char * destination,char * from,char * subject,int isemail)1490 UUE_PrepSingle (FILE *outfile, FILE *infile,
1491 		char *infname, int encoding,
1492 		char *outfname, int filemode,
1493 		char *destination, char *from,
1494 		char *subject, int isemail)
1495 {
1496   return UUE_PrepSingleExt (outfile, infile,
1497 			    infname, encoding,
1498 			    outfname, filemode,
1499 			    destination, from,
1500 			    subject, NULL,
1501 			    isemail);
1502 }
1503 
1504 int UUEXPORT
UUE_PrepSingleExt(FILE * outfile,FILE * infile,char * infname,int encoding,char * outfname,int filemode,char * destination,char * from,char * subject,char * replyto,int isemail)1505 UUE_PrepSingleExt (FILE *outfile, FILE *infile,
1506 		   char *infname, int encoding,
1507 		   char *outfname, int filemode,
1508 		   char *destination, char *from,
1509 		   char *subject, char *replyto,
1510 		   int isemail)
1511 {
1512   mimemap *miter=mimetable;
1513   char *subline, *oname;
1514   char *mimetype, *ptr;
1515   int res, len;
1516 
1517   if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
1518       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
1519        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
1520     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1521 	       uustring (S_PARM_CHECK), "UUE_PrepSingle()");
1522     return UURET_ILLVAL;
1523   }
1524 
1525   oname = UUFNameFilter ((outfname)?outfname:infname);
1526   len   = ((subject)?strlen(subject):0) + strlen(oname) + 40;
1527 
1528   if ((ptr = _FP_strrchr (oname, '.'))) {
1529     while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
1530       miter++;
1531     mimetype = miter->mimetype;
1532   }
1533   else
1534     mimetype = NULL;
1535 
1536   if (mimetype == NULL && (encoding == PT_ENCODED || encoding == QP_ENCODED)) {
1537     mimetype = "text/plain";
1538   }
1539 
1540   if ((subline = (char *) malloc (len)) == NULL) {
1541     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1542 	       uustring (S_OUT_OF_MEMORY), len);
1543     return UURET_NOMEM;
1544   }
1545 
1546   if (encoding == YENC_ENCODED) {
1547     if (subject)
1548       sprintf (subline, "- %s - %s (001/001)", oname, subject);
1549     else
1550       sprintf (subline, "- %s - (001/001)", oname);
1551   }
1552   else {
1553     if (subject)
1554       sprintf (subline, "%s (001/001) - [ %s ]", subject, oname);
1555     else
1556       sprintf (subline, "[ %s ] (001/001)", oname);
1557   }
1558 
1559   if (from) {
1560     fprintf (outfile, "From: %s%s", from, eolstring);
1561   }
1562   if (destination) {
1563     fprintf (outfile, "%s: %s%s",
1564 	     (isemail)?"To":"Newsgroups",
1565 	     destination, eolstring);
1566   }
1567 
1568   fprintf (outfile, "Subject: %s%s", subline, eolstring);
1569 
1570   if (replyto) {
1571     fprintf (outfile, "Reply-To: %s%s", replyto, eolstring);
1572   }
1573 
1574   if (encoding != YENC_ENCODED) {
1575     fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
1576     fprintf (outfile, "Content-Type: %s; name=\"%s\"%s",
1577 	     (mimetype)?mimetype:"Application/Octet-Stream",
1578 	     UUFNameFilter ((outfname)?outfname:infname),
1579 	     eolstring);
1580     fprintf (outfile, "Content-Transfer-Encoding: %s%s",
1581 	     CTE_TYPE(encoding), eolstring);
1582   }
1583 
1584   fprintf (outfile, "%s", eolstring);
1585 
1586   res = UUEncodeToStream (outfile, infile, infname, encoding,
1587 			  outfname, filemode);
1588 
1589   _FP_free (subline);
1590   return res;
1591 }
1592 
1593 int UUEXPORT
UUE_PrepPartial(FILE * outfile,FILE * infile,char * infname,int encoding,char * outfname,int filemode,int partno,long linperfile,long filesize,char * destination,char * from,char * subject,int isemail)1594 UUE_PrepPartial (FILE *outfile, FILE *infile,
1595 		 char *infname, int encoding,
1596 		 char *outfname, int filemode,
1597 		 int partno, long linperfile, long filesize,
1598 		 char *destination, char *from, char *subject,
1599 		 int isemail)
1600 {
1601   return UUE_PrepPartialExt (outfile, infile,
1602 			     infname, encoding,
1603 			     outfname, filemode,
1604 			     partno, linperfile, filesize,
1605 			     destination,
1606 			     from, subject, NULL,
1607 			     isemail);
1608 }
1609 
1610 int UUEXPORT
UUE_PrepPartialExt(FILE * outfile,FILE * infile,char * infname,int encoding,char * outfname,int filemode,int partno,long linperfile,long filesize,char * destination,char * from,char * subject,char * replyto,int isemail)1611 UUE_PrepPartialExt (FILE *outfile, FILE *infile,
1612 		    char *infname, int encoding,
1613 		    char *outfname, int filemode,
1614 		    int partno, long linperfile, long filesize,
1615 		    char *destination,
1616 		    char *from, char *subject, char *replyto,
1617 		    int isemail)
1618 {
1619   static int numparts, themode;
1620   static char mimeid[64];
1621   static FILE *theifile;
1622   struct stat finfo;
1623   char *subline, *oname;
1624   long thesize;
1625   int res, len;
1626   static crc32_t crc;
1627   crc32_t *crcptr=NULL;
1628 
1629   if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
1630       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
1631        encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
1632     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1633 	       uustring (S_PARM_CHECK), "UUE_PrepPartial()");
1634     return UURET_ILLVAL;
1635   }
1636 
1637   oname = UUFNameFilter ((outfname)?outfname:infname);
1638   len   = ((subject)?strlen(subject):0) + strlen (oname) + 40;
1639 
1640   /*
1641    * if first part, get information about the file
1642    */
1643 
1644   if (partno == 1) {
1645     if (infile==NULL) {
1646       if (stat (infname, &finfo) == -1) {
1647 	UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1648 		   uustring (S_NOT_STAT_FILE),
1649 		   infname, strerror (uu_errno=errno));
1650 	return UURET_IOERR;
1651       }
1652       if ((theifile = fopen (infname, "rb")) == NULL) {
1653 	UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1654 		   uustring (S_NOT_OPEN_FILE),
1655 		   infname, strerror (uu_errno=errno));
1656 	return UURET_IOERR;
1657       }
1658       if (linperfile <= 0)
1659 	numparts = 1;
1660       else
1661 	numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
1662 			  (linperfile*bpl[encoding]));
1663 
1664       themode  = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
1665       thesize  = (long) finfo.st_size;
1666     }
1667     else {
1668       if (fstat (fileno (infile), &finfo) != 0) {
1669 	if (filesize <= 0) {
1670 	  UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
1671 		     uustring (S_STAT_ONE_PART));
1672 	  numparts = 1;
1673 	  themode  = (filemode)?filemode:0644;
1674 	  thesize  = -1;
1675 	}
1676 	else {
1677 	  if (linperfile <= 0)
1678 	    numparts = 1;
1679 	  else
1680 	    numparts = (int) ((filesize+(linperfile*bpl[encoding]-1))/
1681 			      (linperfile*bpl[encoding]));
1682 
1683 	  themode  = (filemode)?filemode:0644;
1684 	  thesize  = filesize;
1685 	}
1686       }
1687       else {
1688 	if (linperfile <= 0)
1689 	  numparts = 1;
1690 	else
1691 	  numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
1692 			    (linperfile*bpl[encoding]));
1693 
1694 	filemode = (int) finfo.st_mode & 0777;
1695 	thesize  = (long) finfo.st_size;
1696       }
1697       theifile = infile;
1698     }
1699 
1700     /*
1701      * if there's one part only, don't use Message/Partial
1702      */
1703 
1704     if (numparts == 1) {
1705       if (infile==NULL) fclose (theifile);
1706       return UUE_PrepSingleExt (outfile, infile, infname, encoding,
1707 				outfname, filemode, destination,
1708 				from, subject, replyto, isemail);
1709     }
1710 
1711     /*
1712      * we also need a unique ID
1713      */
1714 
1715     sprintf (mimeid, "UUDV-%ld.%ld.%s",
1716 	     (long) time(NULL), thesize,
1717 	     (strlen(oname)>16)?"oops":oname);
1718   }
1719 
1720   if ((subline = (char *) malloc (len)) == NULL) {
1721     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1722 	       uustring (S_OUT_OF_MEMORY), len);
1723     if (infile==NULL) fclose (theifile);
1724     return UURET_NOMEM;
1725   }
1726 
1727 
1728   if (encoding == YENC_ENCODED) {
1729     if (partno == 1)
1730       crc = crc32(0L, Z_NULL, 0);
1731     crcptr = &crc;
1732     if (subject)
1733       sprintf (subline, "- %s - %s (%03d/%03d)", oname, subject,
1734 	       partno, numparts);
1735     else
1736       sprintf (subline, "- %s - (%03d/%03d)", oname,
1737 	       partno, numparts);
1738   }
1739   else {
1740     if (subject)
1741       sprintf (subline, "%s (%03d/%03d) - [ %s ]",
1742 	       subject, partno, numparts, oname);
1743     else
1744       sprintf (subline, "[ %s ] (%03d/%03d)",
1745 	       oname, partno, numparts);
1746   }
1747 
1748   if (from) {
1749     fprintf (outfile, "From: %s%s", from, eolstring);
1750   }
1751 
1752   if (destination) {
1753     fprintf (outfile, "%s: %s%s",
1754 	     (isemail)?"To":"Newsgroups",
1755 	     destination, eolstring);
1756   }
1757 
1758   fprintf (outfile, "Subject: %s%s", subline, eolstring);
1759 
1760   if (replyto) {
1761     fprintf (outfile, "Reply-To: %s%s", replyto, eolstring);
1762   }
1763 
1764   if (encoding != YENC_ENCODED) {
1765     fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
1766     fprintf (outfile, "Content-Type: Message/Partial; number=%d; total=%d;%s",
1767 	     partno, numparts, eolstring);
1768     fprintf (outfile, "\tid=\"%s\"%s",
1769 	     mimeid, eolstring);
1770   }
1771 
1772   fprintf (outfile, "%s", eolstring);
1773 
1774   res = UUEncodePartial (outfile, theifile,
1775 			 infname, encoding,
1776 			 (outfname)?outfname:infname, NULL,
1777 			 themode, partno, linperfile, crcptr);
1778 
1779   _FP_free (subline);
1780 
1781   if (infile==NULL) {
1782     if (res != UURET_OK) {
1783       fclose (theifile);
1784       return res;
1785     }
1786     if (feof (theifile)) {
1787       fclose (theifile);
1788       return UURET_OK;
1789     }
1790     return UURET_CONT;
1791   }
1792 
1793   return res;
1794 }
1795