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