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