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