ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuencode.c
Revision: 1.1
Committed: Mon Jun 11 19:48:58 2001 UTC (22 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
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     * file uudecoder program (c) 1994 by Frank Pilhofer. The author may be
4     * contacted by his email address, fp@informatik.uni-frankfurt.de
5     *
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     #include <uulib.h>
46     #include <uuint.h>
47     #include <fptools.h>
48     #include <uustring.h>
49    
50     /* for braindead systems */
51     #ifndef SEEK_SET
52     #ifdef L_BEGIN
53     #define SEEK_SET L_BEGIN
54     #else
55     #define SEEK_SET 0
56     #endif
57     #endif
58    
59     char * uuencode_id = "$Id: uuencode.c,v 1.15 1996/09/30 19:28:16 fp Exp $";
60    
61     #if 0
62     /*
63     * the End-Of-Line string. MIME enforces CRLF, so that's what we use. Some
64     * implementations of uudecode will complain about a missing end line, since
65     * they look for "end^J" but find "end^J^M". We don't care - especially be-
66     * cause they still decode the file properly despite this complaint.
67     */
68    
69     #ifndef EOLSTRING
70     #define EOLSTRING "\015\012"
71     #endif
72    
73     #else
74    
75     /*
76     * Argh. Some delivery software (inews) has problems with the CRLF
77     * line termination. Let's try native EOL and see if we run into
78     * any problems.
79     * This involves opening output files in text mode instead of binary
80     */
81    
82     #ifndef EOLSTRING
83     #define EOLSTRING "\n"
84     #endif
85    
86     #endif
87    
88    
89     /*
90     * =========================================================================
91     * User-configurable settings end here. Don't spy below unless you know what
92     * you're doing.
93     * =========================================================================
94     */
95    
96     /*
97     * Define End-Of-Line sequence
98     */
99    
100     #ifdef EOLSTRING
101     static unsigned char *eolstring = (unsigned char *) EOLSTRING;
102     #else
103     static unsigned char *eolstring = (unsigned char *) "\012";
104     #endif
105    
106     /*
107     * Content-Transfer-Encoding types for non-MIME encodings
108     */
109    
110     #define CTE_UUENC "x-uuencode"
111     #define CTE_XXENC "x-xxencode"
112     #define CTE_BINHEX "x-binhex"
113    
114     #define CTE_TYPE(y) (((y)==B64ENCODED) ? "Base64" : \
115     ((y)==UU_ENCODED) ? CTE_UUENC : \
116     ((y)==XX_ENCODED) ? CTE_XXENC : \
117     ((y)==BH_ENCODED) ? CTE_BINHEX : "x-oops")
118    
119     /*
120     * encoding tables
121     */
122    
123     unsigned char UUEncodeTable[64] = {
124     '`', '!', '"', '#', '$', '%', '&', '\'',
125     '(', ')', '*', '+', ',', '-', '.', '/',
126     '0', '1', '2', '3', '4', '5', '6', '7',
127     '8', '9', ':', ';', '<', '=', '>', '?',
128     '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
129     'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
130     'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
131     'X', 'Y', 'Z', '[', '\\',']', '^', '_'
132     };
133    
134    
135     unsigned char B64EncodeTable[64] = {
136     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
137     'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
138     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
139     'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
140     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
141     'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
142     'w', 'x', 'y', 'z', '0', '1', '2', '3',
143     '4', '5', '6', '7', '8', '9', '+', '/'
144     };
145    
146     unsigned char XXEncodeTable[64] = {
147     '+', '-', '0', '1', '2', '3', '4', '5',
148     '6', '7', '8', '9', 'A', 'B', 'C', 'D',
149     'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
150     'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
151     'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
152     'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
153     'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
154     's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
155     };
156    
157     unsigned char BHEncodeTable[64] = {
158     '!', '"', '#', '$', '%', '&', '\'', '(',
159     ')', '*', '+', ',', '-', '0', '1', '2',
160     '3', '4', '5', '6', '8', '9', '@', 'A',
161     'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
162     'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
163     'S', 'T', 'U', 'V', 'X', 'Y', 'Z', '[',
164     '`', 'a', 'b', 'c', 'd', 'e', 'f', 'h',
165     'i', 'j', 'k', 'l', 'm', 'p', 'q', 'r'
166     };
167    
168     typedef struct {
169     char *extension;
170     char *mimetype;
171     } mimemap;
172    
173     /*
174     * This table maps a file's extension into a Content-Type. The current
175     * official list can be downloaded as
176     * ftp://ftp.isi.edu/in-notes/iana/assignments/media-type
177     * I haven't listed any text types since it doesn't make sense to encode
178     * them. Everything not on the list gets mapped to application/octet-stream
179     */
180    
181     static mimemap mimetable[] = {
182     { "gif", "image/gif" }, /* Grafics Interchange Format */
183     { "jpg", "image/jpeg" }, /* JFIF encoded files */
184     { "jpeg", "image/jpeg" },
185     { "tif", "image/tiff" }, /* Tag Image File Format */
186     { "tiff", "image/tiff" },
187     { "cgm", "image/cgm" }, /* Computer Graphics Metafile */
188     { "au", "audio/basic" }, /* 8kHz ulaw audio data */
189     { "mov", "video/quicktime" }, /* Apple Quicktime */
190     { "qt", "video/quicktime" }, /* Also infrequently used */
191     { "mpeg", "video/mpeg" }, /* Motion Picture Expert Group */
192     { "mpg", "video/mpeg" },
193     { "mp2", "video/mpeg" }, /* dito, MPEG-2 encoded files */
194     { "mp3", "video/mpeg" }, /* dito, MPEG-3 encoded files */
195     { "ps", "application/postscript" }, /* Postscript Language */
196     { "zip", "application/zip" }, /* ZIP archive */
197     { "doc", "application/msword"},/* assume Microsoft Word */
198     { NULL, NULL }
199     };
200    
201     /*
202     * the order of the following two tables must match the
203     * Encoding Types definition in uudeview.h
204     */
205    
206     /*
207     * encoded bytes per line
208     */
209    
210     static int bpl[5] = { 0, 45, 57, 45, 45 };
211    
212     /*
213     * tables
214     */
215    
216     static unsigned char *etables[5] = {
217     NULL,
218     UUEncodeTable,
219     B64EncodeTable,
220     XXEncodeTable,
221     BHEncodeTable
222     };
223    
224     /*
225     * variables to malloc upon initialization
226     */
227    
228     char *uuestr_itemp;
229     char *uuestr_otemp;
230    
231     /*
232     * Encode one part of the data stream
233     */
234    
235     static int
236     UUEncodeStream (FILE *outfile, FILE *infile, int encoding, long linperfile)
237     {
238     uchar *itemp = (uchar *) uuestr_itemp;
239     uchar *otemp = (uchar *) uuestr_otemp;
240     unsigned char *optr, *table, *tptr;
241     int index, count;
242     long line=0;
243     size_t llen;
244    
245     if (outfile==NULL || infile==NULL ||
246     (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) {
247     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
248     uustring (S_PARM_CHECK), "UUEncodeStream()");
249     return UURET_ILLVAL;
250     }
251    
252    
253     /*
254     * select charset
255     */
256    
257     table = etables[encoding];
258    
259     if (table==NULL || bpl[encoding]==0) {
260     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
261     uustring (S_PARM_CHECK), "UUEncodeStream()");
262     return UURET_ILLVAL;
263     }
264    
265     while (!feof (infile) && (linperfile <= 0 || line < linperfile)) {
266     if ((count = fread (itemp, 1, bpl[encoding], infile)) != bpl[encoding]) {
267     if (count == 0)
268     break;
269     else if (ferror (infile))
270     return UURET_IOERR;
271     }
272     optr = otemp;
273     llen = 0;
274    
275     /*
276     * Busy Callback
277     */
278    
279     if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
280     UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
281     uustring (S_ENCODE_CANCEL));
282     return UURET_CANCEL;
283     }
284    
285     /*
286     * for UU and XX, encode the number of bytes as first character
287     */
288     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
289     *optr++ = table[count];
290     llen++;
291     }
292    
293     for (index=0; index<=count-3; index+=3, llen+=4) {
294     *optr++ = table[itemp[index] >> 2];
295     *optr++ = table[((itemp[index ] & 0x03) << 4) | (itemp[index+1] >> 4)];
296     *optr++ = table[((itemp[index+1] & 0x0f) << 2) | (itemp[index+2] >> 6)];
297     *optr++ = table[ itemp[index+2] & 0x3f];
298     }
299    
300     /*
301     * Special handling for incomplete lines
302     */
303     if (index != count) {
304     if (encoding == B64ENCODED) {
305     if (count - index == 2) {
306     *optr++ = table[itemp[index] >> 2];
307     *optr++ = table[((itemp[index ] & 0x03) << 4) |
308     ((itemp[index+1] & 0xf0) >> 4)];
309     *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
310     *optr++ = '=';
311     }
312     else if (count - index == 1) {
313     *optr++ = table[ itemp[index] >> 2];
314     *optr++ = table[(itemp[index] & 0x03) << 4];
315     *optr++ = '=';
316     *optr++ = '=';
317     }
318     llen += 4;
319     }
320     else {
321     if (count - index == 2) {
322     *optr++ = table[itemp[index] >> 2];
323     *optr++ = table[((itemp[index ] & 0x03) << 4) |
324     ( itemp[index+1] >> 4)];
325     *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
326     *optr++ = table[0];
327     }
328     else if (count - index == 1) {
329     *optr++ = table[ itemp[index] >> 2];
330     *optr++ = table[(itemp[index] & 0x03) << 4];
331     *optr++ = table[0];
332     *optr++ = table[0];
333     }
334     llen += 4;
335     }
336     }
337     /*
338     * end of line
339     */
340     tptr = eolstring;
341    
342     while (*tptr)
343     *optr++ = *tptr++;
344    
345     *optr++ = '\0';
346     llen += strlen ((char *) eolstring);
347    
348     if (fwrite (otemp, 1, llen, outfile) != llen)
349     return UURET_IOERR;
350    
351     line++;
352     }
353     return UURET_OK;
354     }
355    
356     /*
357     * Encode as MIME multipart/mixed sub-message.
358     */
359    
360     int UUEXPORT
361     UUEncodeMulti (FILE *outfile, FILE *infile, char *infname, int encoding,
362     char *outfname, char *mimetype, int filemode)
363     {
364     mimemap *miter=mimetable;
365     struct stat finfo;
366     int res, themode;
367     FILE *theifile;
368     char *ptr;
369    
370     if (outfile==NULL ||
371     (infile == NULL && infname==NULL) ||
372     (outfname==NULL && infname==NULL) ||
373     (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) {
374     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
375     uustring (S_PARM_CHECK), "UUEncodeMulti()");
376     return UURET_ILLVAL;
377     }
378    
379     progress.action = 0;
380    
381     if (infile==NULL) {
382     if (stat (infname, &finfo) == -1) {
383     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
384     uustring (S_NOT_STAT_FILE),
385     infname, strerror (uu_errno=errno));
386     return UURET_IOERR;
387     }
388     if ((theifile = fopen (infname, "rb")) == NULL) {
389     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
390     uustring (S_NOT_OPEN_FILE),
391     infname, strerror (uu_errno=errno));
392     return UURET_IOERR;
393     }
394     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
395     progress.fsize = (long) finfo.st_size;
396     }
397     else {
398     if (fstat (fileno (infile), &finfo) != 0) {
399     themode = (filemode)?filemode:0644;
400     progress.fsize = -1;
401     }
402     else {
403     themode = (int) finfo.st_mode & 0777;
404     progress.fsize = (long) finfo.st_size;
405     }
406     theifile = infile;
407     }
408    
409     if (progress.fsize <= 0)
410     progress.fsize = -1;
411    
412     FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
413    
414     progress.partno = 1;
415     progress.numparts = 1;
416     progress.percent = 0;
417     progress.foffset = 0;
418     progress.action = UUACT_ENCODING;
419    
420     /*
421     * If not given from outside, select an appropriate Content-Type by
422     * looking at the file's extension. If it is unknown, default to
423     * Application/Octet-Stream
424     */
425    
426     if (mimetype == NULL) {
427     if ((ptr = FP_strrchr ((outfname)?outfname:infname, '.'))) {
428     while (miter->extension && FP_stricmp (ptr+1, miter->extension) != 0)
429     miter++;
430     mimetype = miter->mimetype;
431     }
432     }
433     /*
434     * print sub-header
435     */
436    
437     fprintf (outfile, "Content-Type: %s%s",
438     (mimetype)?mimetype:"Application/Octet-Stream",
439     eolstring);
440     fprintf (outfile, "Content-Transfer-Encoding: %s%s",
441     CTE_TYPE(encoding), eolstring);
442     fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
443     UUFNameFilter ((outfname)?outfname:infname), eolstring);
444     fprintf (outfile, "%s", eolstring);
445    
446     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
447     fprintf (outfile, "begin %o %s%s",
448     (themode) ? themode : 0644,
449     UUFNameFilter ((outfname)?outfname:infname),
450     eolstring);
451     }
452     if ((res = UUEncodeStream (outfile, theifile, encoding, 0)) != UURET_OK) {
453     if (res != UURET_CANCEL) {
454     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
455     uustring (S_ERR_ENCODING),
456     UUFNameFilter ((infname)?infname:outfname),
457     (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
458     }
459     progress.action = 0;
460     return res;
461     }
462     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
463     fprintf (outfile, "%c%s",
464     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
465     eolstring);
466     fprintf (outfile, "end%s", eolstring);
467     }
468     /*
469     * empty line at end does no harm
470     */
471     fprintf (outfile, "%s", eolstring);
472    
473     if (infile==NULL)
474     fclose (theifile);
475    
476     progress.action = 0;
477     return UURET_OK;
478     }
479    
480     /*
481     * Encode as MIME message/partial
482     */
483    
484     int UUEXPORT
485     UUEncodePartial (FILE *outfile, FILE *infile,
486     char *infname, int encoding,
487     char *outfname, char *mimetype,
488     int filemode, int partno, long linperfile)
489     {
490     mimemap *miter=mimetable;
491     static FILE *theifile;
492     int themode, numparts;
493     struct stat finfo;
494     long thesize;
495     char *ptr;
496     int res;
497    
498     if ((outfname==NULL&&infname==NULL) || partno<=0 ||
499     (infile == NULL&&infname==NULL) || outfile==NULL ||
500     (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) {
501     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
502     uustring (S_PARM_CHECK), "UUEncodePartial()");
503     return UURET_ILLVAL;
504     }
505    
506     /*
507     * The first part needs a set of headers
508     */
509    
510     progress.action = 0;
511    
512     if (partno == 1) {
513     if (infile==NULL) {
514     if (stat (infname, &finfo) == -1) {
515     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
516     uustring (S_NOT_STAT_FILE),
517     infname, strerror (uu_errno=errno));
518     return UURET_IOERR;
519     }
520     if ((theifile = fopen (infname, "rb")) == NULL) {
521     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
522     uustring (S_NOT_OPEN_FILE),
523     infname, strerror (uu_errno=errno));
524     return UURET_IOERR;
525     }
526     if (linperfile <= 0)
527     numparts = 1;
528     else
529     numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
530     (linperfile*bpl[encoding]));
531    
532     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
533     thesize = (long) finfo.st_size;
534     }
535     else {
536     if (fstat (fileno (infile), &finfo) != 0) {
537     UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
538     uustring (S_STAT_ONE_PART));
539     numparts = 1;
540     themode = (filemode)?filemode:0644;
541     thesize = 0;
542     }
543     else {
544     if (linperfile <= 0)
545     numparts = 1;
546     else
547     numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
548     (linperfile*bpl[encoding]));
549    
550     themode = (int) finfo.st_mode & 0777;
551     thesize = (long) finfo.st_size;
552     }
553     theifile = infile;
554     }
555    
556     FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
557    
558     progress.totsize = (thesize>0) ? thesize : -1;
559     progress.partno = 1;
560     progress.numparts = numparts;
561     progress.percent = 0;
562     progress.foffset = 0;
563    
564     /*
565     * If not given from outside, select an appropriate Content-Type by
566     * looking at the file's extension. If it is unknown, default to
567     * Application/Octet-Stream
568     */
569    
570     if (mimetype == NULL) {
571     if ((ptr = FP_strrchr ((outfname)?outfname:infname, '.'))) {
572     while (miter->extension && FP_stricmp (ptr+1, miter->extension) != 0)
573     miter++;
574     mimetype = miter->mimetype;
575     }
576     }
577     /*
578     * print sub-header
579     */
580    
581     fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
582     fprintf (outfile, "Content-Type: %s%s",
583     (mimetype)?mimetype:"Application/Octet-Stream",
584     eolstring);
585     fprintf (outfile, "Content-Transfer-Encoding: %s%s",
586     CTE_TYPE(encoding), eolstring);
587     fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
588     UUFNameFilter ((outfname)?outfname:infname), eolstring);
589     fprintf (outfile, "%s", eolstring);
590    
591     /*
592     * for the first part of UU or XX messages, print a begin line
593     */
594     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
595     fprintf (outfile, "begin %o %s%s",
596     (themode) ? themode : ((filemode)?filemode:0644),
597     UUFNameFilter ((outfname)?outfname:infname), eolstring);
598     }
599     }
600    
601     /*
602     * update progress information
603     */
604    
605     progress.partno = partno;
606     progress.percent = 0;
607     progress.foffset = ftell (theifile);
608    
609     if (progress.totsize <= 0)
610     progress.fsize = -1;
611     else if (linperfile <= 0)
612     progress.fsize = progress.totsize;
613     else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
614     progress.fsize = progress.totsize - progress.foffset;
615     else
616     progress.fsize = linperfile*bpl[encoding];
617    
618     progress.action = UUACT_ENCODING;
619    
620     if ((res = UUEncodeStream (outfile, theifile,
621     encoding, linperfile)) != UURET_OK) {
622     if (infile==NULL) fclose (theifile);
623     if (res != UURET_CANCEL) {
624     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
625     uustring (S_ERR_ENCODING),
626     UUFNameFilter ((outfname)?outfname:infname),
627     (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
628     }
629     progress.action = 0;
630     return res;
631     }
632     /*
633     * print end line
634     */
635     if (feof (theifile) &&
636     (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
637     fprintf (outfile, "%c%s",
638     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
639     eolstring);
640     fprintf (outfile, "end%s", eolstring);
641     }
642     /*
643     * empty line at end does no harm
644     */
645     fprintf (outfile, "%s", eolstring);
646    
647     if (infile==NULL) {
648     if (res != UURET_OK) {
649     progress.action = 0;
650     fclose (theifile);
651     return res;
652     }
653     if (feof (theifile)) {
654     progress.action = 0;
655     fclose (theifile);
656     return UURET_OK;
657     }
658     return UURET_CONT;
659     }
660    
661     /*
662     * leave progress.action as-is
663     */
664    
665     return UURET_OK;
666     }
667    
668     /*
669     * send output to a stream, don't do any headers at all
670     */
671    
672     int UUEXPORT
673     UUEncodeToStream (FILE *outfile, FILE *infile,
674     char *infname, int encoding,
675     char *outfname, int filemode)
676     {
677     struct stat finfo;
678     FILE *theifile;
679     int themode;
680     int res;
681    
682     if (outfile==NULL ||
683     (infile == NULL&&infname==NULL) ||
684     (outfname==NULL&&infname==NULL) ||
685     (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) {
686     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
687     uustring (S_PARM_CHECK), "UUEncodeToStream()");
688     return UURET_ILLVAL;
689     }
690    
691     progress.action = 0;
692    
693     if (infile==NULL) {
694     if (stat (infname, &finfo) == -1) {
695     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
696     uustring (S_NOT_STAT_FILE),
697     infname, strerror (uu_errno=errno));
698     return UURET_IOERR;
699     }
700     if ((theifile = fopen (infname, "rb")) == NULL) {
701     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
702     uustring (S_NOT_OPEN_FILE),
703     infname, strerror (uu_errno=errno));
704     return UURET_IOERR;
705     }
706     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
707     progress.fsize = (long) finfo.st_size;
708     }
709     else {
710     if (fstat (fileno (infile), &finfo) == -1) {
711     /* gotta live with it */
712     themode = 0644;
713     progress.fsize = -1;
714     }
715     else {
716     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
717     progress.fsize = (long) finfo.st_size;
718     }
719     theifile = infile;
720     }
721    
722     if (progress.fsize <= 0)
723     progress.fsize = -1;
724    
725     FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
726    
727     progress.partno = 1;
728     progress.numparts = 1;
729     progress.percent = 0;
730     progress.foffset = 0;
731     progress.action = UUACT_ENCODING;
732    
733     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
734     fprintf (outfile, "begin %o %s%s",
735     (themode) ? themode : 0644,
736     UUFNameFilter ((outfname)?outfname:infname),
737     eolstring);
738     }
739     if ((res = UUEncodeStream (outfile, theifile, encoding, 0)) != UURET_OK) {
740     if (res != UURET_CANCEL) {
741     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
742     uustring (S_ERR_ENCODING),
743     UUFNameFilter ((infname)?infname:outfname),
744     (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
745     }
746     progress.action = 0;
747     return res;
748     }
749     if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
750     fprintf (outfile, "%c%s",
751     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
752     eolstring);
753     fprintf (outfile, "end%s", eolstring);
754     }
755     /*
756     * empty line at end does no harm
757     */
758     fprintf (outfile, "%s", eolstring);
759    
760     if (infile==NULL) fclose (theifile);
761     progress.action = 0;
762    
763     return UURET_OK;
764     }
765    
766     /*
767     * Encode to files on disk, don't generate any headers
768     */
769    
770     int UUEXPORT
771     UUEncodeToFile (FILE *infile, char *infname, int encoding,
772     char *outfname, char *diskname, long linperfile)
773     {
774     int part, numparts, len, filemode, res;
775     char *oname=NULL, *optr, *ptr;
776     FILE *theifile, *outfile;
777     struct stat finfo;
778    
779     if ((diskname==NULL&&infname==NULL) ||
780     (outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
781     (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) {
782     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
783     uustring (S_PARM_CHECK), "UUEncodeToFile()");
784     return UURET_ILLVAL;
785     }
786    
787     if (diskname) {
788     if ((ptr = strchr (diskname, '/')) == NULL)
789     ptr = strchr (diskname, '\\');
790     if (ptr) {
791     len = strlen (diskname) + ((uuencodeext)?strlen(uuencodeext):3) + 5;
792    
793     if ((oname = malloc (len)) == NULL) {
794     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
795     uustring (S_OUT_OF_MEMORY), len);
796     return UURET_NOMEM;
797     }
798     sprintf (oname, "%s", diskname);
799     }
800     else {
801     len = ((uusavepath)?strlen(uusavepath):0) + strlen (diskname)
802     + ((uuencodeext)?strlen(uuencodeext):0) + 5;
803    
804     if ((oname = malloc (len)) == NULL) {
805     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
806     uustring (S_OUT_OF_MEMORY), len);
807     return UURET_NOMEM;
808     }
809     sprintf (oname, "%s%s", (uusavepath)?uusavepath:"", diskname);
810     }
811     }
812     else {
813     len = ((uusavepath) ? strlen (uusavepath) : 0) +
814     strlen(UUFNameFilter(infname)) +
815     ((uuencodeext)?strlen(uuencodeext):0) + 5;
816    
817     if ((oname = malloc (len)) == NULL) {
818     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
819     uustring (S_OUT_OF_MEMORY), len);
820     return UURET_NOMEM;
821     }
822     optr = UUFNameFilter (infname);
823     sprintf (oname, "%s%s",
824     (uusavepath)?uusavepath:"",
825     (*optr=='.')?optr+1:optr);
826     }
827    
828     /*
829     * optr points after the last dot, so that we can print the part number
830     * there.
831     */
832    
833     optr = FP_strrchr (oname, '.');
834     if (optr==NULL || strchr (optr, '/')!=NULL || strchr (optr, '\\')!=NULL) {
835     optr = oname + strlen (oname);
836     *optr++ = '.';
837     }
838     else if (optr==oname || *(optr-1)=='/' || *(optr-1)=='\\') {
839     optr = oname + strlen (oname);
840     *optr++ = '.';
841     }
842     else
843     optr++;
844    
845     progress.action = 0;
846    
847     if (infile==NULL) {
848     if (stat (infname, &finfo) == -1) {
849     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
850     uustring (S_NOT_STAT_FILE),
851     infname, strerror (uu_errno=errno));
852     FP_free (oname);
853     return UURET_IOERR;
854     }
855     if ((theifile = fopen (infname, "rb")) == NULL) {
856     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
857     uustring (S_NOT_OPEN_FILE),
858     infname, strerror (uu_errno=errno));
859     FP_free (oname);
860     return UURET_IOERR;
861     }
862     if (linperfile <= 0)
863     numparts = 1;
864     else
865     numparts = (int) (((long)finfo.st_size + (linperfile*bpl[encoding]-1)) /
866     (linperfile*bpl[encoding]));
867    
868     filemode = (int) finfo.st_mode & 0777;
869     progress.totsize = (long) finfo.st_size;
870     }
871     else {
872     if (fstat (fileno (infile), &finfo) == -1) {
873     /* gotta live with it */
874     filemode = 0644;
875     numparts = -1;
876     progress.totsize = -1;
877     }
878     else {
879     if (linperfile <= 0)
880     numparts = 1;
881     else
882     numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
883     (linperfile*bpl[encoding]));
884    
885     filemode = (int) finfo.st_mode & 0777;
886     progress.totsize = -1;
887     }
888     theifile = infile;
889     }
890    
891     FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
892    
893     progress.totsize = (progress.totsize<=0) ? -1 : progress.totsize;
894     progress.numparts = numparts;
895    
896     for (part=1; !feof (theifile); part++) {
897     /*
898     * Attach extension
899     */
900     if (progress.numparts==1 && progress.totsize!=-1 && uuencodeext!=NULL)
901     strcpy (optr, uuencodeext);
902     else
903     sprintf (optr, "%03d", part);
904    
905     /*
906     * check if target file exists
907     */
908    
909     if (!uu_overwrite) {
910     if (stat (oname, &finfo) == 0) {
911     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
912     uustring (S_TARGET_EXISTS), oname);
913     if (infile==NULL) fclose (theifile);
914     progress.action = 0;
915     free (oname);
916     return UURET_EXISTS;
917     }
918     }
919    
920     /*
921     * update progress information
922     */
923    
924     progress.action = 0;
925     progress.partno = part;
926     progress.percent = 0;
927     progress.foffset = ftell (theifile);
928    
929     if (progress.totsize == -1)
930     progress.fsize = -1;
931     else if (linperfile <= 0)
932     progress.fsize = progress.totsize;
933     else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
934     progress.fsize = progress.totsize - progress.foffset;
935     else
936     progress.fsize = linperfile*bpl[encoding];
937    
938     progress.action = UUACT_ENCODING;
939    
940     if ((outfile = fopen (oname, "w")) == NULL) {
941     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
942     uustring (S_NOT_OPEN_TARGET),
943     oname, strerror (uu_errno = errno));
944     if (infile==NULL) fclose (theifile);
945     progress.action = 0;
946     free (oname);
947     return UURET_IOERR;
948     }
949     fprintf (outfile, "%s", eolstring);
950     fprintf (outfile, "_=_ %s", eolstring);
951     if (numparts == -1)
952     fprintf (outfile, "_=_ Part %03d of file %s%s",
953     part, UUFNameFilter ((outfname)?outfname:infname),
954     eolstring);
955     else
956     fprintf (outfile, "_=_ Part %03d of %03d of file %s%s",
957     part, numparts,
958     UUFNameFilter ((outfname)?outfname:infname),
959     eolstring);
960     fprintf (outfile, "_=_ %s", eolstring);
961     fprintf (outfile, "%s", eolstring);
962    
963     if (part==1 && (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
964     fprintf (outfile, "begin %o %s%s",
965     (filemode)?filemode : 0644,
966     UUFNameFilter ((outfname)?outfname:infname),
967     eolstring);
968     }
969     if ((res = UUEncodeStream (outfile, theifile,
970     encoding, linperfile)) != UURET_OK) {
971     if (res != UURET_CANCEL) {
972     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
973     uustring (S_ERR_ENCODING),
974     UUFNameFilter ((infname)?infname:outfname),
975     (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
976     }
977     if (infile==NULL) fclose (theifile);
978     progress.action = 0;
979     fclose (outfile);
980     unlink (oname);
981     FP_free (oname);
982     return res;
983     }
984     if (feof (theifile) &&
985     (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
986     fprintf (outfile, "%c%s",
987     (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
988     eolstring);
989     fprintf (outfile, "end%s", eolstring);
990     }
991     /*
992     * empty line at end does no harm
993     */
994     fprintf (outfile, "%s", eolstring);
995     fclose (outfile);
996     }
997     if (infile==NULL) fclose (theifile);
998     progress.action = 0;
999     FP_free (oname);
1000     return UURET_OK;
1001     }
1002    
1003     /*
1004     * Encode a MIME Mail message or Newsgroup posting and send to a
1005     * stream. Still needs a somewhat smart MDA, since we only gene-
1006     * rate a minimum set of headers.
1007     */
1008    
1009     int UUEXPORT
1010     UUE_PrepSingle (FILE *outfile, FILE *infile,
1011     char *infname, int encoding,
1012     char *outfname, int filemode,
1013     char *destination, char *from,
1014     char *subject, int isemail)
1015     {
1016     mimemap *miter=mimetable;
1017     char *subline, *oname;
1018     char *mimetype, *ptr;
1019     int res, len;
1020    
1021     if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
1022     (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) {
1023     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1024     uustring (S_PARM_CHECK), "UUE_PrepSingle()");
1025     return UURET_ILLVAL;
1026     }
1027    
1028     oname = UUFNameFilter ((outfname)?outfname:infname);
1029     len = ((subject)?strlen(subject):0) + strlen(oname) + 40;
1030    
1031     if ((ptr = FP_strrchr (oname, '.'))) {
1032     while (miter->extension && FP_stricmp (ptr+1, miter->extension) != 0)
1033     miter++;
1034     mimetype = miter->mimetype;
1035     }
1036     else
1037     mimetype = NULL;
1038    
1039     if ((subline = (char *) malloc (len)) == NULL) {
1040     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1041     uustring (S_OUT_OF_MEMORY), len);
1042     return UURET_NOMEM;
1043     }
1044    
1045     if (subject)
1046     sprintf (subline, "%s (001/001) - [ %s ]", subject, oname);
1047     else
1048     sprintf (subline, "[ %s ] (001/001)", oname);
1049    
1050     fprintf (outfile, "Subject: %s%s", subline, eolstring);
1051    
1052     if (from) {
1053     fprintf (outfile, "From: %s%s", from, eolstring);
1054     }
1055     if (destination) {
1056     fprintf (outfile, "%s: %s%s",
1057     (isemail)?"To":"Newsgroups",
1058     destination, eolstring);
1059     }
1060     fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
1061     fprintf (outfile, "Content-Type: %s; name=\"%s\"%s",
1062     (mimetype)?mimetype:"Application/Octet-Stream",
1063     UUFNameFilter ((outfname)?outfname:infname),
1064     eolstring);
1065     fprintf (outfile, "Content-Transfer-Encoding: %s%s",
1066     CTE_TYPE(encoding), eolstring);
1067     fprintf (outfile, "%s", eolstring);
1068    
1069     res = UUEncodeToStream (outfile, infile, infname, encoding,
1070     outfname, filemode);
1071    
1072     FP_free (subline);
1073     return res;
1074     }
1075    
1076     int UUEXPORT
1077     UUE_PrepPartial (FILE *outfile, FILE *infile,
1078     char *infname, int encoding,
1079     char *outfname, int filemode,
1080     int partno, long linperfile, long filesize,
1081     char *destination, char *from, char *subject,
1082     int isemail)
1083     {
1084     static int numparts, themode;
1085     static char mimeid[64];
1086     static FILE *theifile;
1087     struct stat finfo;
1088     char *subline, *oname;
1089     long thesize;
1090     int res, len;
1091    
1092     if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
1093     (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) {
1094     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1095     uustring (S_PARM_CHECK), "UUE_PrepPartial()");
1096     return UURET_ILLVAL;
1097     }
1098    
1099     oname = UUFNameFilter ((outfname)?outfname:infname);
1100     len = ((subject)?strlen(subject):0) + strlen (oname) + 40;
1101    
1102     /*
1103     * if first part, get information about the file
1104     */
1105     if (partno == 1) {
1106     if (infile==NULL) {
1107     if (stat (infname, &finfo) == -1) {
1108     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1109     uustring (S_NOT_STAT_FILE),
1110     infname, strerror (uu_errno=errno));
1111     return UURET_IOERR;
1112     }
1113     if ((theifile = fopen (infname, "rb")) == NULL) {
1114     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1115     uustring (S_NOT_OPEN_FILE),
1116     infname, strerror (uu_errno=errno));
1117     return UURET_IOERR;
1118     }
1119     if (linperfile <= 0)
1120     numparts = 1;
1121     else
1122     numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
1123     (linperfile*bpl[encoding]));
1124    
1125     themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
1126     thesize = (long) finfo.st_size;
1127     }
1128     else {
1129     if (fstat (fileno (infile), &finfo) != 0) {
1130     if (filesize <= 0) {
1131     UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
1132     uustring (S_STAT_ONE_PART));
1133     numparts = 1;
1134     themode = (filemode)?filemode:0644;
1135     thesize = 0;
1136     }
1137     else {
1138     if (linperfile <= 0)
1139     numparts = 1;
1140     else
1141     numparts = (int) ((filesize+(linperfile*bpl[encoding]-1))/
1142     (linperfile*bpl[encoding]));
1143    
1144     themode = (filemode)?filemode:0644;
1145     thesize = filesize;
1146     }
1147     }
1148     else {
1149     if (linperfile <= 0)
1150     numparts = 1;
1151     else
1152     numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
1153     (linperfile*bpl[encoding]));
1154    
1155     filemode = (int) finfo.st_mode & 0777;
1156     thesize = (long) finfo.st_size;
1157     }
1158     theifile = infile;
1159     }
1160     /*
1161     * if there's one part only, don't use Message/Partial
1162     */
1163    
1164     if (numparts == 1) {
1165     if (infile==NULL) fclose (theifile);
1166     return UUE_PrepSingle (outfile, infile, infname, encoding,
1167     outfname, filemode, destination,
1168     from, subject, isemail);
1169     }
1170    
1171     /*
1172     * we also need a unique ID
1173     */
1174     sprintf (mimeid, "UUDV-%ld.%ld.%s",
1175     (long) time(NULL), thesize,
1176     (strlen(oname)>16)?"oops":oname);
1177     }
1178    
1179     if ((subline = (char *) malloc (len)) == NULL) {
1180     UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
1181     uustring (S_OUT_OF_MEMORY), len);
1182     if (infile==NULL) fclose (theifile);
1183     return UURET_NOMEM;
1184     }
1185    
1186     if (subject)
1187     sprintf (subline, "%s (%03d/%03d) - [ %s ]",
1188     subject, partno, numparts, oname);
1189     else
1190     sprintf (subline, "[ %s ] (%03d/%03d)",
1191     oname, partno, numparts);
1192    
1193     fprintf (outfile, "Subject: %s%s", subline, eolstring);
1194    
1195     if (from) {
1196     fprintf (outfile, "From: %s%s", from, eolstring);
1197     }
1198     if (destination) {
1199     fprintf (outfile, "%s: %s%s",
1200     (isemail)?"To":"Newsgroups",
1201     destination, eolstring);
1202     }
1203     fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
1204     fprintf (outfile, "Content-Type: Message/Partial; number=%d; total=%d;%s",
1205     partno, numparts, eolstring);
1206     fprintf (outfile, "\tid=\"%s\"%s",
1207     mimeid, eolstring);
1208     fprintf (outfile, "%s", eolstring);
1209    
1210     res = UUEncodePartial (outfile, theifile,
1211     infname, encoding,
1212     (outfname)?outfname:infname, NULL,
1213     themode, partno, linperfile);
1214    
1215     FP_free (subline);
1216    
1217     if (infile==NULL) {
1218     if (res != UURET_OK) {
1219     fclose (theifile);
1220     return res;
1221     }
1222     if (feof (theifile)) {
1223     fclose (theifile);
1224     return UURET_OK;
1225     }
1226     return UURET_CONT;
1227     }
1228    
1229     return res;
1230     }