ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuencode.c
Revision: 1.2
Committed: Mon Jun 11 20:42:37 2001 UTC (23 years ago) by root
Content type: text/plain
Branch: MAIN
Branch point for: UUDEVIEW
Changes since 1.1: +265 -28 lines
Log Message:
*** empty log message ***

File Contents

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