ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Convert-UUlib/uulib/uuencode.c
Revision: 1.11
Committed: Sat Sep 24 06:02:04 2022 UTC (4 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.10: +0 -2 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     #if 0
61     /*
62     * the End-Of-Line string. MIME enforces CRLF, so that's what we use. Some
63     * implementations of uudecode will complain about a missing end line, since
64     * they look for "end^J" but find "end^J^M". We don't care - especially be-
65     * cause they still decode the file properly despite this complaint.
66     */
67    
68     #ifndef EOLSTRING
69     #define EOLSTRING "\015\012"
70     #endif
71    
72     #else
73    
74     /*
75     * Argh. Some delivery software (inews) has problems with the CRLF
76     * line termination. Let's try native EOL and see if we run into
77     * any problems.
78     * This involves opening output files in text mode instead of binary
79     */
80    
81     #ifndef EOLSTRING
82     #define EOLSTRING "\n"
83     #endif
84    
85     #endif
86    
87    
88     /*
89     * =========================================================================
90     * User-configurable settings end here. Don't spy below unless you know what
91     * you're doing.
92     * =========================================================================
93     */
94    
95     /*
96     * Define End-Of-Line sequence
97     */
98    
99     #ifdef EOLSTRING
100     static unsigned char *eolstring = (unsigned char *) EOLSTRING;
101     #else
102     static unsigned char *eolstring = (unsigned char *) "\012";
103     #endif
104    
105     /*
106     * Content-Transfer-Encoding types for non-MIME encodings
107     */
108    
109     #define CTE_UUENC "x-uuencode"
110     #define CTE_XXENC "x-xxencode"
111     #define CTE_BINHEX "x-binhex"
112 root 1.3 #define CTE_YENC "x-yenc"
113 root 1.1
114     #define CTE_TYPE(y) (((y)==B64ENCODED) ? "Base64" : \
115     ((y)==UU_ENCODED) ? CTE_UUENC : \
116     ((y)==XX_ENCODED) ? CTE_XXENC : \
117 root 1.2 ((y)==PT_ENCODED) ? "8bit" : \
118     ((y)==QP_ENCODED) ? "quoted-printable" : \
119 root 1.3 ((y)==BH_ENCODED) ? CTE_BINHEX : \
120     ((y)==YENC_ENCODED) ? CTE_YENC : "x-oops")
121 root 1.1
122     /*
123     * encoding tables
124     */
125    
126     unsigned char UUEncodeTable[64] = {
127     '`', '!', '"', '#', '$', '%', '&', '\'',
128     '(', ')', '*', '+', ',', '-', '.', '/',
129     '0', '1', '2', '3', '4', '5', '6', '7',
130     '8', '9', ':', ';', '<', '=', '>', '?',
131     '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
132     'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
133     'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
134     'X', 'Y', 'Z', '[', '\\',']', '^', '_'
135     };
136 root 1.9
137 root 1.1
138     unsigned char B64EncodeTable[64] = {
139     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
140     'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
141     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
142     'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
143     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
144     'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
145     'w', 'x', 'y', 'z', '0', '1', '2', '3',
146     '4', '5', '6', '7', '8', '9', '+', '/'
147     };
148    
149     unsigned char XXEncodeTable[64] = {
150     '+', '-', '0', '1', '2', '3', '4', '5',
151     '6', '7', '8', '9', 'A', 'B', 'C', 'D',
152     'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
153     'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
154     'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
155     'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
156     'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
157     's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
158     };
159    
160     unsigned char BHEncodeTable[64] = {
161     '!', '"', '#', '$', '%', '&', '\'', '(',
162     ')', '*', '+', ',', '-', '0', '1', '2',
163 root 1.9 '3', '4', '5', '6', '8', '9', '@', 'A',
164     'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
165     'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
166     'S', 'T', 'U', 'V', 'X', 'Y', 'Z', '[',
167     '`', 'a', 'b', 'c', 'd', 'e', 'f', 'h',
168 root 1.1 'i', 'j', 'k', 'l', 'm', 'p', 'q', 'r'
169 root 1.2 };
170    
171     unsigned char HexEncodeTable[16] = {
172     '0', '1', '2', '3', '4', '5', '6', '7',
173     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
174     };
175 root 1.1
176     typedef struct {
177     char *extension;
178     char *mimetype;
179     } mimemap;
180    
181     /*
182     * This table maps a file's extension into a Content-Type. The current
183     * official list can be downloaded as
184     * ftp://ftp.isi.edu/in-notes/iana/assignments/media-type
185     * I haven't listed any text types since it doesn't make sense to encode
186     * them. Everything not on the list gets mapped to application/octet-stream
187     */
188    
189     static mimemap mimetable[] = {
190     { "gif", "image/gif" }, /* Grafics Interchange Format */
191     { "jpg", "image/jpeg" }, /* JFIF encoded files */
192     { "jpeg", "image/jpeg" },
193     { "tif", "image/tiff" }, /* Tag Image File Format */
194     { "tiff", "image/tiff" },
195     { "cgm", "image/cgm" }, /* Computer Graphics Metafile */
196     { "au", "audio/basic" }, /* 8kHz ulaw audio data */
197     { "mov", "video/quicktime" }, /* Apple Quicktime */
198     { "qt", "video/quicktime" }, /* Also infrequently used */
199     { "mpeg", "video/mpeg" }, /* Motion Picture Expert Group */
200     { "mpg", "video/mpeg" },
201     { "mp2", "video/mpeg" }, /* dito, MPEG-2 encoded files */
202 root 1.2 { "mp3", "audio/mpeg" }, /* dito, MPEG-3 encoded files */
203 root 1.1 { "ps", "application/postscript" }, /* Postscript Language */
204     { "zip", "application/zip" }, /* ZIP archive */
205     { "doc", "application/msword"},/* assume Microsoft Word */
206     { NULL, NULL }
207     };
208    
209     /*
210     * the order of the following two tables must match the
211     * Encoding Types definition in uudeview.h
212     */
213    
214     /*
215     * encoded bytes per line
216     */
217    
218 root 1.3 static int bpl[8] = { 0, 45, 57, 45, 45, 0, 0, 128 };
219 root 1.1
220     /*
221     * tables
222     */
223    
224     static unsigned char *etables[5] = {
225     NULL,
226     UUEncodeTable,
227     B64EncodeTable,
228     XXEncodeTable,
229     BHEncodeTable
230     };
231    
232     /*
233     * variables to malloc upon initialization
234     */
235    
236     char *uuestr_itemp;
237     char *uuestr_otemp;
238    
239     /*
240     * Encode one part of the data stream
241     */
242    
243 root 1.9 static int
244 root 1.5 UUEncodeStream (FILE *outfile, FILE *infile, int encoding, long linperfile, crc32_t *crc, crc32_t *pcrc)
245 root 1.1 {
246     uchar *itemp = (uchar *) uuestr_itemp;
247     uchar *otemp = (uchar *) uuestr_otemp;
248     unsigned char *optr, *table, *tptr;
249     int index, count;
250     long line=0;
251     size_t llen;
252    
253     if (outfile==NULL || infile==NULL ||
254 root 1.2 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
255 root 1.3 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
256 root 1.1 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
257     uustring (S_PARM_CHECK), "UUEncodeStream()");
258     return UURET_ILLVAL;
259     }
260    
261 root 1.2 /*
262     * Special handling for plain text and quoted printable. Text is
263     * read line oriented.
264     */
265    
266     if (encoding == PT_ENCODED || encoding == QP_ENCODED) {
267 root 1.10 while (!FP_feof (infile) && (linperfile <= 0 || line < linperfile)) {
268     if (FP_fgets (itemp, 255, infile) == NULL) {
269 root 1.2 break;
270     }
271    
272     itemp[255] = '\0';
273     count = strlen (itemp);
274    
275     llen = 0;
276     optr = otemp;
277    
278     /*
279     * Busy Callback
280     */
281 root 1.9
282 root 1.2 if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
283     UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
284     uustring (S_ENCODE_CANCEL));
285     return UURET_CANCEL;
286     }
287    
288     if (encoding == PT_ENCODED) {
289     /*
290     * If there is a line feed, replace by eolstring
291     */
292     if (count > 0 && itemp[count-1] == '\n') {
293     itemp[--count] = '\0';
294     if (fwrite (itemp, 1, count, outfile) != count ||
295     fwrite ((char *) eolstring, 1,
296     strlen(eolstring), outfile) != strlen (eolstring)) {
297     return UURET_IOERR;
298     }
299     }
300     else {
301     if (fwrite (itemp, 1, count, outfile) != llen) {
302     return UURET_IOERR;
303     }
304     }
305     }
306     else if (encoding == QP_ENCODED) {
307     for (index=0; index<count; index++) {
308     if (llen == 0 && itemp[index] == '.') {
309     /*
310     * Special rule: encode '.' at the beginning of a line, so
311     * that some mailers aren't confused.
312     */
313     *optr++ = '=';
314     *optr++ = HexEncodeTable[itemp[index] >> 4];
315     *optr++ = HexEncodeTable[itemp[index] & 0x0f];
316     llen += 3;
317     }
318     else if ((itemp[index] >= 33 && itemp[index] <= 60) ||
319     (itemp[index] >= 62 && itemp[index] <= 126) ||
320     itemp[index] == 9 || itemp[index] == 32) {
321     *optr++ = itemp[index];
322     llen++;
323     }
324     else if (itemp[index] == '\n') {
325     /*
326     * If the last character before EOL was a space or tab,
327     * we must encode it. If llen > 74, there's no space to do
328     * that, so generate a soft line break instead.
329     */
330    
331     if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32)) {
332     *(optr-1) = '=';
333     if (llen <= 74) {
334     *optr++ = HexEncodeTable[itemp[index-1] >> 4];
335     *optr++ = HexEncodeTable[itemp[index-1] & 0x0f];
336     llen += 2;
337     }
338     }
339    
340     if (fwrite (otemp, 1, llen, outfile) != llen ||
341     fwrite ((char *) eolstring, 1,
342     strlen(eolstring), outfile) != strlen (eolstring)) {
343     return UURET_IOERR;
344     }
345    
346     /*
347     * Fix the soft line break condition from above
348     */
349    
350     if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32) &&
351     *(optr-1) == '=') {
352     otemp[0] = '=';
353     otemp[1] = HexEncodeTable[itemp[index-1] >> 4];
354     otemp[2] = HexEncodeTable[itemp[index-1] & 0x0f];
355    
356     if (fwrite (otemp, 1, 3, outfile) != 3 ||
357     fwrite ((char *) eolstring, 1,
358     strlen(eolstring), outfile) != strlen (eolstring)) {
359     return UURET_IOERR;
360     }
361     }
362    
363     optr = otemp;
364     llen = 0;
365     }
366     else {
367     *optr++ = '=';
368     *optr++ = HexEncodeTable[itemp[index] >> 4];
369     *optr++ = HexEncodeTable[itemp[index] & 0x0f];
370     llen += 3;
371     }
372    
373     /*
374     * Lines must be shorter than 76 characters (not counting CRLF).
375     * If the line grows longer than that, we must include a soft
376     * line break.
377     */
378    
379     if (itemp[index+1] != 0 && itemp[index+1] != '\n' &&
380     (llen >= 75 ||
381 root 1.3 (!((itemp[index+1] >= 33 && itemp[index+1] <= 60) ||
382     (itemp[index+1] >= 62 && itemp[index+1] <= 126)) &&
383     llen >= 73))) {
384 root 1.2
385     *optr++ = '=';
386     llen++;
387 root 1.9
388 root 1.2 if (fwrite (otemp, 1, llen, outfile) != llen ||
389     fwrite ((char *) eolstring, 1,
390     strlen(eolstring), outfile) != strlen (eolstring)) {
391     return UURET_IOERR;
392     }
393 root 1.9
394 root 1.2 optr = otemp;
395     llen = 0;
396     }
397     }
398     }
399    
400     line++;
401     }
402    
403     return UURET_OK;
404     }
405    
406     /*
407 root 1.3 * Special handling for yEnc
408     */
409    
410     if (encoding == YENC_ENCODED) {
411     llen = 0;
412     optr = otemp;
413    
414 root 1.10 while (!FP_feof (infile) && (linperfile <= 0 || line < linperfile)) {
415 root 1.3 if ((count = fread (itemp, 1, 128, infile)) != 128) {
416     if (count == 0) {
417     break;
418     }
419     else if (ferror (infile)) {
420     return UURET_IOERR;
421     }
422     }
423    
424 root 1.5 if (pcrc)
425 root 1.8 *pcrc = uu_crc32(*pcrc, itemp, count);
426 root 1.5 if (crc)
427 root 1.8 *crc = uu_crc32(*crc, itemp, count);
428 root 1.5
429 root 1.3 line++;
430    
431     /*
432     * Busy Callback
433     */
434 root 1.9
435 root 1.3 if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
436     UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
437     uustring (S_ENCODE_CANCEL));
438     return UURET_CANCEL;
439     }
440    
441     for (index=0; index<count; index++) {
442     if (llen > 127) {
443     if (fwrite (otemp, 1, llen, outfile) != llen ||
444     fwrite ((char *) eolstring, 1,
445     strlen(eolstring), outfile) != strlen (eolstring)) {
446     return UURET_IOERR;
447     }
448     llen = 0;
449     optr = otemp;
450     }
451    
452     switch ((char) ((int) itemp[index] + 42)) {
453     case '\0':
454     case '\t':
455     case '\n':
456     case '\r':
457     case '=':
458     case '\033':
459     *optr++ = '=';
460     *optr++ = (char) ((int) itemp[index] + 42 + 64);
461     llen += 2;
462     break;
463    
464     case '.':
465     if (llen == 0) {
466     *optr++ = '=';
467     *optr++ = (char) ((int) itemp[index] + 42 + 64);
468     llen += 2;
469     }
470     else {
471     *optr++ = (char) ((int) itemp[index] + 42);
472     llen++;
473     }
474     break;
475    
476     default:
477     *optr++ = (char) ((int) itemp[index] + 42);
478     llen++;
479     break;
480     }
481     }
482     }
483    
484     /*
485     * write last line
486     */
487    
488     if (llen) {
489     if (fwrite (otemp, 1, llen, outfile) != llen ||
490     fwrite ((char *) eolstring, 1,
491     strlen(eolstring), outfile) != strlen (eolstring)) {
492     return UURET_IOERR;
493     }
494     }
495    
496     return UURET_OK;
497     }
498    
499     /*
500 root 1.2 * Handling for binary encodings
501     */
502 root 1.1
503     /*
504     * select charset
505     */
506    
507     table = etables[encoding];
508    
509     if (table==NULL || bpl[encoding]==0) {
510     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
511 root 1.2 uustring (S_PARM_CHECK), "UUEncodeStream()");
512 root 1.1 return UURET_ILLVAL;
513     }
514    
515 root 1.10 while (!FP_feof (infile) && (linperfile <= 0 || line < linperfile)) {
516 root 1.1 if ((count = fread (itemp, 1, bpl[encoding], infile)) != bpl[encoding]) {
517     if (count == 0)
518     break;
519     else if (ferror (infile))
520     return UURET_IOERR;
521     }
522 root 1.2
523 root 1.1 optr = otemp;
524     llen = 0;
525    
526     /*
527     * Busy Callback
528     */
529    
530     if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
531     UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
532     uustring (S_ENCODE_CANCEL));
533     return UURET_CANCEL;
534     }
535    
536     /*
537     * for UU and XX, encode the number of bytes as first character
538     */
539 root 1.2
540 root 1.1 if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
541     *optr++ = table[count];
542     llen++;
543     }
544    
545 root 1.2 /*
546     * Main encoding
547     */
548    
549 root 1.3 for (index=0; index<=count-3; index+=3, llen+=4) {
550     *optr++ = table[itemp[index] >> 2];
551     *optr++ = table[((itemp[index ] & 0x03) << 4)|(itemp[index+1] >> 4)];
552     *optr++ = table[((itemp[index+1] & 0x0f) << 2)|(itemp[index+2] >> 6)];
553     *optr++ = table[ itemp[index+2] & 0x3f];
554 root 1.1 }
555    
556     /*
557     * Special handling for incomplete lines
558     */
559 root 1.2
560 root 1.1 if (index != count) {
561     if (encoding == B64ENCODED) {
562     if (count - index == 2) {
563     *optr++ = table[itemp[index] >> 2];
564 root 1.9 *optr++ = table[((itemp[index ] & 0x03) << 4) |
565 root 1.1 ((itemp[index+1] & 0xf0) >> 4)];
566     *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
567     *optr++ = '=';
568     }
569     else if (count - index == 1) {
570     *optr++ = table[ itemp[index] >> 2];
571     *optr++ = table[(itemp[index] & 0x03) << 4];
572     *optr++ = '=';
573     *optr++ = '=';
574     }
575     llen += 4;
576     }
577 root 1.2 else if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
578 root 1.1 if (count - index == 2) {
579     *optr++ = table[itemp[index] >> 2];
580 root 1.9 *optr++ = table[((itemp[index ] & 0x03) << 4) |
581 root 1.1 ( itemp[index+1] >> 4)];
582     *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
583     *optr++ = table[0];
584     }
585     else if (count - index == 1) {
586     *optr++ = table[ itemp[index] >> 2];
587     *optr++ = table[(itemp[index] & 0x03) << 4];
588     *optr++ = table[0];
589     *optr++ = table[0];
590     }
591     llen += 4;
592     }
593     }
594 root 1.2
595 root 1.1 /*
596     * end of line
597     */
598 root 1.2
599 root 1.1 tptr = eolstring;
600    
601     while (*tptr)
602     *optr++ = *tptr++;
603    
604     *optr++ = '\0';
605     llen += strlen ((char *) eolstring);
606    
607     if (fwrite (otemp, 1, llen, outfile) != llen)
608     return UURET_IOERR;
609    
610     line++;
611     }
612     return UURET_OK;
613     }
614    
615     /*
616     * Encode as MIME multipart/mixed sub-message.
617     */
618    
619     int UUEXPORT
620     UUEncodeMulti (FILE *outfile, FILE *infile, char *infname, int encoding,
621     char *outfname, char *mimetype, int filemode)
622     {
623     mimemap *miter=mimetable;
624     struct stat finfo;
625     int res, themode;
626     FILE *theifile;
627     char *ptr;
628 root 1.5 crc32_t crc;
629     crc32_t *crcptr=NULL;
630 root 1.1
631 root 1.9 if (outfile==NULL ||
632 root 1.1 (infile == NULL && infname==NULL) ||
633     (outfname==NULL && infname==NULL) ||
634 root 1.2 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
635 root 1.3 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
636 root 1.1 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
637     uustring (S_PARM_CHECK), "UUEncodeMulti()");
638     return UURET_ILLVAL;
639     }
640    
641     progress.action = 0;
642    
643     if (infile==NULL) {
644     if (stat (infname, &finfo) == -1) {
645     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
646     uustring (S_NOT_STAT_FILE),
647     infname, strerror (uu_errno=errno));
648     return UURET_IOERR;
649     }
650     if ((theifile = fopen (infname, "rb")) == NULL) {
651     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
652     uustring (S_NOT_OPEN_FILE),
653     infname, strerror (uu_errno=errno));
654     return UURET_IOERR;
655     }
656     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
657     progress.fsize = (long) finfo.st_size;
658     }
659     else {
660     if (fstat (fileno (infile), &finfo) != 0) {
661     themode = (filemode)?filemode:0644;
662     progress.fsize = -1;
663     }
664     else {
665     themode = (int) finfo.st_mode & 0777;
666     progress.fsize = (long) finfo.st_size;
667     }
668     theifile = infile;
669     }
670    
671 root 1.5 if (progress.fsize < 0)
672 root 1.1 progress.fsize = -1;
673    
674 root 1.10 FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
675 root 1.1
676     progress.partno = 1;
677     progress.numparts = 1;
678     progress.percent = 0;
679     progress.foffset = 0;
680     progress.action = UUACT_ENCODING;
681    
682     /*
683     * If not given from outside, select an appropriate Content-Type by
684     * looking at the file's extension. If it is unknown, default to
685     * Application/Octet-Stream
686     */
687    
688     if (mimetype == NULL) {
689 root 1.10 if ((ptr = FP_strrchr ((outfname)?outfname:infname, '.'))) {
690     while (miter->extension && FP_stricmp (ptr+1, miter->extension) != 0)
691 root 1.1 miter++;
692     mimetype = miter->mimetype;
693     }
694     }
695 root 1.2
696     if (mimetype == NULL && (encoding == PT_ENCODED || encoding == QP_ENCODED)) {
697     mimetype = "text/plain";
698     }
699    
700 root 1.1 /*
701     * print sub-header
702     */
703    
704 root 1.3 if (encoding != YENC_ENCODED) {
705     fprintf (outfile, "Content-Type: %s%s",
706     (mimetype)?mimetype:"Application/Octet-Stream",
707     eolstring);
708     fprintf (outfile, "Content-Transfer-Encoding: %s%s",
709     CTE_TYPE(encoding), eolstring);
710     fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
711     UUFNameFilter ((outfname)?outfname:infname), eolstring);
712     fprintf (outfile, "%s", eolstring);
713     }
714 root 1.1
715     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
716     fprintf (outfile, "begin %o %s%s",
717     (themode) ? themode : 0644,
718 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
719 root 1.1 eolstring);
720     }
721 root 1.3 else if (encoding == YENC_ENCODED) {
722 root 1.8 crc = CRC32_INIT;
723 root 1.5 crcptr = &crc;
724 root 1.3 if (progress.fsize == -1) {
725     fprintf (outfile, "=ybegin line=128 name=%s%s",
726 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
727 root 1.3 eolstring);
728     }
729     else {
730     fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
731     progress.fsize,
732 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
733 root 1.3 eolstring);
734     }
735     }
736    
737 root 1.5 if ((res = UUEncodeStream (outfile, theifile, encoding, 0, crcptr, NULL)) != UURET_OK) {
738 root 1.1 if (res != UURET_CANCEL) {
739     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
740     uustring (S_ERR_ENCODING),
741     UUFNameFilter ((infname)?infname:outfname),
742     (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
743     }
744     progress.action = 0;
745     return res;
746     }
747 root 1.3
748 root 1.1 if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
749 root 1.9 fprintf (outfile, "%c%s",
750     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
751 root 1.1 eolstring);
752     fprintf (outfile, "end%s", eolstring);
753     }
754 root 1.3 else if (encoding == YENC_ENCODED) {
755     if (progress.fsize == -1) {
756 root 1.5 fprintf (outfile, "=yend crc32=%08lx%s",
757 root 1.7 (long)crc,
758 root 1.3 eolstring);
759     }
760     else {
761 root 1.5 fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
762 root 1.3 progress.fsize,
763 root 1.7 (long)crc,
764 root 1.3 eolstring);
765     }
766     }
767    
768 root 1.1 /*
769     * empty line at end does no harm
770     */
771 root 1.3
772 root 1.1 fprintf (outfile, "%s", eolstring);
773    
774     if (infile==NULL)
775     fclose (theifile);
776    
777     progress.action = 0;
778     return UURET_OK;
779     }
780    
781     /*
782     * Encode as MIME message/partial
783     */
784    
785     int UUEXPORT
786     UUEncodePartial (FILE *outfile, FILE *infile,
787     char *infname, int encoding,
788     char *outfname, char *mimetype,
789 root 1.5 int filemode, int partno, long linperfile,
790     crc32_t *crcptr)
791 root 1.1 {
792     mimemap *miter=mimetable;
793     static FILE *theifile;
794     int themode, numparts;
795     struct stat finfo;
796     long thesize;
797     char *ptr;
798     int res;
799 root 1.5 crc32_t pcrc;
800     crc32_t *pcrcptr=NULL;
801 root 1.1
802     if ((outfname==NULL&&infname==NULL) || partno<=0 ||
803     (infile == NULL&&infname==NULL) || outfile==NULL ||
804 root 1.2 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
805 root 1.3 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
806 root 1.1 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
807     uustring (S_PARM_CHECK), "UUEncodePartial()");
808     return UURET_ILLVAL;
809     }
810    
811     /*
812     * The first part needs a set of headers
813     */
814    
815     progress.action = 0;
816    
817     if (partno == 1) {
818     if (infile==NULL) {
819     if (stat (infname, &finfo) == -1) {
820     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
821     uustring (S_NOT_STAT_FILE),
822     infname, strerror (uu_errno=errno));
823     return UURET_IOERR;
824     }
825     if ((theifile = fopen (infname, "rb")) == NULL) {
826     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
827     uustring (S_NOT_OPEN_FILE),
828     infname, strerror (uu_errno=errno));
829     return UURET_IOERR;
830     }
831     if (linperfile <= 0)
832     numparts = 1;
833 root 1.9 else
834 root 1.1 numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
835     (linperfile*bpl[encoding]));
836    
837     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
838     thesize = (long) finfo.st_size;
839     }
840     else {
841     if (fstat (fileno (infile), &finfo) != 0) {
842     UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
843     uustring (S_STAT_ONE_PART));
844     numparts = 1;
845     themode = (filemode)?filemode:0644;
846 root 1.5 thesize = -1;
847 root 1.1 }
848     else {
849     if (linperfile <= 0)
850     numparts = 1;
851     else
852     numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
853     (linperfile*bpl[encoding]));
854    
855     themode = (int) finfo.st_mode & 0777;
856     thesize = (long) finfo.st_size;
857     }
858     theifile = infile;
859     }
860    
861 root 1.10 FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
862 root 1.1
863 root 1.5 progress.totsize = (thesize>=0) ? thesize : -1;
864 root 1.1 progress.partno = 1;
865     progress.numparts = numparts;
866     progress.percent = 0;
867     progress.foffset = 0;
868    
869     /*
870     * If not given from outside, select an appropriate Content-Type by
871     * looking at the file's extension. If it is unknown, default to
872     * Application/Octet-Stream
873     */
874    
875     if (mimetype == NULL) {
876 root 1.10 if ((ptr = FP_strrchr ((outfname)?outfname:infname, '.'))) {
877     while (miter->extension && FP_stricmp (ptr+1, miter->extension) != 0)
878 root 1.1 miter++;
879     mimetype = miter->mimetype;
880     }
881     }
882 root 1.2
883     if (mimetype == NULL && (encoding==PT_ENCODED || encoding==QP_ENCODED)) {
884     mimetype = "text/plain";
885     }
886    
887 root 1.1 /*
888     * print sub-header
889     */
890    
891 root 1.3 if (encoding != YENC_ENCODED) {
892     fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
893     fprintf (outfile, "Content-Type: %s%s",
894     (mimetype)?mimetype:"Application/Octet-Stream",
895     eolstring);
896     fprintf (outfile, "Content-Transfer-Encoding: %s%s",
897     CTE_TYPE(encoding), eolstring);
898     fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
899     UUFNameFilter ((outfname)?outfname:infname), eolstring);
900     }
901    
902 root 1.1 fprintf (outfile, "%s", eolstring);
903 root 1.9
904 root 1.1 /*
905     * for the first part of UU or XX messages, print a begin line
906     */
907 root 1.3
908 root 1.1 if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
909     fprintf (outfile, "begin %o %s%s",
910     (themode) ? themode : ((filemode)?filemode:0644),
911     UUFNameFilter ((outfname)?outfname:infname), eolstring);
912     }
913 root 1.5 }
914     if (encoding == YENC_ENCODED) {
915 root 1.8 pcrc = CRC32_INIT;
916 root 1.5 pcrcptr = &pcrc;
917     if (numparts != 1) {
918     if (progress.totsize == -1) {
919     fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
920     partno,
921 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
922 root 1.5 eolstring);
923     }
924     else {
925     fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
926     partno,
927     progress.totsize,
928 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
929 root 1.5 eolstring);
930     }
931 root 1.3
932 root 1.6 fprintf (outfile, "=ypart begin=%ld end=%ld%s",
933     (partno - 1) * linperfile * 128 + 1,
934     (partno * linperfile * 128) < progress.totsize
935     ? partno * linperfile * 128
936     : progress.totsize,
937 root 1.5 eolstring);
938     }
939     else {
940     if (progress.totsize == -1) {
941     fprintf (outfile, "=ybegin line=128 name=%s%s",
942 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
943 root 1.3 eolstring);
944     }
945     else {
946 root 1.5 fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
947     progress.totsize,
948 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
949 root 1.5 eolstring);
950 root 1.3 }
951     }
952 root 1.1 }
953    
954     /*
955     * update progress information
956     */
957    
958     progress.partno = partno;
959     progress.percent = 0;
960     progress.foffset = ftell (theifile);
961    
962     if (progress.totsize <= 0)
963     progress.fsize = -1;
964     else if (linperfile <= 0)
965     progress.fsize = progress.totsize;
966     else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
967     progress.fsize = progress.totsize - progress.foffset;
968     else
969     progress.fsize = linperfile*bpl[encoding];
970    
971     progress.action = UUACT_ENCODING;
972    
973 root 1.5 if ((res = UUEncodeStream (outfile, theifile, encoding, linperfile,
974     crcptr, pcrcptr)) != UURET_OK) {
975 root 1.1 if (infile==NULL) fclose (theifile);
976     if (res != UURET_CANCEL) {
977     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
978     uustring (S_ERR_ENCODING),
979     UUFNameFilter ((outfname)?outfname:infname),
980     (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
981     }
982     progress.action = 0;
983     return res;
984     }
985 root 1.3
986 root 1.1 /*
987     * print end line
988     */
989 root 1.3
990 root 1.10 if (FP_feof (theifile) &&
991 root 1.1 (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
992 root 1.9 fprintf (outfile, "%c%s",
993     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
994 root 1.1 eolstring);
995     fprintf (outfile, "end%s", eolstring);
996     }
997 root 1.3 else if (encoding == YENC_ENCODED) {
998     if (numparts != 1) {
999 root 1.6 fprintf (outfile, "=yend size=%ld part=%d pcrc32=%08lx",
1000     (partno * linperfile * 128) < progress.totsize
1001     ? linperfile * 128
1002     : (progress.totsize - (partno - 1) * linperfile * 128),
1003 root 1.3 partno,
1004 root 1.7 (long)pcrc);
1005 root 1.3 }
1006     else {
1007 root 1.6 fprintf (outfile, "=yend size=%ld",
1008 root 1.5 progress.totsize);
1009 root 1.3 }
1010 root 1.10 if (FP_feof (theifile))
1011 root 1.7 fprintf (outfile, " crc32=%08lx", (long)*crcptr);
1012 root 1.5 fprintf (outfile, "%s", eolstring);
1013 root 1.3 }
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 root 1.10 if (FP_feof (theifile)) {
1030 root 1.1 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.5 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.3 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.5 if (progress.fsize < 0)
1102 root 1.1 progress.fsize = -1;
1103    
1104 root 1.10 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 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
1116 root 1.1 eolstring);
1117     }
1118 root 1.3 else if (encoding == YENC_ENCODED) {
1119 root 1.8 crc = CRC32_INIT;
1120 root 1.5 crcptr = &crc;
1121 root 1.3 if (progress.fsize == -1) {
1122     fprintf (outfile, "=ybegin line=128 name=%s%s",
1123 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
1124 root 1.3 eolstring);
1125     }
1126     else {
1127     fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
1128     progress.fsize,
1129 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
1130 root 1.3 eolstring);
1131     }
1132     }
1133    
1134 root 1.5 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 root 1.9 UUFNameFilter ((infname)?infname:outfname),
1139 root 1.1 (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
1140     }
1141     progress.action = 0;
1142     return res;
1143     }
1144 root 1.3
1145 root 1.1 if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
1146 root 1.9 fprintf (outfile, "%c%s",
1147     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
1148 root 1.1 eolstring);
1149     fprintf (outfile, "end%s", eolstring);
1150     }
1151 root 1.3 else if (encoding == YENC_ENCODED) {
1152     if (progress.fsize == -1) {
1153 root 1.5 fprintf (outfile, "=yend crc32=%08lx%s",
1154 root 1.7 (long)crc,
1155 root 1.3 eolstring);
1156     }
1157     else {
1158 root 1.5 fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
1159 root 1.3 progress.fsize,
1160 root 1.7 (long)crc,
1161 root 1.3 eolstring);
1162     }
1163     }
1164    
1165 root 1.1 /*
1166     * empty line at end does no harm
1167     */
1168 root 1.3
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.5 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.3 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 root 1.9 len = ((uusavepath)?strlen(uusavepath):0) + strlen (diskname)
1216 root 1.1 + ((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 root 1.9 len = ((uusavepath) ? strlen (uusavepath) : 0) +
1228 root 1.1 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 root 1.9 sprintf (oname, "%s%s",
1238 root 1.1 (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.10 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.10 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.10 FP_free (oname);
1274 root 1.1 return UURET_IOERR;
1275     }
1276     if (linperfile <= 0)
1277     numparts = 1;
1278 root 1.9 else
1279 root 1.1 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.10 FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
1306 root 1.1
1307 root 1.5 progress.totsize = (progress.totsize<0) ? -1 : progress.totsize;
1308 root 1.1 progress.numparts = numparts;
1309    
1310 root 1.10 for (part=1; !FP_feof (theifile); part++) {
1311 root 1.1 /*
1312     * Attach extension
1313     */
1314     if (progress.numparts==1 && progress.totsize!=-1 && uuencodeext!=NULL)
1315     strcpy (optr, uuencodeext);
1316 root 1.9 else
1317 root 1.1 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.3
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 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
1384 root 1.1 eolstring);
1385     }
1386 root 1.3 else if (encoding == YENC_ENCODED) {
1387 root 1.5 if (!crcptr) {
1388 root 1.8 crc = CRC32_INIT;
1389 root 1.5 crcptr = &crc;
1390     }
1391 root 1.8 pcrc = CRC32_INIT;
1392 root 1.5 pcrcptr = &pcrc;
1393 root 1.3 if (numparts != 1) {
1394     if (progress.totsize == -1) {
1395     fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
1396     part,
1397 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
1398 root 1.3 eolstring);
1399     }
1400     else {
1401     fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
1402     part,
1403     progress.totsize,
1404 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
1405 root 1.3 eolstring);
1406     }
1407    
1408 root 1.6 fprintf (outfile, "=ypart begin=%ld end=%ld%s",
1409 root 1.3 (part-1)*linperfile*128+1,
1410 root 1.9 (part*linperfile*128) < progress.totsize ?
1411 root 1.3 (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 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
1418 root 1.3 eolstring);
1419     }
1420     else {
1421     fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
1422     progress.totsize,
1423 root 1.9 UUFNameFilter ((outfname)?outfname:infname),
1424 root 1.3 eolstring);
1425     }
1426     }
1427     }
1428    
1429 root 1.1 if ((res = UUEncodeStream (outfile, theifile,
1430 root 1.5 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 root 1.9 UUFNameFilter ((infname)?infname:outfname),
1435 root 1.1 (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.10 FP_free (oname);
1442 root 1.1 return res;
1443     }
1444 root 1.3
1445 root 1.10 if (FP_feof (theifile) &&
1446 root 1.1 (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
1447 root 1.9 fprintf (outfile, "%c%s",
1448     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
1449 root 1.1 eolstring);
1450     fprintf (outfile, "end%s", eolstring);
1451     }
1452 root 1.3 else if (encoding == YENC_ENCODED) {
1453     if (numparts != 1) {
1454 root 1.6 fprintf (outfile, "=yend size=%ld part=%d pcrc32=%08lx",
1455 root 1.9 (part*linperfile*128) < progress.totsize ?
1456 root 1.3 linperfile*128 : (progress.totsize-(part-1)*linperfile*128),
1457     part,
1458 root 1.7 (long)pcrc);
1459 root 1.3 }
1460     else {
1461 root 1.6 fprintf (outfile, "=yend size=%ld",
1462 root 1.5 progress.totsize);
1463 root 1.3 }
1464 root 1.10 if (FP_feof (theifile))
1465 root 1.9 fprintf (outfile, " crc32=%08lx", (long)crc);
1466 root 1.5 fprintf (outfile, "%s", eolstring);
1467 root 1.3 }
1468    
1469 root 1.1 /*
1470     * empty line at end does no harm
1471     */
1472 root 1.3
1473 root 1.1 fprintf (outfile, "%s", eolstring);
1474     fclose (outfile);
1475     }
1476 root 1.3
1477 root 1.1 if (infile==NULL) fclose (theifile);
1478     progress.action = 0;
1479 root 1.10 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.3 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.10 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.3 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.3 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 root 1.9
1589 root 1.10 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.5 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.3 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.3
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 root 1.9 else
1661 root 1.1 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.5 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.3
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.3
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.3
1728     if (encoding == YENC_ENCODED) {
1729 root 1.5 if (partno == 1)
1730 root 1.8 crc = CRC32_INIT;
1731 root 1.5 crcptr = &crc;
1732 root 1.3 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 root 1.9 sprintf (subline, "%s (%03d/%03d) - [ %s ]",
1742 root 1.3 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.3 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 root 1.9
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.5 themode, partno, linperfile, crcptr);
1778 root 1.1
1779 root 1.10 FP_free (subline);
1780 root 1.1
1781     if (infile==NULL) {
1782     if (res != UURET_OK) {
1783     fclose (theifile);
1784     return res;
1785     }
1786 root 1.10 if (FP_feof (theifile)) {
1787 root 1.1 fclose (theifile);
1788     return UURET_OK;
1789     }
1790     return UURET_CONT;
1791     }
1792    
1793     return res;
1794     }