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