ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuencode.c
Revision: 1.7
Committed: Sun Feb 9 15:06:43 2020 UTC (4 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_62
Changes since 1.6: +8 -8 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 root 1.5 #include <crc32.h>
50 root 1.1
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 root 1.6 char * uuencode_id = "$Id$";
61 root 1.1
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 root 1.3 #define CTE_YENC "x-yenc"
115 root 1.1
116     #define CTE_TYPE(y) (((y)==B64ENCODED) ? "Base64" : \
117     ((y)==UU_ENCODED) ? CTE_UUENC : \
118     ((y)==XX_ENCODED) ? CTE_XXENC : \
119 root 1.2 ((y)==PT_ENCODED) ? "8bit" : \
120     ((y)==QP_ENCODED) ? "quoted-printable" : \
121 root 1.3 ((y)==BH_ENCODED) ? CTE_BINHEX : \
122     ((y)==YENC_ENCODED) ? CTE_YENC : "x-oops")
123 root 1.1
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 root 1.2 };
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 root 1.1
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 root 1.2 { "mp3", "audio/mpeg" }, /* dito, MPEG-3 encoded files */
205 root 1.1 { "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 root 1.3 static int bpl[8] = { 0, 45, 57, 45, 45, 0, 0, 128 };
221 root 1.1
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
246 root 1.5 UUEncodeStream (FILE *outfile, FILE *infile, int encoding, long linperfile, crc32_t *crc, crc32_t *pcrc)
247 root 1.1 {
248     uchar *itemp = (uchar *) uuestr_itemp;
249     uchar *otemp = (uchar *) 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 root 1.2 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
257 root 1.3 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
258 root 1.1 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
259     uustring (S_PARM_CHECK), "UUEncodeStream()");
260     return UURET_ILLVAL;
261     }
262    
263 root 1.2 /*
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 root 1.4 if (_FP_fgets (itemp, 255, infile) == NULL) {
271 root 1.2 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 root 1.3 (!((itemp[index+1] >= 33 && itemp[index+1] <= 60) ||
384     (itemp[index+1] >= 62 && itemp[index+1] <= 126)) &&
385     llen >= 73))) {
386 root 1.2
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 root 1.3 * 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 root 1.5 if (pcrc)
427     *pcrc = crc32(*pcrc, itemp, count);
428     if (crc)
429     *crc = crc32(*crc, itemp, count);
430    
431 root 1.3 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 root 1.2 * Handling for binary encodings
503     */
504 root 1.1
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 root 1.2 uustring (S_PARM_CHECK), "UUEncodeStream()");
514 root 1.1 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 root 1.2
525 root 1.1 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 root 1.2
542 root 1.1 if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
543     *optr++ = table[count];
544     llen++;
545     }
546    
547 root 1.2 /*
548     * Main encoding
549     */
550    
551 root 1.3 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 root 1.1 }
557    
558     /*
559     * Special handling for incomplete lines
560     */
561 root 1.2
562 root 1.1 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 root 1.2 else if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
580 root 1.1 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 root 1.2
597 root 1.1 /*
598     * end of line
599     */
600 root 1.2
601 root 1.1 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
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 root 1.5 crc32_t crc;
631     crc32_t *crcptr=NULL;
632 root 1.1
633     if (outfile==NULL ||
634     (infile == NULL && infname==NULL) ||
635     (outfname==NULL && infname==NULL) ||
636 root 1.2 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
637 root 1.3 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
638 root 1.1 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 root 1.5 if (progress.fsize < 0)
674 root 1.1 progress.fsize = -1;
675    
676 root 1.4 _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
677 root 1.1
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 root 1.4 if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.'))) {
692     while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
693 root 1.1 miter++;
694     mimetype = miter->mimetype;
695     }
696     }
697 root 1.2
698     if (mimetype == NULL && (encoding == PT_ENCODED || encoding == QP_ENCODED)) {
699     mimetype = "text/plain";
700     }
701    
702 root 1.1 /*
703     * print sub-header
704     */
705    
706 root 1.3 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 root 1.1
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 root 1.3 else if (encoding == YENC_ENCODED) {
724 root 1.5 crc = crc32(0L, Z_NULL, 0);
725     crcptr = &crc;
726 root 1.3 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 root 1.5 if ((res = UUEncodeStream (outfile, theifile, encoding, 0, crcptr, NULL)) != UURET_OK) {
740 root 1.1 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 root 1.3
750 root 1.1 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 root 1.3 else if (encoding == YENC_ENCODED) {
757     if (progress.fsize == -1) {
758 root 1.5 fprintf (outfile, "=yend crc32=%08lx%s",
759 root 1.7 (long)crc,
760 root 1.3 eolstring);
761     }
762     else {
763 root 1.5 fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
764 root 1.3 progress.fsize,
765 root 1.7 (long)crc,
766 root 1.3 eolstring);
767     }
768     }
769    
770 root 1.1 /*
771     * empty line at end does no harm
772     */
773 root 1.3
774 root 1.1 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
788     UUEncodePartial (FILE *outfile, FILE *infile,
789     char *infname, int encoding,
790     char *outfname, char *mimetype,
791 root 1.5 int filemode, int partno, long linperfile,
792     crc32_t *crcptr)
793 root 1.1 {
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 root 1.5 crc32_t pcrc;
802     crc32_t *pcrcptr=NULL;
803 root 1.1
804     if ((outfname==NULL&&infname==NULL) || partno<=0 ||
805     (infile == NULL&&infname==NULL) || outfile==NULL ||
806 root 1.2 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
807 root 1.3 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
808 root 1.1 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 root 1.5 thesize = -1;
849 root 1.1 }
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 root 1.4 _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
864 root 1.1
865 root 1.5 progress.totsize = (thesize>=0) ? thesize : -1;
866 root 1.1 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 root 1.4 if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.'))) {
879     while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
880 root 1.1 miter++;
881     mimetype = miter->mimetype;
882     }
883     }
884 root 1.2
885     if (mimetype == NULL && (encoding==PT_ENCODED || encoding==QP_ENCODED)) {
886     mimetype = "text/plain";
887     }
888    
889 root 1.1 /*
890     * print sub-header
891     */
892    
893 root 1.3 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 root 1.1 fprintf (outfile, "%s", eolstring);
905 root 1.3
906 root 1.1 /*
907     * for the first part of UU or XX messages, print a begin line
908     */
909 root 1.3
910 root 1.1 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 root 1.5 }
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 root 1.3
934 root 1.6 fprintf (outfile, "=ypart begin=%ld end=%ld%s",
935     (partno - 1) * linperfile * 128 + 1,
936     (partno * linperfile * 128) < progress.totsize
937     ? partno * linperfile * 128
938     : progress.totsize,
939 root 1.5 eolstring);
940     }
941     else {
942     if (progress.totsize == -1) {
943     fprintf (outfile, "=ybegin line=128 name=%s%s",
944     UUFNameFilter ((outfname)?outfname:infname),
945 root 1.3 eolstring);
946     }
947     else {
948 root 1.5 fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
949     progress.totsize,
950     UUFNameFilter ((outfname)?outfname:infname),
951     eolstring);
952 root 1.3 }
953     }
954 root 1.1 }
955    
956     /*
957     * update progress information
958     */
959    
960     progress.partno = partno;
961     progress.percent = 0;
962     progress.foffset = ftell (theifile);
963    
964     if (progress.totsize <= 0)
965     progress.fsize = -1;
966     else if (linperfile <= 0)
967     progress.fsize = progress.totsize;
968     else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
969     progress.fsize = progress.totsize - progress.foffset;
970     else
971     progress.fsize = linperfile*bpl[encoding];
972    
973     progress.action = UUACT_ENCODING;
974    
975 root 1.5 if ((res = UUEncodeStream (outfile, theifile, encoding, linperfile,
976     crcptr, pcrcptr)) != UURET_OK) {
977 root 1.1 if (infile==NULL) fclose (theifile);
978     if (res != UURET_CANCEL) {
979     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
980     uustring (S_ERR_ENCODING),
981     UUFNameFilter ((outfname)?outfname:infname),
982     (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
983     }
984     progress.action = 0;
985     return res;
986     }
987 root 1.3
988 root 1.1 /*
989     * print end line
990     */
991 root 1.3
992 root 1.1 if (feof (theifile) &&
993     (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
994     fprintf (outfile, "%c%s",
995     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
996     eolstring);
997     fprintf (outfile, "end%s", eolstring);
998     }
999 root 1.3 else if (encoding == YENC_ENCODED) {
1000     if (numparts != 1) {
1001 root 1.6 fprintf (outfile, "=yend size=%ld part=%d pcrc32=%08lx",
1002     (partno * linperfile * 128) < progress.totsize
1003     ? linperfile * 128
1004     : (progress.totsize - (partno - 1) * linperfile * 128),
1005 root 1.3 partno,
1006 root 1.7 (long)pcrc);
1007 root 1.3 }
1008     else {
1009 root 1.6 fprintf (outfile, "=yend size=%ld",
1010 root 1.5 progress.totsize);
1011 root 1.3 }
1012 root 1.5 if (feof (theifile))
1013 root 1.7 fprintf (outfile, " crc32=%08lx", (long)*crcptr);
1014 root 1.5 fprintf (outfile, "%s", eolstring);
1015 root 1.3 }
1016 root 1.2
1017 root 1.1 /*
1018     * empty line at end does no harm
1019     */
1020 root 1.2
1021     if (encoding != PT_ENCODED && encoding != QP_ENCODED) {
1022     fprintf (outfile, "%s", eolstring);
1023     }
1024 root 1.1
1025     if (infile==NULL) {
1026     if (res != UURET_OK) {
1027     progress.action = 0;
1028     fclose (theifile);
1029     return res;
1030     }
1031     if (feof (theifile)) {
1032     progress.action = 0;
1033     fclose (theifile);
1034     return UURET_OK;
1035     }
1036     return UURET_CONT;
1037     }
1038    
1039     /*
1040     * leave progress.action as-is
1041     */
1042    
1043     return UURET_OK;
1044     }
1045    
1046     /*
1047     * send output to a stream, don't do any headers at all
1048     */
1049    
1050     int UUEXPORT
1051     UUEncodeToStream (FILE *outfile, FILE *infile,
1052     char *infname, int encoding,
1053     char *outfname, int filemode)
1054     {
1055     struct stat finfo;
1056     FILE *theifile;
1057     int themode;
1058     int res;
1059 root 1.5 crc32_t crc;
1060     crc32_t *crcptr=NULL;
1061 root 1.1
1062     if (outfile==NULL ||
1063     (infile == NULL&&infname==NULL) ||
1064     (outfname==NULL&&infname==NULL) ||
1065 root 1.2 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
1066 root 1.3 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
1067 root 1.1 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1068     uustring (S_PARM_CHECK), "UUEncodeToStream()");
1069     return UURET_ILLVAL;
1070     }
1071    
1072     progress.action = 0;
1073    
1074     if (infile==NULL) {
1075     if (stat (infname, &finfo) == -1) {
1076     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1077     uustring (S_NOT_STAT_FILE),
1078     infname, strerror (uu_errno=errno));
1079     return UURET_IOERR;
1080     }
1081     if ((theifile = fopen (infname, "rb")) == NULL) {
1082     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1083     uustring (S_NOT_OPEN_FILE),
1084     infname, strerror (uu_errno=errno));
1085     return UURET_IOERR;
1086     }
1087     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
1088     progress.fsize = (long) finfo.st_size;
1089     }
1090     else {
1091     if (fstat (fileno (infile), &finfo) == -1) {
1092     /* gotta live with it */
1093     themode = 0644;
1094     progress.fsize = -1;
1095     }
1096     else {
1097     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
1098     progress.fsize = (long) finfo.st_size;
1099     }
1100     theifile = infile;
1101     }
1102    
1103 root 1.5 if (progress.fsize < 0)
1104 root 1.1 progress.fsize = -1;
1105    
1106 root 1.4 _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
1107 root 1.1
1108     progress.partno = 1;
1109     progress.numparts = 1;
1110     progress.percent = 0;
1111     progress.foffset = 0;
1112     progress.action = UUACT_ENCODING;
1113    
1114     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
1115     fprintf (outfile, "begin %o %s%s",
1116     (themode) ? themode : 0644,
1117     UUFNameFilter ((outfname)?outfname:infname),
1118     eolstring);
1119     }
1120 root 1.3 else if (encoding == YENC_ENCODED) {
1121 root 1.5 crc = crc32(0L, Z_NULL, 0);
1122     crcptr = &crc;
1123 root 1.3 if (progress.fsize == -1) {
1124     fprintf (outfile, "=ybegin line=128 name=%s%s",
1125     UUFNameFilter ((outfname)?outfname:infname),
1126     eolstring);
1127     }
1128     else {
1129     fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
1130     progress.fsize,
1131     UUFNameFilter ((outfname)?outfname:infname),
1132     eolstring);
1133     }
1134     }
1135    
1136 root 1.5 if ((res = UUEncodeStream (outfile, theifile, encoding, 0, crcptr, NULL)) != UURET_OK) {
1137 root 1.1 if (res != UURET_CANCEL) {
1138     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1139     uustring (S_ERR_ENCODING),
1140     UUFNameFilter ((infname)?infname:outfname),
1141     (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
1142     }
1143     progress.action = 0;
1144     return res;
1145     }
1146 root 1.3
1147 root 1.1 if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
1148     fprintf (outfile, "%c%s",
1149     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
1150     eolstring);
1151     fprintf (outfile, "end%s", eolstring);
1152     }
1153 root 1.3 else if (encoding == YENC_ENCODED) {
1154     if (progress.fsize == -1) {
1155 root 1.5 fprintf (outfile, "=yend crc32=%08lx%s",
1156 root 1.7 (long)crc,
1157 root 1.3 eolstring);
1158     }
1159     else {
1160 root 1.5 fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
1161 root 1.3 progress.fsize,
1162 root 1.7 (long)crc,
1163 root 1.3 eolstring);
1164     }
1165     }
1166    
1167 root 1.1 /*
1168     * empty line at end does no harm
1169     */
1170 root 1.3
1171 root 1.1 fprintf (outfile, "%s", eolstring);
1172    
1173     if (infile==NULL) fclose (theifile);
1174     progress.action = 0;
1175    
1176     return UURET_OK;
1177     }
1178    
1179     /*
1180     * Encode to files on disk, don't generate any headers
1181     */
1182    
1183     int UUEXPORT
1184     UUEncodeToFile (FILE *infile, char *infname, int encoding,
1185     char *outfname, char *diskname, long linperfile)
1186     {
1187     int part, numparts, len, filemode, res;
1188     char *oname=NULL, *optr, *ptr;
1189     FILE *theifile, *outfile;
1190     struct stat finfo;
1191 root 1.5 crc32_t pcrc, crc;
1192     crc32_t *pcrcptr=NULL, *crcptr=NULL;
1193 root 1.1
1194     if ((diskname==NULL&&infname==NULL) ||
1195     (outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
1196 root 1.2 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
1197 root 1.3 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
1198 root 1.1 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1199     uustring (S_PARM_CHECK), "UUEncodeToFile()");
1200     return UURET_ILLVAL;
1201     }
1202    
1203     if (diskname) {
1204     if ((ptr = strchr (diskname, '/')) == NULL)
1205     ptr = strchr (diskname, '\\');
1206     if (ptr) {
1207     len = strlen (diskname) + ((uuencodeext)?strlen(uuencodeext):3) + 5;
1208    
1209     if ((oname = malloc (len)) == NULL) {
1210     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1211     uustring (S_OUT_OF_MEMORY), len);
1212     return UURET_NOMEM;
1213     }
1214     sprintf (oname, "%s", diskname);
1215     }
1216     else {
1217     len = ((uusavepath)?strlen(uusavepath):0) + strlen (diskname)
1218     + ((uuencodeext)?strlen(uuencodeext):0) + 5;
1219    
1220     if ((oname = malloc (len)) == NULL) {
1221     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1222     uustring (S_OUT_OF_MEMORY), len);
1223     return UURET_NOMEM;
1224     }
1225     sprintf (oname, "%s%s", (uusavepath)?uusavepath:"", diskname);
1226     }
1227     }
1228     else {
1229     len = ((uusavepath) ? strlen (uusavepath) : 0) +
1230     strlen(UUFNameFilter(infname)) +
1231     ((uuencodeext)?strlen(uuencodeext):0) + 5;
1232    
1233     if ((oname = malloc (len)) == NULL) {
1234     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1235     uustring (S_OUT_OF_MEMORY), len);
1236     return UURET_NOMEM;
1237     }
1238     optr = UUFNameFilter (infname);
1239     sprintf (oname, "%s%s",
1240     (uusavepath)?uusavepath:"",
1241     (*optr=='.')?optr+1:optr);
1242     }
1243    
1244     /*
1245     * optr points after the last dot, so that we can print the part number
1246     * there.
1247     */
1248    
1249 root 1.4 optr = _FP_strrchr (oname, '.');
1250 root 1.1 if (optr==NULL || strchr (optr, '/')!=NULL || strchr (optr, '\\')!=NULL) {
1251     optr = oname + strlen (oname);
1252     *optr++ = '.';
1253     }
1254     else if (optr==oname || *(optr-1)=='/' || *(optr-1)=='\\') {
1255     optr = oname + strlen (oname);
1256     *optr++ = '.';
1257     }
1258     else
1259     optr++;
1260    
1261     progress.action = 0;
1262    
1263     if (infile==NULL) {
1264     if (stat (infname, &finfo) == -1) {
1265     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1266     uustring (S_NOT_STAT_FILE),
1267     infname, strerror (uu_errno=errno));
1268 root 1.4 _FP_free (oname);
1269 root 1.1 return UURET_IOERR;
1270     }
1271     if ((theifile = fopen (infname, "rb")) == NULL) {
1272     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1273     uustring (S_NOT_OPEN_FILE),
1274     infname, strerror (uu_errno=errno));
1275 root 1.4 _FP_free (oname);
1276 root 1.1 return UURET_IOERR;
1277     }
1278     if (linperfile <= 0)
1279     numparts = 1;
1280     else
1281     numparts = (int) (((long)finfo.st_size + (linperfile*bpl[encoding]-1)) /
1282     (linperfile*bpl[encoding]));
1283    
1284     filemode = (int) finfo.st_mode & 0777;
1285     progress.totsize = (long) finfo.st_size;
1286     }
1287     else {
1288     if (fstat (fileno (infile), &finfo) == -1) {
1289     /* gotta live with it */
1290     filemode = 0644;
1291     numparts = -1;
1292     progress.totsize = -1;
1293     }
1294     else {
1295     if (linperfile <= 0)
1296     numparts = 1;
1297     else
1298     numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
1299     (linperfile*bpl[encoding]));
1300    
1301     filemode = (int) finfo.st_mode & 0777;
1302     progress.totsize = -1;
1303     }
1304     theifile = infile;
1305     }
1306    
1307 root 1.4 _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
1308 root 1.1
1309 root 1.5 progress.totsize = (progress.totsize<0) ? -1 : progress.totsize;
1310 root 1.1 progress.numparts = numparts;
1311    
1312     for (part=1; !feof (theifile); part++) {
1313     /*
1314     * Attach extension
1315     */
1316     if (progress.numparts==1 && progress.totsize!=-1 && uuencodeext!=NULL)
1317     strcpy (optr, uuencodeext);
1318     else
1319     sprintf (optr, "%03d", part);
1320    
1321     /*
1322     * check if target file exists
1323     */
1324    
1325     if (!uu_overwrite) {
1326     if (stat (oname, &finfo) == 0) {
1327     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1328     uustring (S_TARGET_EXISTS), oname);
1329     if (infile==NULL) fclose (theifile);
1330     progress.action = 0;
1331     free (oname);
1332     return UURET_EXISTS;
1333     }
1334     }
1335    
1336     /*
1337     * update progress information
1338     */
1339    
1340     progress.action = 0;
1341     progress.partno = part;
1342     progress.percent = 0;
1343     progress.foffset = ftell (theifile);
1344    
1345     if (progress.totsize == -1)
1346     progress.fsize = -1;
1347     else if (linperfile <= 0)
1348     progress.fsize = progress.totsize;
1349     else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
1350     progress.fsize = progress.totsize - progress.foffset;
1351     else
1352     progress.fsize = linperfile*bpl[encoding];
1353    
1354     progress.action = UUACT_ENCODING;
1355    
1356     if ((outfile = fopen (oname, "w")) == NULL) {
1357     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1358     uustring (S_NOT_OPEN_TARGET),
1359     oname, strerror (uu_errno = errno));
1360     if (infile==NULL) fclose (theifile);
1361     progress.action = 0;
1362     free (oname);
1363     return UURET_IOERR;
1364     }
1365 root 1.3
1366     if (encoding != YENC_ENCODED) {
1367     fprintf (outfile, "%s", eolstring);
1368     fprintf (outfile, "_=_ %s", eolstring);
1369     if (numparts == -1)
1370     fprintf (outfile, "_=_ Part %03d of file %s%s",
1371     part, UUFNameFilter ((outfname)?outfname:infname),
1372     eolstring);
1373     else
1374     fprintf (outfile, "_=_ Part %03d of %03d of file %s%s",
1375     part, numparts,
1376     UUFNameFilter ((outfname)?outfname:infname),
1377     eolstring);
1378     fprintf (outfile, "_=_ %s", eolstring);
1379     fprintf (outfile, "%s", eolstring);
1380     }
1381 root 1.1
1382     if (part==1 && (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
1383     fprintf (outfile, "begin %o %s%s",
1384     (filemode)?filemode : 0644,
1385     UUFNameFilter ((outfname)?outfname:infname),
1386     eolstring);
1387     }
1388 root 1.3 else if (encoding == YENC_ENCODED) {
1389 root 1.5 if (!crcptr) {
1390     crc = crc32(0L, Z_NULL, 0);
1391     crcptr = &crc;
1392     }
1393     pcrc = crc32(0L, Z_NULL, 0);
1394     pcrcptr = &pcrc;
1395 root 1.3 if (numparts != 1) {
1396     if (progress.totsize == -1) {
1397     fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
1398     part,
1399     UUFNameFilter ((outfname)?outfname:infname),
1400     eolstring);
1401     }
1402     else {
1403     fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
1404     part,
1405     progress.totsize,
1406     UUFNameFilter ((outfname)?outfname:infname),
1407     eolstring);
1408     }
1409    
1410 root 1.6 fprintf (outfile, "=ypart begin=%ld end=%ld%s",
1411 root 1.3 (part-1)*linperfile*128+1,
1412     (part*linperfile*128) < progress.totsize ?
1413     (part*linperfile*128) : progress.totsize,
1414     eolstring);
1415     }
1416     else {
1417     if (progress.totsize == -1) {
1418     fprintf (outfile, "=ybegin line=128 name=%s%s",
1419     UUFNameFilter ((outfname)?outfname:infname),
1420     eolstring);
1421     }
1422     else {
1423     fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
1424     progress.totsize,
1425     UUFNameFilter ((outfname)?outfname:infname),
1426     eolstring);
1427     }
1428     }
1429     }
1430    
1431 root 1.1 if ((res = UUEncodeStream (outfile, theifile,
1432 root 1.5 encoding, linperfile, crcptr, pcrcptr)) != UURET_OK) {
1433 root 1.1 if (res != UURET_CANCEL) {
1434     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1435     uustring (S_ERR_ENCODING),
1436     UUFNameFilter ((infname)?infname:outfname),
1437     (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
1438     }
1439     if (infile==NULL) fclose (theifile);
1440     progress.action = 0;
1441     fclose (outfile);
1442     unlink (oname);
1443 root 1.4 _FP_free (oname);
1444 root 1.1 return res;
1445     }
1446 root 1.3
1447 root 1.1 if (feof (theifile) &&
1448     (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
1449     fprintf (outfile, "%c%s",
1450     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
1451     eolstring);
1452     fprintf (outfile, "end%s", eolstring);
1453     }
1454 root 1.3 else if (encoding == YENC_ENCODED) {
1455     if (numparts != 1) {
1456 root 1.6 fprintf (outfile, "=yend size=%ld part=%d pcrc32=%08lx",
1457 root 1.3 (part*linperfile*128) < progress.totsize ?
1458     linperfile*128 : (progress.totsize-(part-1)*linperfile*128),
1459     part,
1460 root 1.7 (long)pcrc);
1461 root 1.3 }
1462     else {
1463 root 1.6 fprintf (outfile, "=yend size=%ld",
1464 root 1.5 progress.totsize);
1465 root 1.3 }
1466 root 1.5 if (feof (theifile))
1467 root 1.7 fprintf (outfile, " crc32=%08lx", (long)crc);
1468 root 1.5 fprintf (outfile, "%s", eolstring);
1469 root 1.3 }
1470    
1471 root 1.1 /*
1472     * empty line at end does no harm
1473     */
1474 root 1.3
1475 root 1.1 fprintf (outfile, "%s", eolstring);
1476     fclose (outfile);
1477     }
1478 root 1.3
1479 root 1.1 if (infile==NULL) fclose (theifile);
1480     progress.action = 0;
1481 root 1.4 _FP_free (oname);
1482 root 1.1 return UURET_OK;
1483     }
1484    
1485     /*
1486     * Encode a MIME Mail message or Newsgroup posting and send to a
1487     * stream. Still needs a somewhat smart MDA, since we only gene-
1488     * rate a minimum set of headers.
1489     */
1490    
1491     int UUEXPORT
1492     UUE_PrepSingle (FILE *outfile, FILE *infile,
1493     char *infname, int encoding,
1494     char *outfname, int filemode,
1495     char *destination, char *from,
1496     char *subject, int isemail)
1497     {
1498 root 1.2 return UUE_PrepSingleExt (outfile, infile,
1499     infname, encoding,
1500     outfname, filemode,
1501     destination, from,
1502     subject, NULL,
1503     isemail);
1504     }
1505    
1506     int UUEXPORT
1507     UUE_PrepSingleExt (FILE *outfile, FILE *infile,
1508     char *infname, int encoding,
1509     char *outfname, int filemode,
1510     char *destination, char *from,
1511     char *subject, char *replyto,
1512     int isemail)
1513     {
1514 root 1.1 mimemap *miter=mimetable;
1515     char *subline, *oname;
1516     char *mimetype, *ptr;
1517     int res, len;
1518    
1519     if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
1520 root 1.2 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
1521 root 1.3 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
1522 root 1.1 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1523     uustring (S_PARM_CHECK), "UUE_PrepSingle()");
1524     return UURET_ILLVAL;
1525     }
1526    
1527     oname = UUFNameFilter ((outfname)?outfname:infname);
1528     len = ((subject)?strlen(subject):0) + strlen(oname) + 40;
1529    
1530 root 1.4 if ((ptr = _FP_strrchr (oname, '.'))) {
1531     while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
1532 root 1.1 miter++;
1533     mimetype = miter->mimetype;
1534     }
1535     else
1536     mimetype = NULL;
1537    
1538 root 1.2 if (mimetype == NULL && (encoding == PT_ENCODED || encoding == QP_ENCODED)) {
1539     mimetype = "text/plain";
1540     }
1541    
1542 root 1.1 if ((subline = (char *) malloc (len)) == NULL) {
1543     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1544     uustring (S_OUT_OF_MEMORY), len);
1545     return UURET_NOMEM;
1546     }
1547    
1548 root 1.3 if (encoding == YENC_ENCODED) {
1549     if (subject)
1550     sprintf (subline, "- %s - %s (001/001)", oname, subject);
1551     else
1552     sprintf (subline, "- %s - (001/001)", oname);
1553     }
1554     else {
1555     if (subject)
1556     sprintf (subline, "%s (001/001) - [ %s ]", subject, oname);
1557     else
1558     sprintf (subline, "[ %s ] (001/001)", oname);
1559     }
1560 root 1.1
1561     if (from) {
1562     fprintf (outfile, "From: %s%s", from, eolstring);
1563     }
1564     if (destination) {
1565     fprintf (outfile, "%s: %s%s",
1566     (isemail)?"To":"Newsgroups",
1567     destination, eolstring);
1568     }
1569 root 1.2
1570     fprintf (outfile, "Subject: %s%s", subline, eolstring);
1571    
1572     if (replyto) {
1573     fprintf (outfile, "Reply-To: %s%s", replyto, eolstring);
1574     }
1575    
1576 root 1.3 if (encoding != YENC_ENCODED) {
1577     fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
1578     fprintf (outfile, "Content-Type: %s; name=\"%s\"%s",
1579     (mimetype)?mimetype:"Application/Octet-Stream",
1580     UUFNameFilter ((outfname)?outfname:infname),
1581     eolstring);
1582     fprintf (outfile, "Content-Transfer-Encoding: %s%s",
1583     CTE_TYPE(encoding), eolstring);
1584     }
1585    
1586 root 1.1 fprintf (outfile, "%s", eolstring);
1587    
1588     res = UUEncodeToStream (outfile, infile, infname, encoding,
1589     outfname, filemode);
1590    
1591 root 1.4 _FP_free (subline);
1592 root 1.1 return res;
1593     }
1594    
1595     int UUEXPORT
1596     UUE_PrepPartial (FILE *outfile, FILE *infile,
1597     char *infname, int encoding,
1598     char *outfname, int filemode,
1599     int partno, long linperfile, long filesize,
1600     char *destination, char *from, char *subject,
1601     int isemail)
1602     {
1603 root 1.2 return UUE_PrepPartialExt (outfile, infile,
1604     infname, encoding,
1605     outfname, filemode,
1606     partno, linperfile, filesize,
1607     destination,
1608     from, subject, NULL,
1609     isemail);
1610     }
1611    
1612     int UUEXPORT
1613     UUE_PrepPartialExt (FILE *outfile, FILE *infile,
1614     char *infname, int encoding,
1615     char *outfname, int filemode,
1616     int partno, long linperfile, long filesize,
1617     char *destination,
1618     char *from, char *subject, char *replyto,
1619     int isemail)
1620     {
1621 root 1.1 static int numparts, themode;
1622     static char mimeid[64];
1623     static FILE *theifile;
1624     struct stat finfo;
1625     char *subline, *oname;
1626     long thesize;
1627     int res, len;
1628 root 1.5 static crc32_t crc;
1629     crc32_t *crcptr=NULL;
1630 root 1.1
1631     if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
1632 root 1.2 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
1633 root 1.3 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
1634 root 1.1 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1635     uustring (S_PARM_CHECK), "UUE_PrepPartial()");
1636     return UURET_ILLVAL;
1637     }
1638    
1639     oname = UUFNameFilter ((outfname)?outfname:infname);
1640     len = ((subject)?strlen(subject):0) + strlen (oname) + 40;
1641    
1642     /*
1643     * if first part, get information about the file
1644     */
1645 root 1.3
1646 root 1.1 if (partno == 1) {
1647     if (infile==NULL) {
1648     if (stat (infname, &finfo) == -1) {
1649     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1650     uustring (S_NOT_STAT_FILE),
1651     infname, strerror (uu_errno=errno));
1652     return UURET_IOERR;
1653     }
1654     if ((theifile = fopen (infname, "rb")) == NULL) {
1655     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1656     uustring (S_NOT_OPEN_FILE),
1657     infname, strerror (uu_errno=errno));
1658     return UURET_IOERR;
1659     }
1660     if (linperfile <= 0)
1661     numparts = 1;
1662     else
1663     numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
1664     (linperfile*bpl[encoding]));
1665    
1666     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
1667     thesize = (long) finfo.st_size;
1668     }
1669     else {
1670     if (fstat (fileno (infile), &finfo) != 0) {
1671     if (filesize <= 0) {
1672     UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
1673     uustring (S_STAT_ONE_PART));
1674     numparts = 1;
1675     themode = (filemode)?filemode:0644;
1676 root 1.5 thesize = -1;
1677 root 1.1 }
1678     else {
1679     if (linperfile <= 0)
1680     numparts = 1;
1681     else
1682     numparts = (int) ((filesize+(linperfile*bpl[encoding]-1))/
1683     (linperfile*bpl[encoding]));
1684    
1685     themode = (filemode)?filemode:0644;
1686     thesize = filesize;
1687     }
1688     }
1689     else {
1690     if (linperfile <= 0)
1691     numparts = 1;
1692     else
1693     numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
1694     (linperfile*bpl[encoding]));
1695    
1696     filemode = (int) finfo.st_mode & 0777;
1697     thesize = (long) finfo.st_size;
1698     }
1699     theifile = infile;
1700     }
1701 root 1.3
1702 root 1.1 /*
1703     * if there's one part only, don't use Message/Partial
1704     */
1705    
1706     if (numparts == 1) {
1707     if (infile==NULL) fclose (theifile);
1708 root 1.2 return UUE_PrepSingleExt (outfile, infile, infname, encoding,
1709     outfname, filemode, destination,
1710     from, subject, replyto, isemail);
1711 root 1.1 }
1712    
1713     /*
1714     * we also need a unique ID
1715     */
1716 root 1.3
1717 root 1.1 sprintf (mimeid, "UUDV-%ld.%ld.%s",
1718     (long) time(NULL), thesize,
1719     (strlen(oname)>16)?"oops":oname);
1720     }
1721    
1722     if ((subline = (char *) malloc (len)) == NULL) {
1723     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1724     uustring (S_OUT_OF_MEMORY), len);
1725     if (infile==NULL) fclose (theifile);
1726     return UURET_NOMEM;
1727     }
1728    
1729 root 1.3
1730     if (encoding == YENC_ENCODED) {
1731 root 1.5 if (partno == 1)
1732     crc = crc32(0L, Z_NULL, 0);
1733     crcptr = &crc;
1734 root 1.3 if (subject)
1735     sprintf (subline, "- %s - %s (%03d/%03d)", oname, subject,
1736     partno, numparts);
1737     else
1738     sprintf (subline, "- %s - (%03d/%03d)", oname,
1739     partno, numparts);
1740     }
1741     else {
1742     if (subject)
1743     sprintf (subline, "%s (%03d/%03d) - [ %s ]",
1744     subject, partno, numparts, oname);
1745     else
1746     sprintf (subline, "[ %s ] (%03d/%03d)",
1747     oname, partno, numparts);
1748     }
1749 root 1.1
1750     if (from) {
1751     fprintf (outfile, "From: %s%s", from, eolstring);
1752     }
1753 root 1.2
1754 root 1.1 if (destination) {
1755     fprintf (outfile, "%s: %s%s",
1756     (isemail)?"To":"Newsgroups",
1757     destination, eolstring);
1758     }
1759 root 1.2
1760     fprintf (outfile, "Subject: %s%s", subline, eolstring);
1761    
1762     if (replyto) {
1763     fprintf (outfile, "Reply-To: %s%s", replyto, eolstring);
1764     }
1765    
1766 root 1.3 if (encoding != YENC_ENCODED) {
1767     fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
1768     fprintf (outfile, "Content-Type: Message/Partial; number=%d; total=%d;%s",
1769     partno, numparts, eolstring);
1770     fprintf (outfile, "\tid=\"%s\"%s",
1771     mimeid, eolstring);
1772     }
1773    
1774 root 1.1 fprintf (outfile, "%s", eolstring);
1775    
1776     res = UUEncodePartial (outfile, theifile,
1777     infname, encoding,
1778     (outfname)?outfname:infname, NULL,
1779 root 1.5 themode, partno, linperfile, crcptr);
1780 root 1.1
1781 root 1.4 _FP_free (subline);
1782 root 1.1
1783     if (infile==NULL) {
1784     if (res != UURET_OK) {
1785     fclose (theifile);
1786     return res;
1787     }
1788     if (feof (theifile)) {
1789     fclose (theifile);
1790     return UURET_OK;
1791     }
1792     return UURET_CONT;
1793     }
1794    
1795     return res;
1796     }