ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuencode.c
Revision: 1.12
Committed: Sat Sep 24 06:22:47 2022 UTC (19 months, 3 weeks ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.11: +36 -59 lines
Log Message:
*** empty log message ***

File Contents

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