ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuencode.c
Revision: 1.2.2.2
Committed: Sun Mar 31 19:52:07 2002 UTC (22 years, 2 months ago) by root
Content type: text/plain
Branch: UUDEVIEW
CVS Tags: UUDEVIEW-0-5-17
Changes since 1.2.2.1: +360 -73 lines
Log Message:
*** empty log message ***

File Contents

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