ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuencode.c
Revision: 1.2.2.4
Committed: Thu Nov 6 13:08:23 2003 UTC (20 years, 7 months ago) by root
Content type: text/plain
Branch: UUDEVIEW
CVS Tags: UUDEVIEW-0-5-19
Changes since 1.2.2.3: +0 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * This file is part of uudeview, the simple and friendly multi-part multi-
3 * file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may
4 * be contacted at fp@fpx.de
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #ifdef SYSTEM_WINDLL
22 #include <windows.h>
23 #endif
24 #ifdef SYSTEM_OS2
25 #include <os2.h>
26 #endif
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <time.h>
33
34 #ifdef STDC_HEADERS
35 #include <stdlib.h>
36 #include <string.h>
37 #endif
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #ifdef HAVE_ERRNO_H
42 #include <errno.h>
43 #endif
44
45 #include <uudeview.h>
46 #include <uuint.h>
47 #include <fptools.h>
48 #include <uustring.h>
49 #include <crc32.h>
50
51 /* for braindead systems */
52 #ifndef SEEK_SET
53 #ifdef L_BEGIN
54 #define SEEK_SET L_BEGIN
55 #else
56 #define SEEK_SET 0
57 #endif
58 #endif
59
60 char * uuencode_id = "$Id: uuencode.c,v 1.22 2002/04/02 10:04:52 fp Exp $";
61
62 #if 0
63 /*
64 * the End-Of-Line string. MIME enforces CRLF, so that's what we use. Some
65 * implementations of uudecode will complain about a missing end line, since
66 * they look for "end^J" but find "end^J^M". We don't care - especially be-
67 * cause they still decode the file properly despite this complaint.
68 */
69
70 #ifndef EOLSTRING
71 #define EOLSTRING "\015\012"
72 #endif
73
74 #else
75
76 /*
77 * Argh. Some delivery software (inews) has problems with the CRLF
78 * line termination. Let's try native EOL and see if we run into
79 * any problems.
80 * This involves opening output files in text mode instead of binary
81 */
82
83 #ifndef EOLSTRING
84 #define EOLSTRING "\n"
85 #endif
86
87 #endif
88
89
90 /*
91 * =========================================================================
92 * User-configurable settings end here. Don't spy below unless you know what
93 * you're doing.
94 * =========================================================================
95 */
96
97 /*
98 * Define End-Of-Line sequence
99 */
100
101 #ifdef EOLSTRING
102 static unsigned char *eolstring = (unsigned char *) EOLSTRING;
103 #else
104 static unsigned char *eolstring = (unsigned char *) "\012";
105 #endif
106
107 /*
108 * Content-Transfer-Encoding types for non-MIME encodings
109 */
110
111 #define CTE_UUENC "x-uuencode"
112 #define CTE_XXENC "x-xxencode"
113 #define CTE_BINHEX "x-binhex"
114 #define CTE_YENC "x-yenc"
115
116 #define CTE_TYPE(y) (((y)==B64ENCODED) ? "Base64" : \
117 ((y)==UU_ENCODED) ? CTE_UUENC : \
118 ((y)==XX_ENCODED) ? CTE_XXENC : \
119 ((y)==PT_ENCODED) ? "8bit" : \
120 ((y)==QP_ENCODED) ? "quoted-printable" : \
121 ((y)==BH_ENCODED) ? CTE_BINHEX : \
122 ((y)==YENC_ENCODED) ? CTE_YENC : "x-oops")
123
124 /*
125 * encoding tables
126 */
127
128 unsigned char UUEncodeTable[64] = {
129 '`', '!', '"', '#', '$', '%', '&', '\'',
130 '(', ')', '*', '+', ',', '-', '.', '/',
131 '0', '1', '2', '3', '4', '5', '6', '7',
132 '8', '9', ':', ';', '<', '=', '>', '?',
133 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
134 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
135 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
136 'X', 'Y', 'Z', '[', '\\',']', '^', '_'
137 };
138
139
140 unsigned char B64EncodeTable[64] = {
141 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
142 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
143 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
144 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
145 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
146 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
147 'w', 'x', 'y', 'z', '0', '1', '2', '3',
148 '4', '5', '6', '7', '8', '9', '+', '/'
149 };
150
151 unsigned char XXEncodeTable[64] = {
152 '+', '-', '0', '1', '2', '3', '4', '5',
153 '6', '7', '8', '9', 'A', 'B', 'C', 'D',
154 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
155 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
156 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
157 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
158 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
159 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
160 };
161
162 unsigned char BHEncodeTable[64] = {
163 '!', '"', '#', '$', '%', '&', '\'', '(',
164 ')', '*', '+', ',', '-', '0', '1', '2',
165 '3', '4', '5', '6', '8', '9', '@', 'A',
166 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
167 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
168 'S', 'T', 'U', 'V', 'X', 'Y', 'Z', '[',
169 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'h',
170 'i', 'j', 'k', 'l', 'm', 'p', 'q', 'r'
171 };
172
173 unsigned char HexEncodeTable[16] = {
174 '0', '1', '2', '3', '4', '5', '6', '7',
175 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
176 };
177
178 typedef struct {
179 char *extension;
180 char *mimetype;
181 } mimemap;
182
183 /*
184 * This table maps a file's extension into a Content-Type. The current
185 * official list can be downloaded as
186 * ftp://ftp.isi.edu/in-notes/iana/assignments/media-type
187 * I haven't listed any text types since it doesn't make sense to encode
188 * them. Everything not on the list gets mapped to application/octet-stream
189 */
190
191 static mimemap mimetable[] = {
192 { "gif", "image/gif" }, /* Grafics Interchange Format */
193 { "jpg", "image/jpeg" }, /* JFIF encoded files */
194 { "jpeg", "image/jpeg" },
195 { "tif", "image/tiff" }, /* Tag Image File Format */
196 { "tiff", "image/tiff" },
197 { "cgm", "image/cgm" }, /* Computer Graphics Metafile */
198 { "au", "audio/basic" }, /* 8kHz ulaw audio data */
199 { "mov", "video/quicktime" }, /* Apple Quicktime */
200 { "qt", "video/quicktime" }, /* Also infrequently used */
201 { "mpeg", "video/mpeg" }, /* Motion Picture Expert Group */
202 { "mpg", "video/mpeg" },
203 { "mp2", "video/mpeg" }, /* dito, MPEG-2 encoded files */
204 { "mp3", "audio/mpeg" }, /* dito, MPEG-3 encoded files */
205 { "ps", "application/postscript" }, /* Postscript Language */
206 { "zip", "application/zip" }, /* ZIP archive */
207 { "doc", "application/msword"},/* assume Microsoft Word */
208 { NULL, NULL }
209 };
210
211 /*
212 * the order of the following two tables must match the
213 * Encoding Types definition in uudeview.h
214 */
215
216 /*
217 * encoded bytes per line
218 */
219
220 static int bpl[8] = { 0, 45, 57, 45, 45, 0, 0, 128 };
221
222 /*
223 * tables
224 */
225
226 static unsigned char *etables[5] = {
227 NULL,
228 UUEncodeTable,
229 B64EncodeTable,
230 XXEncodeTable,
231 BHEncodeTable
232 };
233
234 /*
235 * variables to malloc upon initialization
236 */
237
238 char *uuestr_itemp;
239 char *uuestr_otemp;
240
241 /*
242 * Encode one part of the data stream
243 */
244
245 static int
246 UUEncodeStream (FILE *outfile, FILE *infile, int encoding, long linperfile, crc32_t *crc, crc32_t *pcrc)
247 {
248 unsigned char *itemp = (char *) uuestr_itemp;
249 unsigned char *otemp = (char *) uuestr_otemp;
250 unsigned char *optr, *table, *tptr;
251 int index, count;
252 long line=0;
253 size_t llen;
254
255 if (outfile==NULL || infile==NULL ||
256 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
257 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
258 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
259 uustring (S_PARM_CHECK), "UUEncodeStream()");
260 return UURET_ILLVAL;
261 }
262
263 /*
264 * Special handling for plain text and quoted printable. Text is
265 * read line oriented.
266 */
267
268 if (encoding == PT_ENCODED || encoding == QP_ENCODED) {
269 while (!feof (infile) && (linperfile <= 0 || line < linperfile)) {
270 if (_FP_fgets (itemp, 255, infile) == NULL) {
271 break;
272 }
273
274 itemp[255] = '\0';
275 count = strlen (itemp);
276
277 llen = 0;
278 optr = otemp;
279
280 /*
281 * Busy Callback
282 */
283
284 if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
285 UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
286 uustring (S_ENCODE_CANCEL));
287 return UURET_CANCEL;
288 }
289
290 if (encoding == PT_ENCODED) {
291 /*
292 * If there is a line feed, replace by eolstring
293 */
294 if (count > 0 && itemp[count-1] == '\n') {
295 itemp[--count] = '\0';
296 if (fwrite (itemp, 1, count, outfile) != count ||
297 fwrite ((char *) eolstring, 1,
298 strlen(eolstring), outfile) != strlen (eolstring)) {
299 return UURET_IOERR;
300 }
301 }
302 else {
303 if (fwrite (itemp, 1, count, outfile) != llen) {
304 return UURET_IOERR;
305 }
306 }
307 }
308 else if (encoding == QP_ENCODED) {
309 for (index=0; index<count; index++) {
310 if (llen == 0 && itemp[index] == '.') {
311 /*
312 * Special rule: encode '.' at the beginning of a line, so
313 * that some mailers aren't confused.
314 */
315 *optr++ = '=';
316 *optr++ = HexEncodeTable[itemp[index] >> 4];
317 *optr++ = HexEncodeTable[itemp[index] & 0x0f];
318 llen += 3;
319 }
320 else if ((itemp[index] >= 33 && itemp[index] <= 60) ||
321 (itemp[index] >= 62 && itemp[index] <= 126) ||
322 itemp[index] == 9 || itemp[index] == 32) {
323 *optr++ = itemp[index];
324 llen++;
325 }
326 else if (itemp[index] == '\n') {
327 /*
328 * If the last character before EOL was a space or tab,
329 * we must encode it. If llen > 74, there's no space to do
330 * that, so generate a soft line break instead.
331 */
332
333 if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32)) {
334 *(optr-1) = '=';
335 if (llen <= 74) {
336 *optr++ = HexEncodeTable[itemp[index-1] >> 4];
337 *optr++ = HexEncodeTable[itemp[index-1] & 0x0f];
338 llen += 2;
339 }
340 }
341
342 if (fwrite (otemp, 1, llen, outfile) != llen ||
343 fwrite ((char *) eolstring, 1,
344 strlen(eolstring), outfile) != strlen (eolstring)) {
345 return UURET_IOERR;
346 }
347
348 /*
349 * Fix the soft line break condition from above
350 */
351
352 if (index>0 && (itemp[index-1] == 9 || itemp[index-1] == 32) &&
353 *(optr-1) == '=') {
354 otemp[0] = '=';
355 otemp[1] = HexEncodeTable[itemp[index-1] >> 4];
356 otemp[2] = HexEncodeTable[itemp[index-1] & 0x0f];
357
358 if (fwrite (otemp, 1, 3, outfile) != 3 ||
359 fwrite ((char *) eolstring, 1,
360 strlen(eolstring), outfile) != strlen (eolstring)) {
361 return UURET_IOERR;
362 }
363 }
364
365 optr = otemp;
366 llen = 0;
367 }
368 else {
369 *optr++ = '=';
370 *optr++ = HexEncodeTable[itemp[index] >> 4];
371 *optr++ = HexEncodeTable[itemp[index] & 0x0f];
372 llen += 3;
373 }
374
375 /*
376 * Lines must be shorter than 76 characters (not counting CRLF).
377 * If the line grows longer than that, we must include a soft
378 * line break.
379 */
380
381 if (itemp[index+1] != 0 && itemp[index+1] != '\n' &&
382 (llen >= 75 ||
383 (!((itemp[index+1] >= 33 && itemp[index+1] <= 60) ||
384 (itemp[index+1] >= 62 && itemp[index+1] <= 126)) &&
385 llen >= 73))) {
386
387 *optr++ = '=';
388 llen++;
389
390 if (fwrite (otemp, 1, llen, outfile) != llen ||
391 fwrite ((char *) eolstring, 1,
392 strlen(eolstring), outfile) != strlen (eolstring)) {
393 return UURET_IOERR;
394 }
395
396 optr = otemp;
397 llen = 0;
398 }
399 }
400 }
401
402 line++;
403 }
404
405 return UURET_OK;
406 }
407
408 /*
409 * Special handling for yEnc
410 */
411
412 if (encoding == YENC_ENCODED) {
413 llen = 0;
414 optr = otemp;
415
416 while (!feof (infile) && (linperfile <= 0 || line < linperfile)) {
417 if ((count = fread (itemp, 1, 128, infile)) != 128) {
418 if (count == 0) {
419 break;
420 }
421 else if (ferror (infile)) {
422 return UURET_IOERR;
423 }
424 }
425
426 if (pcrc)
427 *pcrc = crc32(*pcrc, itemp, count);
428 if (crc)
429 *crc = crc32(*crc, itemp, count);
430
431 line++;
432
433 /*
434 * Busy Callback
435 */
436
437 if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
438 UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
439 uustring (S_ENCODE_CANCEL));
440 return UURET_CANCEL;
441 }
442
443 for (index=0; index<count; index++) {
444 if (llen > 127) {
445 if (fwrite (otemp, 1, llen, outfile) != llen ||
446 fwrite ((char *) eolstring, 1,
447 strlen(eolstring), outfile) != strlen (eolstring)) {
448 return UURET_IOERR;
449 }
450 llen = 0;
451 optr = otemp;
452 }
453
454 switch ((char) ((int) itemp[index] + 42)) {
455 case '\0':
456 case '\t':
457 case '\n':
458 case '\r':
459 case '=':
460 case '\033':
461 *optr++ = '=';
462 *optr++ = (char) ((int) itemp[index] + 42 + 64);
463 llen += 2;
464 break;
465
466 case '.':
467 if (llen == 0) {
468 *optr++ = '=';
469 *optr++ = (char) ((int) itemp[index] + 42 + 64);
470 llen += 2;
471 }
472 else {
473 *optr++ = (char) ((int) itemp[index] + 42);
474 llen++;
475 }
476 break;
477
478 default:
479 *optr++ = (char) ((int) itemp[index] + 42);
480 llen++;
481 break;
482 }
483 }
484 }
485
486 /*
487 * write last line
488 */
489
490 if (llen) {
491 if (fwrite (otemp, 1, llen, outfile) != llen ||
492 fwrite ((char *) eolstring, 1,
493 strlen(eolstring), outfile) != strlen (eolstring)) {
494 return UURET_IOERR;
495 }
496 }
497
498 return UURET_OK;
499 }
500
501 /*
502 * Handling for binary encodings
503 */
504
505 /*
506 * select charset
507 */
508
509 table = etables[encoding];
510
511 if (table==NULL || bpl[encoding]==0) {
512 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
513 uustring (S_PARM_CHECK), "UUEncodeStream()");
514 return UURET_ILLVAL;
515 }
516
517 while (!feof (infile) && (linperfile <= 0 || line < linperfile)) {
518 if ((count = fread (itemp, 1, bpl[encoding], infile)) != bpl[encoding]) {
519 if (count == 0)
520 break;
521 else if (ferror (infile))
522 return UURET_IOERR;
523 }
524
525 optr = otemp;
526 llen = 0;
527
528 /*
529 * Busy Callback
530 */
531
532 if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) {
533 UUMessage (uuencode_id, __LINE__, UUMSG_NOTE,
534 uustring (S_ENCODE_CANCEL));
535 return UURET_CANCEL;
536 }
537
538 /*
539 * for UU and XX, encode the number of bytes as first character
540 */
541
542 if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
543 *optr++ = table[count];
544 llen++;
545 }
546
547 /*
548 * Main encoding
549 */
550
551 for (index=0; index<=count-3; index+=3, llen+=4) {
552 *optr++ = table[itemp[index] >> 2];
553 *optr++ = table[((itemp[index ] & 0x03) << 4)|(itemp[index+1] >> 4)];
554 *optr++ = table[((itemp[index+1] & 0x0f) << 2)|(itemp[index+2] >> 6)];
555 *optr++ = table[ itemp[index+2] & 0x3f];
556 }
557
558 /*
559 * Special handling for incomplete lines
560 */
561
562 if (index != count) {
563 if (encoding == B64ENCODED) {
564 if (count - index == 2) {
565 *optr++ = table[itemp[index] >> 2];
566 *optr++ = table[((itemp[index ] & 0x03) << 4) |
567 ((itemp[index+1] & 0xf0) >> 4)];
568 *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
569 *optr++ = '=';
570 }
571 else if (count - index == 1) {
572 *optr++ = table[ itemp[index] >> 2];
573 *optr++ = table[(itemp[index] & 0x03) << 4];
574 *optr++ = '=';
575 *optr++ = '=';
576 }
577 llen += 4;
578 }
579 else if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
580 if (count - index == 2) {
581 *optr++ = table[itemp[index] >> 2];
582 *optr++ = table[((itemp[index ] & 0x03) << 4) |
583 ( itemp[index+1] >> 4)];
584 *optr++ = table[((itemp[index+1] & 0x0f) << 2)];
585 *optr++ = table[0];
586 }
587 else if (count - index == 1) {
588 *optr++ = table[ itemp[index] >> 2];
589 *optr++ = table[(itemp[index] & 0x03) << 4];
590 *optr++ = table[0];
591 *optr++ = table[0];
592 }
593 llen += 4;
594 }
595 }
596
597 /*
598 * end of line
599 */
600
601 tptr = eolstring;
602
603 while (*tptr)
604 *optr++ = *tptr++;
605
606 *optr++ = '\0';
607 llen += strlen ((char *) eolstring);
608
609 if (fwrite (otemp, 1, llen, outfile) != llen)
610 return UURET_IOERR;
611
612 line++;
613 }
614 return UURET_OK;
615 }
616
617 /*
618 * Encode as MIME multipart/mixed sub-message.
619 */
620
621 int UUEXPORT
622 UUEncodeMulti (FILE *outfile, FILE *infile, char *infname, int encoding,
623 char *outfname, char *mimetype, int filemode)
624 {
625 mimemap *miter=mimetable;
626 struct stat finfo;
627 int res, themode;
628 FILE *theifile;
629 char *ptr;
630 crc32_t crc;
631 crc32_t *crcptr=NULL;
632
633 if (outfile==NULL ||
634 (infile == NULL && infname==NULL) ||
635 (outfname==NULL && infname==NULL) ||
636 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
637 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
638 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
639 uustring (S_PARM_CHECK), "UUEncodeMulti()");
640 return UURET_ILLVAL;
641 }
642
643 progress.action = 0;
644
645 if (infile==NULL) {
646 if (stat (infname, &finfo) == -1) {
647 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
648 uustring (S_NOT_STAT_FILE),
649 infname, strerror (uu_errno=errno));
650 return UURET_IOERR;
651 }
652 if ((theifile = fopen (infname, "rb")) == NULL) {
653 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
654 uustring (S_NOT_OPEN_FILE),
655 infname, strerror (uu_errno=errno));
656 return UURET_IOERR;
657 }
658 themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
659 progress.fsize = (long) finfo.st_size;
660 }
661 else {
662 if (fstat (fileno (infile), &finfo) != 0) {
663 themode = (filemode)?filemode:0644;
664 progress.fsize = -1;
665 }
666 else {
667 themode = (int) finfo.st_mode & 0777;
668 progress.fsize = (long) finfo.st_size;
669 }
670 theifile = infile;
671 }
672
673 if (progress.fsize < 0)
674 progress.fsize = -1;
675
676 _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
677
678 progress.partno = 1;
679 progress.numparts = 1;
680 progress.percent = 0;
681 progress.foffset = 0;
682 progress.action = UUACT_ENCODING;
683
684 /*
685 * If not given from outside, select an appropriate Content-Type by
686 * looking at the file's extension. If it is unknown, default to
687 * Application/Octet-Stream
688 */
689
690 if (mimetype == NULL) {
691 if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.'))) {
692 while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
693 miter++;
694 mimetype = miter->mimetype;
695 }
696 }
697
698 if (mimetype == NULL && (encoding == PT_ENCODED || encoding == QP_ENCODED)) {
699 mimetype = "text/plain";
700 }
701
702 /*
703 * print sub-header
704 */
705
706 if (encoding != YENC_ENCODED) {
707 fprintf (outfile, "Content-Type: %s%s",
708 (mimetype)?mimetype:"Application/Octet-Stream",
709 eolstring);
710 fprintf (outfile, "Content-Transfer-Encoding: %s%s",
711 CTE_TYPE(encoding), eolstring);
712 fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
713 UUFNameFilter ((outfname)?outfname:infname), eolstring);
714 fprintf (outfile, "%s", eolstring);
715 }
716
717 if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
718 fprintf (outfile, "begin %o %s%s",
719 (themode) ? themode : 0644,
720 UUFNameFilter ((outfname)?outfname:infname),
721 eolstring);
722 }
723 else if (encoding == YENC_ENCODED) {
724 crc = crc32(0L, Z_NULL, 0);
725 crcptr = &crc;
726 if (progress.fsize == -1) {
727 fprintf (outfile, "=ybegin line=128 name=%s%s",
728 UUFNameFilter ((outfname)?outfname:infname),
729 eolstring);
730 }
731 else {
732 fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
733 progress.fsize,
734 UUFNameFilter ((outfname)?outfname:infname),
735 eolstring);
736 }
737 }
738
739 if ((res = UUEncodeStream (outfile, theifile, encoding, 0, crcptr, NULL)) != UURET_OK) {
740 if (res != UURET_CANCEL) {
741 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
742 uustring (S_ERR_ENCODING),
743 UUFNameFilter ((infname)?infname:outfname),
744 (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
745 }
746 progress.action = 0;
747 return res;
748 }
749
750 if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
751 fprintf (outfile, "%c%s",
752 (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
753 eolstring);
754 fprintf (outfile, "end%s", eolstring);
755 }
756 else if (encoding == YENC_ENCODED) {
757 if (progress.fsize == -1) {
758 fprintf (outfile, "=yend crc32=%08lx%s",
759 crc,
760 eolstring);
761 }
762 else {
763 fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
764 progress.fsize,
765 crc,
766 eolstring);
767 }
768 }
769
770 /*
771 * empty line at end does no harm
772 */
773
774 fprintf (outfile, "%s", eolstring);
775
776 if (infile==NULL)
777 fclose (theifile);
778
779 progress.action = 0;
780 return UURET_OK;
781 }
782
783 /*
784 * Encode as MIME message/partial
785 */
786
787 int UUEXPORT
788 UUEncodePartial (FILE *outfile, FILE *infile,
789 char *infname, int encoding,
790 char *outfname, char *mimetype,
791 int filemode, int partno, long linperfile,
792 crc32_t *crcptr)
793 {
794 mimemap *miter=mimetable;
795 static FILE *theifile;
796 int themode, numparts;
797 struct stat finfo;
798 long thesize;
799 char *ptr;
800 int res;
801 crc32_t pcrc;
802 crc32_t *pcrcptr=NULL;
803
804 if ((outfname==NULL&&infname==NULL) || partno<=0 ||
805 (infile == NULL&&infname==NULL) || outfile==NULL ||
806 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
807 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
808 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
809 uustring (S_PARM_CHECK), "UUEncodePartial()");
810 return UURET_ILLVAL;
811 }
812
813 /*
814 * The first part needs a set of headers
815 */
816
817 progress.action = 0;
818
819 if (partno == 1) {
820 if (infile==NULL) {
821 if (stat (infname, &finfo) == -1) {
822 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
823 uustring (S_NOT_STAT_FILE),
824 infname, strerror (uu_errno=errno));
825 return UURET_IOERR;
826 }
827 if ((theifile = fopen (infname, "rb")) == NULL) {
828 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
829 uustring (S_NOT_OPEN_FILE),
830 infname, strerror (uu_errno=errno));
831 return UURET_IOERR;
832 }
833 if (linperfile <= 0)
834 numparts = 1;
835 else
836 numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
837 (linperfile*bpl[encoding]));
838
839 themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777);
840 thesize = (long) finfo.st_size;
841 }
842 else {
843 if (fstat (fileno (infile), &finfo) != 0) {
844 UUMessage (uuencode_id, __LINE__, UUMSG_WARNING,
845 uustring (S_STAT_ONE_PART));
846 numparts = 1;
847 themode = (filemode)?filemode:0644;
848 thesize = -1;
849 }
850 else {
851 if (linperfile <= 0)
852 numparts = 1;
853 else
854 numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/
855 (linperfile*bpl[encoding]));
856
857 themode = (int) finfo.st_mode & 0777;
858 thesize = (long) finfo.st_size;
859 }
860 theifile = infile;
861 }
862
863 _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256);
864
865 progress.totsize = (thesize>=0) ? thesize : -1;
866 progress.partno = 1;
867 progress.numparts = numparts;
868 progress.percent = 0;
869 progress.foffset = 0;
870
871 /*
872 * If not given from outside, select an appropriate Content-Type by
873 * looking at the file's extension. If it is unknown, default to
874 * Application/Octet-Stream
875 */
876
877 if (mimetype == NULL) {
878 if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.'))) {
879 while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0)
880 miter++;
881 mimetype = miter->mimetype;
882 }
883 }
884
885 if (mimetype == NULL && (encoding==PT_ENCODED || encoding==QP_ENCODED)) {
886 mimetype = "text/plain";
887 }
888
889 /*
890 * print sub-header
891 */
892
893 if (encoding != YENC_ENCODED) {
894 fprintf (outfile, "MIME-Version: 1.0%s", eolstring);
895 fprintf (outfile, "Content-Type: %s%s",
896 (mimetype)?mimetype:"Application/Octet-Stream",
897 eolstring);
898 fprintf (outfile, "Content-Transfer-Encoding: %s%s",
899 CTE_TYPE(encoding), eolstring);
900 fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s",
901 UUFNameFilter ((outfname)?outfname:infname), eolstring);
902 }
903
904 fprintf (outfile, "%s", eolstring);
905
906 /*
907 * for the first part of UU or XX messages, print a begin line
908 */
909
910 if (encoding == UU_ENCODED || encoding == XX_ENCODED) {
911 fprintf (outfile, "begin %o %s%s",
912 (themode) ? themode : ((filemode)?filemode:0644),
913 UUFNameFilter ((outfname)?outfname:infname), eolstring);
914 }
915 }
916 if (encoding == YENC_ENCODED) {
917 pcrc = crc32(0L, Z_NULL, 0);
918 pcrcptr = &pcrc;
919 if (numparts != 1) {
920 if (progress.totsize == -1) {
921 fprintf (outfile, "=ybegin part=%d line=128 name=%s%s",
922 partno,
923 UUFNameFilter ((outfname)?outfname:infname),
924 eolstring);
925 }
926 else {
927 fprintf (outfile, "=ybegin part=%d line=128 size=%ld name=%s%s",
928 partno,
929 progress.totsize,
930 UUFNameFilter ((outfname)?outfname:infname),
931 eolstring);
932 }
933
934 fprintf (outfile, "=ypart begin=%d end=%d%s",
935 (partno-1)*linperfile*128+1,
936 (partno*linperfile*128) < progress.totsize ?
937 (partno*linperfile*128) : progress.totsize,
938 eolstring);
939 }
940 else {
941 if (progress.totsize == -1) {
942 fprintf (outfile, "=ybegin line=128 name=%s%s",
943 UUFNameFilter ((outfname)?outfname:infname),
944 eolstring);
945 }
946 else {
947 fprintf (outfile, "=ybegin line=128 size=%ld name=%s%s",
948 progress.totsize,
949 UUFNameFilter ((outfname)?outfname:infname),
950 eolstring);
951 }
952 }
953 }
954
955 /*
956 * update progress information
957 */
958
959 progress.partno = partno;
960 progress.percent = 0;
961 progress.foffset = ftell (theifile);
962
963 if (progress.totsize <= 0)
964 progress.fsize = -1;
965 else if (linperfile <= 0)
966 progress.fsize = progress.totsize;
967 else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize)
968 progress.fsize = progress.totsize - progress.foffset;
969 else
970 progress.fsize = linperfile*bpl[encoding];
971
972 progress.action = UUACT_ENCODING;
973
974 if ((res = UUEncodeStream (outfile, theifile, encoding, linperfile,
975 crcptr, pcrcptr)) != UURET_OK) {
976 if (infile==NULL) fclose (theifile);
977 if (res != UURET_CANCEL) {
978 UUMessage (uuencode_id, __LINE__, UUMSG_ERROR,
979 uustring (S_ERR_ENCODING),
980 UUFNameFilter ((outfname)?outfname:infname),
981 (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res));
982 }
983 progress.action = 0;
984 return res;
985 }
986
987 /*
988 * print end line
989 */
990
991 if (feof (theifile) &&
992 (encoding == UU_ENCODED || encoding == XX_ENCODED)) {
993 fprintf (outfile, "%c%s",
994 (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0],
995 eolstring);
996 fprintf (outfile, "end%s", eolstring);
997 }
998 else if (encoding == YENC_ENCODED) {
999 if (numparts != 1) {
1000 fprintf (outfile, "=yend size=%d part=%d pcrc32=%08lx",
1001 (partno*linperfile*128) < progress.totsize ?
1002 linperfile*128 : (progress.totsize-(partno-1)*linperfile*128),
1003 partno,
1004 pcrc);
1005 }
1006 else {
1007 fprintf (outfile, "=yend size=%d",
1008 progress.totsize);
1009 }
1010 if (feof (theifile))
1011 fprintf (outfile, " crc32=%08lx", *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 (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(0L, Z_NULL, 0);
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 crc,
1155 eolstring);
1156 }
1157 else {
1158 fprintf (outfile, "=yend size=%ld crc32=%08lx%s",
1159 progress.fsize,
1160 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; !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(0L, Z_NULL, 0);
1389 crcptr = &crc;
1390 }
1391 pcrc = crc32(0L, Z_NULL, 0);
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=%d end=%d%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 (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=%d part=%d pcrc32=%08lx",
1455 (part*linperfile*128) < progress.totsize ?
1456 linperfile*128 : (progress.totsize-(part-1)*linperfile*128),
1457 part,
1458 pcrc);
1459 }
1460 else {
1461 fprintf (outfile, "=yend size=%d",
1462 progress.totsize);
1463 }
1464 if (feof (theifile))
1465 fprintf (outfile, " crc32=%08lx", 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(0L, Z_NULL, 0);
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 (feof (theifile)) {
1787 fclose (theifile);
1788 return UURET_OK;
1789 }
1790 return UURET_CONT;
1791 }
1792
1793 return res;
1794 }