ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuencode.c
Revision: 1.3
Committed: Sun Mar 31 20:04:30 2002 UTC (22 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +360 -73 lines
Log Message:
*** empty log message ***

File Contents

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