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 /*
29 * Main function for standalone uuenview
30 */
31
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <ctype.h>
35 #include <stdio.h>
36 #include <time.h>
37
38 #ifdef STDC_HEADERS
39 #include <stdlib.h>
40 #include <string.h>
41 #endif
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 #ifdef HAVE_ERRNO_H
46 #include <errno.h>
47 #endif
48
49
50 #include <uudeview.h>
51 #include <fptools.h>
52 #include <uufnflt.h>
53
54
55 char * uuenview_id = "$Id: uuenview.c,v 1.22 2002/03/06 13:52:46 fp Exp $";
56
57 /*
58 * mail and news software
59 */
60
61 #ifdef PROG_INEWS
62 char * uue_inewsprog = PROG_INEWS;
63 #else
64 char * uue_inewsprog = NULL;
65 #endif
66 #ifdef PROG_MAILER
67 char * uue_mailprog = PROG_MAILER;
68 #else
69 char * uue_mailprog = NULL;
70 #endif
71 #ifdef MAILER_NEEDS_SUBJECT
72 int uue_mpsubject = 1;
73 #else
74 int uue_mpsubject = 0;
75 #endif
76
77 /*
78 * defines
79 */
80
81 #define UUE_STDOUT 0
82 #define UUE_TOFILE 1
83 #define UUE_MAILTO 2
84 #define UUE_POSTTO 3
85
86 /*
87 * the progress meter is only displayed if stderr is a terminal.
88 * take care of systems where we can't check this condition.
89 */
90
91 #ifdef HAVE_ISATTY
92 #define UUISATTY(f) (isatty(fileno(f)))
93 #else
94 #define UUISATTY(f) (1)
95 #endif
96
97 /*
98 * Message Callback
99 */
100
101 static void
MessageCallback(void * param,char * message,int level)102 MessageCallback (void *param, char *message, int level)
103 {
104 #if 0
105 if (UUGetOption (UUOPT_VERBOSE, NULL, NULL, 0) || level >= UUMSG_WARNING) {
106 fprintf (stderr, "%70s\r", "");
107 fprintf (stderr, "%s\n", message);
108 }
109 #else
110 if (level >= UUMSG_WARNING) {
111 fprintf (stderr, "%70s\r", "");
112 fprintf (stderr, "%s\n", message);
113 }
114 #endif
115 }
116
117 static int
BusyCallback(void * param,uuprogress * progress)118 BusyCallback (void *param, uuprogress *progress)
119 {
120 char stuff[26];
121 int count, pcts;
122 char *ptr;
123
124 /*
125 * Display progress meter only if stderr is a terminal
126 */
127
128 if (!UUISATTY(stderr))
129 return 0;
130
131 if ((ptr = _FP_strrchr (progress->curfile, DIRSEPARATOR[0])) == NULL)
132 ptr = progress->curfile;
133 else
134 ptr++;
135
136 if (progress->action == 4 && UUGetOption (UUOPT_VERBOSE, NULL, NULL, 0)) {
137 pcts = (int)((100*progress->partno+progress->percent-100) /
138 progress->numparts);
139 for (count=0, stuff[25]='\0'; count<25; count++)
140 stuff[count] = (count<pcts/4)?'#':'.';
141 fprintf (stderr, "encoding part %3d/%3d %s\r",
142 progress->partno, progress->numparts,
143 stuff);
144 fflush (stderr);
145 }
146 return 0;
147 }
148
149 /*
150 * usage
151 */
152
153 static void
usage(char * argv0)154 usage (char *argv0)
155 {
156 if (_FP_stristr (argv0, "uuencode") != NULL) {
157 printf ("\n\
158 uuencode -- a simple encoder (w) 1995 Frank Pilhofer\n\n\
159 usage:\n\
160 uuencode [infile] remotefile\n\n\
161 ");
162 printf ("\
163 \tinfile the local file, where to read data from. If no infile\n\
164 \t is given, or infile is a single hyphen, the standard\n\
165 \t input is used instead.\n\
166 \tremotefile the name as which the recepient will receive the file\n\
167 \n\
168 For much more powerful encoding facilities, try calling this program\n\
169 as 'uuenview'.\n\
170 \n\
171 ");
172 return;
173 }
174 printf ("\n\
175 UUENVIEW %spl%s -- a simple encoder (w) 1995 Frank Pilhofer\n\n\
176 usage:\n\
177 uuenview [-type] [options] file [...]\n\n", VERSION, PATCH);
178 printf (" Options:\n");
179 printf ("\t-b,-u,-x,-y Encode files as Base64, Uuencoding, Xx, yEnc,\n");
180 printf ("\t-t,-q Plain text or Quoted-Printable, respectively\n");
181 printf ("\t-o Encode to file(s) using the original's base name\n");
182 printf ("\t-od path Same, but write files to selected path\n");
183 #if defined(HAVE_POPEN) && defined(PROG_MAILER)
184 printf ("\t-m addr Send file(s) by mail\n");
185 #endif
186 #if defined(HAVE_POPEN) && defined(PROG_INEWS)
187 printf ("\t-p group Post file(s) to newsgroups\n");
188 #endif
189 printf ("\t-a Read message from stdin and attach files\n");
190 printf ("\t-lines Chunk into messages of lines lines each\n");
191 printf ("\n");
192 #if defined(SYSTEM_DOS) || defined(SYSTEM_QUICKWIN)
193 printf (" See Manual for more details\n\n");
194 #else
195 printf (" See uuenview(1) for more details.\n\n");
196 #endif
197 printf (" Example:\n");
198 #ifndef HAVE_POPEN
199 printf (" uuenview -b -2000 -o uuenview.exe\n");
200 printf ("\tEncodes uuenview.exe as Base64 into 2000-line chunks, and\n");
201 printf ("\twrites the result to uuenview.001 and uuenview.002.\n\n");
202 #else
203 printf (" uuenview -b -2000 -m root -o uudeview.tar.gz\n");
204 printf ("\tEncodes 'uudeview.tar.gz' as Base64 into 2000-line chunks.\n");
205 printf ("\tIt is both mailed to your system administrator and written\n");
206 printf ("\tto the files uudeview.001 and uudeview.002\n\n");
207 #endif
208
209 return;
210 }
211
212 /*
213 * -----------------------------------------------------------------------
214 * Stolen from uuscan.c to parse boundary
215 * -----------------------------------------------------------------------
216 */
217
218 /*
219 * Extract the value from a MIME attribute=value pair. This function
220 * receives a pointer to the attribute.
221 */
222 static char *
ParseValue(char * attribute)223 ParseValue (char *attribute)
224 {
225 static char uuscan_pvvalue[256];
226 char *ptr=uuscan_pvvalue;
227 int length=0;
228
229 if (attribute == NULL)
230 return NULL;
231
232 while (*attribute && *attribute != '=')
233 attribute++;
234
235 if (*attribute == '=') {
236 attribute++;
237 while (isspace (*attribute))
238 attribute++;
239 }
240 if (!*attribute)
241 return NULL;
242
243 if (*attribute == '"') {
244 /* quoted-string */
245 attribute++;
246 while (*attribute && *attribute != '"' && length < 255) {
247 if (*attribute == '\\')
248 *ptr++ = *++attribute;
249 else
250 *ptr++ = *attribute;
251 attribute++;
252 length++;
253 }
254 *ptr = '\0';
255 }
256 else {
257 /* tspecials from RFC1521 */
258
259 while (*attribute && !isspace (*attribute) &&
260 *attribute != '(' && *attribute != ')' &&
261 *attribute != '<' && *attribute != '>' &&
262 *attribute != '@' && *attribute != ',' &&
263 *attribute != ';' && *attribute != ':' &&
264 *attribute != '\\' &&*attribute != '"' &&
265 *attribute != '/' && *attribute != '[' &&
266 *attribute != ']' && *attribute != '?' &&
267 *attribute != '=' && length < 255)
268 *ptr++ = *attribute++;
269
270 *ptr = '\0';
271 }
272 return uuscan_pvvalue;
273 }
274
275 /*
276 * -----------------------------------------------------------------------
277 * Stolen from uuscan.c (end)
278 * -----------------------------------------------------------------------
279 */
280
281 /*
282 * Create command line to mail or post a file. The result is malloc()ed
283 * and must be freed manually
284 */
285
286 static char *
SendMkCommand(char ** rcptlist,char * towhom,char * subject,int isemail)287 SendMkCommand (char **rcptlist, char *towhom, char *subject, int isemail)
288 {
289 char *command, *ptr;
290 int len, count;
291
292 *rcptlist = NULL;
293
294 if (isemail && (uue_mailprog == NULL || *uue_mailprog == '\0')) {
295 fprintf (stderr, "error: Cannot Email file: option not configured\n");
296 return NULL;
297 }
298 else if (!isemail && (uue_inewsprog == NULL || *uue_inewsprog == '\0')) {
299 fprintf (stderr, "error: Cannot Post file: option not configured\n");
300 return NULL;
301 }
302
303 len = strlen ((isemail)?uue_mailprog:uue_inewsprog) +
304 ((uue_mpsubject)?strlen(subject):0) +
305 ((isemail)?strlen(towhom):0) + 32;
306
307 if ((command = (char *) malloc (len)) == NULL) {
308 fprintf (stderr, "error: Out of memory allocating %d bytes\n", len);
309 return NULL;
310 }
311
312 if ((*rcptlist = (char *) malloc (strlen (towhom) + 16)) == NULL) {
313 fprintf (stderr, "error: Out of memory allocating %d bytes\n",
314 strlen (towhom)+16);
315 _FP_free (command);
316 return NULL;
317 }
318
319 if (isemail) {
320 if (uue_mpsubject && subject!=NULL)
321 sprintf (command, "%s -s \"%s\"", uue_mailprog, subject);
322 else
323 sprintf (command, "%s", uue_mailprog);
324
325 /*
326 * Attach list of recipients to mailer command and compose another list
327 * of recipients
328 */
329
330 count = 0;
331 (*rcptlist)[0] = '\0';
332 ptr = _FP_strtok (towhom, ",; ");
333
334 while (ptr) {
335 strcat (command, " \"");
336 strcat (command, ptr);
337 strcat (command, "\"");
338
339 if (count++)
340 strcat (*rcptlist, ",");
341 strcat (*rcptlist, ptr);
342
343 ptr = _FP_strtok (NULL, ",; ");
344 }
345 }
346 else {
347 /* posting */
348 sprintf (command, "%s", uue_inewsprog);
349
350 count = 0;
351 (*rcptlist)[0] = '\0';
352 ptr = _FP_strtok (towhom, ";, ");
353
354 while (ptr) {
355 if (count++)
356 strcat (*rcptlist, ",");
357 strcat (*rcptlist, ptr);
358 ptr = _FP_strtok (NULL, ";, ");
359 }
360 }
361
362 return command;
363 }
364
365 /*
366 * Attach something. A text is read from stdin and converted into a proper
367 * MIME message. All files from the command line are then attached MIME-
368 * style. The result is mailed or posted.
369 * If towhom==NULL, the result is sent to stdout.
370 */
371
372 static int
AttachFiles(char * towhom,char * subject,char * from,char * replyto,int isemail,int encoding,int argc,char * argv[])373 AttachFiles (char *towhom, char *subject,
374 char *from, char *replyto,
375 int isemail, int encoding,
376 int argc, char *argv[])
377 {
378 static char input[1024], *ctype=NULL, *cte=NULL, boundary[64];
379 char *command=NULL, *rcptlist=NULL, *ptr;
380 FILE *thepipe;
381 int index, res;
382 /* remember the headers we care about */
383 int hadsubject=0, hadgroups=0, hadto=0, hadmime=0, hadmulti=0;
384 int hadfrom=0, hadreplyto=0;
385
386 if (towhom) {
387 #ifndef HAVE_POPEN
388 fprintf (stderr, "error: Your system does not support %s of files\n",
389 (isemail)?"mailing":"posting");
390 return UURET_ILLVAL;
391 #else
392 if ((command = SendMkCommand (&rcptlist, towhom,
393 subject, isemail)) == NULL) {
394 return UURET_ILLVAL;
395 }
396 if ((thepipe = popen (command, "w")) == NULL) {
397 fprintf (stderr, "error: could not open pipe %s\n", command);
398 _FP_free (rcptlist);
399 _FP_free (command);
400 return UURET_IOERR;
401 }
402 #endif
403 }
404 else {
405 thepipe = stdout;
406 }
407
408 /*
409 * okay, copy and scan header
410 */
411
412 index=0;
413 while (!feof (stdin)) {
414 if (_FP_fgets (input, 1024, stdin) == NULL)
415 break;
416 if (input[0] == '\0' || input[0] == '\012' || input[0] == '\015')
417 break;
418
419 /*
420 * If the first line does not appear to be a header
421 */
422
423 if (index == 0) {
424 ptr = input;
425 while (*ptr && !isspace(*ptr) && *ptr!=':')
426 ptr++;
427 if (*ptr != ':' && _FP_strnicmp (input, "From ", 5) != 0) {
428 break;
429 }
430 index++;
431 }
432
433 if (_FP_strnicmp (input, "Subject:", 8) == 0) {
434 if (subject) {
435 fprintf (thepipe, "Subject: %s\n", subject);
436 }
437 else {
438 fprintf (thepipe, "%s", input);
439 }
440 hadsubject = 1;
441 }
442 else if (_FP_strnicmp (input, "Newsgroups:", 11) == 0) {
443 if (towhom && !isemail && rcptlist) {
444 fprintf (thepipe, "Newsgroups: %s\n", rcptlist);
445 }
446 else {
447 fprintf (thepipe, "%s", input);
448 }
449 hadgroups = 1;
450 }
451 else if (_FP_strnicmp (input, "To:", 3) == 0) {
452 if (towhom && isemail && rcptlist) {
453 fprintf (thepipe, "To: %s\n", rcptlist);
454 }
455 else {
456 fprintf (thepipe, "%s", input);
457 }
458 hadto = 1;
459 }
460 else if (_FP_strnicmp (input, "From:", 5) == 0) {
461 if (from) {
462 fprintf (thepipe, "From: %s\n", from);
463 }
464 else {
465 fprintf (thepipe, "%s", input);
466 }
467 hadfrom = 1;
468 }
469 else if (_FP_strnicmp (input, "Reply-To:", 9) == 0) {
470 if (replyto) {
471 fprintf (thepipe, "Reply-To: %s\n", replyto);
472 }
473 else {
474 fprintf (thepipe, "%s", input);
475 }
476 hadreplyto = 1;
477 }
478 else if (_FP_strnicmp (input, "Mime-Version:", 13) == 0) {
479 fprintf (thepipe, "%s", input);
480 hadmime = 1;
481 }
482 else if (_FP_strnicmp (input, "Content-Type:", 13) == 0) {
483 if (_FP_stristr (input, "multipart") != NULL) {
484 /* it is already a multipart posting. grab the boundary */
485 if ((ptr = _FP_stristr (input, "boundary=")) != NULL) {
486 fprintf(thepipe, input);
487 strcpy (boundary, ParseValue (ptr));
488 hadmulti = 1;
489 }
490 }
491 else {
492 /*
493 * save content-type for later, must be only one line!
494 */
495 ctype = _FP_strdup (input);
496 }
497 }
498 else if (_FP_strnicmp (input, "Content-Transfer-Encoding:", 26) == 0) {
499 /*
500 * save for later, must be only one line
501 */
502 cte = _FP_strdup (input);
503 }
504 else {
505 /*
506 * just copy header line
507 */
508 fprintf (thepipe, "%s", input);
509 }
510 }
511
512 /*
513 * okay, header is copied. add our own fields if necessary
514 */
515
516 if (!hadmime && encoding != YENC_ENCODED)
517 fprintf (thepipe, "Mime-Version: 1.0\n");
518
519 if (!hadmulti && encoding != YENC_ENCODED) {
520 /* must invent a boundary */
521 sprintf (boundary, "==UUD_=_%ld", (long) time (NULL));
522 fprintf (thepipe, "Content-Type: multipart/mixed; boundary=\"%s\"\n",
523 boundary);
524 }
525
526 /*
527 * huh, there have been no headers.
528 */
529
530 if (!hadfrom && from) {
531 fprintf (thepipe, "From: %s\n", from);
532 }
533
534 if (!hadgroups && towhom && !isemail && rcptlist) {
535 fprintf (thepipe, "Newsgroups: %s\n", rcptlist);
536 }
537
538 if (!hadto && towhom && isemail && rcptlist) {
539 fprintf (thepipe, "To: %s\n", rcptlist);
540 }
541
542 if (!hadreplyto && replyto) {
543 fprintf (thepipe, "Reply-To: %s\n", replyto);
544 }
545
546 if (!hadsubject && subject) {
547 fprintf (thepipe, "Subject: %s\n", subject);
548 }
549
550
551 /*
552 * end headers
553 */
554
555 fprintf (thepipe, "\n");
556
557 /*
558 * okay, copy text if available
559 */
560
561 if (!feof (stdin) && index > 0) {
562 ptr = _FP_fgets (input, 1024, stdin);
563 }
564 else {
565 ptr = input;
566 }
567
568 if (!feof (stdin) && ptr) {
569 if (!hadmulti && encoding != YENC_ENCODED) {
570 /*
571 * need our own header
572 */
573 fprintf (thepipe, "--%s\n", boundary);
574 if (ctype) {
575 fprintf (thepipe, "%s", ctype);
576 }
577 else {
578 fprintf (thepipe, "Content-Type: text/plain\n");
579 }
580 if (cte) {
581 fprintf (thepipe, "%s", cte);
582 }
583 else {
584 fprintf (thepipe, "Content-Transfer-Encoding: 8bit\n");
585 }
586 fprintf (thepipe, "\n");
587
588 /*
589 * just copy stdin
590 */
591
592 fprintf (thepipe, "%s", input);
593
594 while (!feof (stdin)) {
595 if (_FP_fgets (input, 256, stdin) == NULL)
596 break;
597 fprintf (thepipe, "%s", input);
598 }
599
600 /*
601 * the last crlf is to be ignored, so add another one
602 */
603
604 fprintf (thepipe, "\n");
605 }
606 else {
607 /*
608 * this was already a multipart/mixed posting, copy everything up
609 * to the final boundary
610 */
611 while (!feof (stdin)) {
612 if (_FP_fgets (input, 256, stdin) == NULL)
613 break;
614 if (input[0] == '-' && input[1] == '-' &&
615 strncmp (input+2, boundary, strlen (boundary)) == 0 &&
616 input[strlen(boundary)+2] == '-' &&
617 input[strlen(boundary)+3] == '-')
618 break;
619 fprintf (thepipe, "%s", input);
620 }
621 }
622 }
623
624 /*
625 * okay, so let's finally make our attachments
626 */
627
628 for (index=1; index<argc; index++) {
629 if (*argv[index] == '-' && argv[index][1] != '\0') {
630 switch (argv[index][1]) {
631 case 'm': /* skip parameters of options */
632 case 'p':
633 case 's':
634 case 'i':
635 case 'f':
636 case 'r':
637 if (index+1 < argc && argv[index+1][0] != '-')
638 index++;
639 break;
640 case 'o': /* may or may have not a parameter */
641 if (argv[index][2]=='d' && index+1<argc && argv[index+1][0]!='-')
642 index++;
643 break;
644 case 'b': encoding = B64ENCODED; break;
645 case 'u': encoding = UU_ENCODED; break;
646 case 'x': encoding = XX_ENCODED; break;
647 case 't': encoding = PT_ENCODED; break;
648 case 'q': encoding = QP_ENCODED; break;
649 case 'y': encoding = YENC_ENCODED; break;
650 default: /* parameter without option */
651 break;
652 }
653 }
654 else /* this is a filename */ {
655 /*
656 * new boundary
657 */
658
659 if (encoding != YENC_ENCODED) {
660 fprintf (thepipe, "--%s\n", boundary);
661 }
662
663 if ((res = UUEncodeMulti (thepipe, NULL, argv[index], encoding,
664 NULL, NULL, 0)) != UURET_OK) {
665 fprintf (stderr, "error while attaching %s: %s %s\n",
666 argv[index], UUstrerror (res),
667 (res==UURET_IOERR)?
668 strerror (UUGetOption (UUOPT_ERRNO, NULL, NULL, 0)) : "");
669 }
670 fprintf (thepipe, "\n");
671 }
672 }
673
674 /*
675 * done.
676 */
677
678 if (encoding != YENC_ENCODED) {
679 fprintf (thepipe, "--%s--\n\n", boundary);
680 }
681
682 if (towhom) {
683 #ifdef HAVE_POPEN
684 pclose (thepipe);
685 _FP_free (rcptlist);
686 _FP_free (command);
687 #endif
688 }
689 _FP_free (ctype);
690 _FP_free (cte);
691
692 /* phew */
693 return UURET_OK;
694 }
695
696 /*
697 * Mail or Post a file. Remember to keep in sync with uutcl.c
698 */
699
700 static int
SendAFile(FILE * infile,char * infname,int encoding,int linperfile,char * outfname,char * towhom,char * subject,char * from,char * replyto,int isemail)701 SendAFile (FILE *infile, char *infname,
702 int encoding, int linperfile,
703 char *outfname, char *towhom,
704 char *subject, char *from,
705 char *replyto, int isemail)
706 {
707 char *command, *rcptlist;
708 FILE *thepipe, *theifile;
709 int res, part;
710
711 if (towhom==NULL ||
712 (outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) ||
713 (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
714 encoding!=PT_ENCODED&&encoding!=QP_ENCODED&&encoding!=YENC_ENCODED)) {
715 fprintf (stderr, "oops: Parameter check failed in SendAFile()\n");
716 return UURET_ILLVAL;
717 }
718
719 #ifndef HAVE_POPEN
720 fprintf (stderr, "error: Your system does not support %s of files\n",
721 (isemail)?"mailing":"posting");
722 return UURET_ILLVAL;
723 #else
724 if ((command = SendMkCommand (&rcptlist, towhom,
725 subject, isemail)) == NULL) {
726 return UURET_ILLVAL;
727 }
728
729 /*
730 * Get going ...
731 */
732
733 if (infile == NULL) {
734 if ((theifile = fopen (infname, "rb")) == NULL) {
735 fprintf (stderr, "error: Could not open input file %s: %s\n",
736 infname, strerror (errno));
737 _FP_free (rcptlist);
738 _FP_free (command);
739 return UURET_IOERR;
740 }
741 }
742 else {
743 theifile = infile;
744 }
745
746 for (part=1; !feof (theifile); part++) {
747 if ((thepipe = popen (command, "w")) == NULL) {
748 fprintf (stderr, "error: could not open pipe %s\n", command);
749 if (infile==NULL) fclose (theifile);
750 _FP_free (rcptlist);
751 _FP_free (command);
752 return UURET_IOERR;
753 }
754
755 #if 0
756 if (UUGetOption(UUOPT_VERBOSE, NULL, NULL, 0)) {
757 fprintf (stderr, "%s part %03d of %s to %s ... ",
758 (isemail)?"mailing":"posting",
759 part, (infname)?infname:outfname,
760 rcptlist);
761 fflush (stderr);
762 }
763 #endif
764
765 res = UUE_PrepPartialExt (thepipe, theifile, infname, encoding,
766 outfname, 0, part, linperfile, 0,
767 rcptlist, from, subject, replyto,
768 isemail);
769
770 #if 0
771 if (UUGetOption (UUOPT_VERBOSE, NULL, NULL, 0)) {
772 if (res == UURET_OK)
773 fprintf (stderr, "ok.\n");
774 else
775 fprintf (stderr, "%s\n", UUstrerror (res));
776 }
777 #endif
778
779 pclose (thepipe);
780
781 if (res != UURET_OK) {
782 if (infile == NULL) fclose (theifile);
783 _FP_free (rcptlist);
784 _FP_free (command);
785 return res;
786 }
787 }
788
789 if (infile == NULL) fclose (theifile);
790 _FP_free (rcptlist);
791 _FP_free (command);
792 return UURET_OK;
793 #endif
794 }
795
796 /*
797 * main function from uuenview
798 */
799
800 int
main(int argc,char * argv[])801 main (int argc, char *argv[])
802 {
803 int outflags[5], tostdout, linperfile, uuencode, encoding;
804 int index, subject, count, fileflag, stdinused;
805 int from, replyto;
806 char filename[512], usename[512], outdir[512];
807 int iskipflag, attach, files;
808 char *p1, *myargv[256];
809 int myargc, quote;
810 FILE *testit;
811
812 /*
813 * set defaults
814 */
815 outflags[UUE_TOFILE] = -1;
816 outflags[UUE_MAILTO] = -1;
817 outflags[UUE_POSTTO] = -1;
818 subject = -1;
819 tostdout = 1;
820 linperfile = 0;
821 uuencode = 0;
822 encoding = -1;
823 count = 0;
824 stdinused = 0;
825 attach = 0;
826 files = 0;
827 from = -1;
828 replyto = -1;
829
830 if (UUInitialize () != UURET_OK) {
831 fprintf (stderr, "oops: could not initialize decoding library\n");
832 return 2;
833 }
834
835 UUSetOption (UUOPT_VERBOSE, 0, NULL);
836
837 #if defined(SYSTEM_DOS) || defined(SYSTEM_QUICKWIN)
838 UUSetFNameFilter (NULL, UUFNameFilterDOS);
839 #else
840 UUSetFNameFilter (NULL, UUFNameFilterUnix);
841 #endif
842 /*
843 * Setup Callback
844 */
845 UUSetMsgCallback (NULL, MessageCallback);
846 UUSetBusyCallback (NULL, BusyCallback, 100);
847
848 /*
849 * OK to overwrite target files
850 */
851
852 UUSetOption (UUOPT_OVERWRITE, 1, NULL);
853
854 if (argc < 2) {
855 usage (argv[0]);
856 return 1;
857 }
858
859 /*
860 * In DOS, the default is to create files, not to send it to stdout
861 */
862
863 #ifdef SYSTEM_DOS
864 outflags[UUE_TOFILE] = -42; /* MAGIC */
865 tostdout = 0;
866 #endif
867
868 /*
869 * Check for environment variable called INEWS and override
870 * compile-time option if present
871 */
872
873 if (getenv ("INEWS") && *(char *)getenv ("INEWS")) {
874 uue_inewsprog = getenv ("INEWS");
875 }
876
877 /*
878 * Check for environment variable called UUENVIEW and read it
879 */
880
881 myargc = 1;
882 myargv[0] = argv[0];
883
884 if ((p1 = (char *) getenv ("UUENVIEW"))) {
885 myargv[myargc++] = p1;
886 quote = 0;
887
888 while (*p1 && myargc < 255) {
889 switch (*p1) {
890 case ' ':
891 case '\t':
892 if (!quote) {
893 if ((*myargv[myargc-1] == '"' || *myargv[myargc-1] == '\'') &&
894 p1-1 != myargv[myargc-1] &&
895 *(p1-1) == *myargv[myargc-1]) {
896 *(p1-1) = '\0';
897 myargv[myargc-1] += 1;
898 }
899 *p1++ = '\0';
900 while (*p1 == ' ' || *p1 == '\t')
901 p1++;
902 myargv[myargc++] = p1;
903 }
904 else {
905 p1++;
906 }
907 break;
908
909 case '"':
910 case '\'':
911 if (!quote) {
912 quote = *p1++;
913 }
914 else if (quote == *p1++) {
915 quote = 0;
916 }
917 break;
918
919 default:
920 p1++;
921 }
922 }
923 }
924
925 for (index=1; index<argc; index++) {
926 myargv[myargc++] = argv[index];
927 }
928
929 /*
930 * browse command line flags
931 */
932
933 for (index=1; index<myargc; index++) {
934 if (*myargv[index] == '-') {
935 switch (myargv[index][1]) {
936 case '\0': /* read from stdin */
937 if (attach) {
938 fprintf (stderr, "error: stdin already in use for attachment\n");
939 return 1;
940 }
941 if (stdinused) {
942 fprintf (stderr, "warning: can only use stdin once\n");
943 stdinused--;
944 }
945 stdinused++;
946 files++;
947 break;
948 case 'b': encoding = B64ENCODED; break;
949 case 'u': encoding = UU_ENCODED; break;
950 case 'x': encoding = XX_ENCODED; break;
951 case 't': encoding = PT_ENCODED; break;
952 case 'q': encoding = QP_ENCODED; break;
953 case 'y': encoding = YENC_ENCODED; break;
954 #ifdef HAVE_POPEN
955 case 'm':
956 if (index+1<myargc && myargv[index+1][0] != '-') {
957 outflags[UUE_MAILTO] = ++index;
958 tostdout = 0;
959 }
960 else
961 fprintf (stderr, "error: -m requires a parameter\n");
962 break;
963 case 'p':
964 if (index+1<myargc && myargv[index+1][0] != '-') {
965 outflags[UUE_POSTTO] = ++index;
966 tostdout = 0;
967 }
968 else
969 fprintf (stderr, "error: -p requires a parameter\n");
970 break;
971 #endif
972 case 'o':
973 if (myargv[index][2] == 'd') {
974 if (index+1<myargc && myargv[index+1][0] != '-') {
975 strcpy (outdir, myargv[++index]);
976 outflags[UUE_TOFILE] = index;
977 tostdout = 0;
978 if (strlen(outdir)>0) {
979 if (outdir[strlen(outdir)-1]!=DIRSEPARATOR[0]) {
980 strcat (outdir, DIRSEPARATOR);
981 }
982 }
983 UUSetOption (UUOPT_SAVEPATH, 0, outdir);
984 }
985 else {
986 fprintf (stderr, "error: -od requires a parameter\n");
987 }
988 }
989 else {
990 outflags[UUE_TOFILE] = index;
991 tostdout = 0;
992 }
993 break;
994 case 's':
995 if (index+1<myargc && myargv[index+1][0] != '-') {
996 subject = ++index;
997 }
998 else
999 fprintf (stderr, "error: -s requires a parameter\n");
1000 break;
1001 case 'f':
1002 if (index+1<myargc && myargv[index+1][0] != '-') {
1003 from = ++index;
1004 }
1005 else
1006 fprintf (stderr, "error: -f requires a parameter\n");
1007 break;
1008 case 'r':
1009 if (index+1<myargc && myargv[index+1][0] != '-') {
1010 replyto = ++index;
1011 }
1012 else
1013 fprintf (stderr, "error: -r requires a parameter\n");
1014 break;
1015 case 'v':
1016 UUSetOption (UUOPT_VERBOSE, 1, NULL);
1017 break;
1018 case 'a':
1019 if (linperfile) {
1020 fprintf (stderr, "error: cannot attach to splitfile\n");
1021 return 1;
1022 }
1023 attach = 1;
1024 break;
1025 case 'h':
1026 case '?':
1027 usage(myargv[0]);
1028 return 0;
1029 case 'V':
1030 fprintf (stdout, "uuenview %spl%s compiled on %s\n",
1031 VERSION, PATCH, __DATE__);
1032 return 0;
1033 default:
1034 /* should be a line count of the form -1000 or a forced line count
1035 * like --100 which disables the sanity check
1036 */
1037 if (myargv[index][1]>='0' && myargv[index][1]<='9') {
1038 if (attach) {
1039 fprintf (stderr, "error: cannot attach to splitfile\n");
1040 return 1;
1041 }
1042 linperfile = atoi (myargv[index] + 1);
1043 if (linperfile != 0 && linperfile < 200) {
1044 fprintf (stderr,
1045 "warning: lines per file must be >= 200 (ignored).\n");
1046 linperfile=0;
1047 }
1048 }
1049 else if (myargv[index][1]=='-' &&
1050 myargv[index][2]>='0' && myargv[index][2]<='9') {
1051 if (attach) {
1052 fprintf (stderr, "error: cannot attach to splitfile\n");
1053 return 1;
1054 }
1055 linperfile = atoi (myargv[index] + 2);
1056 }
1057 else if (myargv[index][1]=='-') {
1058 usage(myargv[0]);
1059 return 0;
1060 }
1061 else {
1062 fprintf (stderr, "warning: unknown option '%s' ignored.\n",
1063 myargv[index]);
1064 }
1065 }
1066 }
1067 else {
1068 files++;
1069 }
1070 }
1071
1072 if (_FP_stristr (myargv[0], "uuencode") != NULL) {
1073 uuencode = 1; /* uuencode compatibility */
1074
1075 if (encoding == -1) {
1076 encoding = UU_ENCODED;
1077 }
1078
1079 if (files == 1) {
1080 stdinused = 1;
1081 }
1082 else if (files > 2) {
1083 fprintf (stderr, "usage: %s [infile] destname\n", myargv[0]);
1084 return 0;
1085 }
1086 }
1087
1088 /*
1089 * check integrity
1090 */
1091
1092 if (linperfile != 0 && tostdout) {
1093 fprintf (stderr, "warning: cannot split file on standard output (use -o)\n");
1094 linperfile=0;
1095 }
1096
1097 if (subject>0 && tostdout && !attach) {
1098 fprintf (stderr, "warning: -s not possible on standard output\n");
1099 subject = -1;
1100 }
1101
1102 if (encoding == -1) {
1103 if (attach || outflags[UUE_POSTTO]>0 || outflags[UUE_MAILTO]>0) {
1104 encoding = B64ENCODED;
1105 }
1106 else {
1107 encoding = UU_ENCODED;
1108 }
1109 }
1110
1111 if (encoding!=UU_ENCODED && encoding!=XX_ENCODED &&
1112 encoding!=B64ENCODED && encoding!=PT_ENCODED &&
1113 encoding!=QP_ENCODED && encoding!=YENC_ENCODED) {
1114 fprintf (stderr, "warning: unknown encoding method (%d)?\n",
1115 encoding);
1116 encoding=UU_ENCODED;
1117 }
1118
1119 #ifdef SYSTEM_DOS
1120 if (tostdout==0 && outflags[UUE_TOFILE] == -1) {
1121 fprintf (stderr, "error: no output defined?\n");
1122 exit (2);
1123 }
1124 #endif
1125
1126 /*
1127 * In Attach mode, first open the pipe and copy the existing article
1128 */
1129
1130 if (attach) {
1131 if (outflags[UUE_POSTTO]==0 && outflags[UUE_MAILTO]==0 && !tostdout) {
1132 fprintf (stderr, "error: attach only possible to mail, news or stdout\n");
1133 exit (2);
1134 }
1135 if (outflags[UUE_POSTTO]>0 && outflags[UUE_MAILTO]>0) {
1136 fprintf (stderr, "warning: can attach only to one destination (sending mail only)\n");
1137 outflags[UUE_POSTTO] = 0;
1138 }
1139 if (outflags[UUE_POSTTO]>0) {
1140 AttachFiles (myargv[outflags[UUE_POSTTO]],
1141 (subject>0)?myargv[subject]:NULL,
1142 (from>0)?myargv[from]:NULL,
1143 (replyto>0)?myargv[replyto]:NULL,
1144 0, encoding, myargc, myargv);
1145 }
1146 else if (outflags[UUE_MAILTO]>0) {
1147 AttachFiles (myargv[outflags[UUE_MAILTO]],
1148 (subject>0)?myargv[subject]:NULL,
1149 (from>0)?myargv[from]:NULL,
1150 (replyto>0)?myargv[replyto]:NULL,
1151 1, encoding, myargc, myargv);
1152 }
1153 else /* tostdout */ {
1154 AttachFiles (NULL,
1155 (subject>0)?myargv[subject]:NULL,
1156 (from>0)?myargv[from]:NULL,
1157 (replyto>0)?myargv[replyto]:NULL,
1158 0, encoding, myargc, myargv);
1159 }
1160 /* finished here */
1161 count=1;
1162 goto uuenview_end;
1163 }
1164
1165 /*
1166 * okay, now process the files
1167 */
1168
1169 for (index=1, iskipflag=0; index<myargc; index+=iskipflag+1) {
1170 iskipflag = 0;
1171
1172 if (*myargv[index] == '-' && myargv[index][1] != '\0') {
1173 switch (myargv[index][1]) {
1174 case 'm': /* skip parameters of options */
1175 case 'p':
1176 case 's':
1177 case 'i':
1178 case 'f':
1179 case 'r':
1180 if (index+1 < myargc && myargv[index+1][0] != '-')
1181 index++;
1182 break;
1183 case 'o': /* may or may have not a parameter */
1184 if (myargv[index][2]=='d' && index+1<myargc && myargv[index+1][0]!='-')
1185 index++;
1186 break;
1187 case 'b': encoding = B64ENCODED; break;
1188 case 'u': encoding = UU_ENCODED; break;
1189 case 'x': encoding = XX_ENCODED; break;
1190 case 't': encoding = PT_ENCODED; break;
1191 case 'q': encoding = QP_ENCODED; break;
1192 case 'y': encoding = YENC_ENCODED; break;
1193 default: /* parameter without option */
1194 break;
1195 }
1196 }
1197 else /* this is a filename */ {
1198 if (uuencode) {
1199 /*
1200 * we're in uuencode compatibility mode. This means the actual
1201 * parameter is the file name on disk, the next parameter, if
1202 * it exists and is not an option, is the name for the encoded
1203 * file. If there is no next parameter, we shall read from stdin
1204 * and use the given name as output filename
1205 */
1206 if (index+1<myargc && myargv[index+1][0] != '-') {
1207 if (myargv[index][0] != '-' || myargv[index][1] != '\0') {
1208 strcpy (filename, myargv[index]);
1209 }
1210 else {
1211 filename[0] = '\0';
1212 stdinused--;
1213 }
1214 strcpy (usename, myargv[index+1]);
1215 iskipflag = 1; /* ignore next argument */
1216 }
1217 else {
1218 if (stdinused == 0) {
1219 /* oops, stdin already used up */
1220 continue;
1221 }
1222 stdinused--;
1223 filename[0] = '\0';
1224 strcpy (usename, myargv[index]);
1225 }
1226 }
1227 else if (myargv[index][0]=='-' && myargv[index][1]=='\0') {
1228 /*
1229 * supposed to read from stdin. we expect the next parameter to be
1230 * the name to be used
1231 */
1232 if (stdinused == 0) {
1233 /* oops, stdin already used up */
1234 continue;
1235 }
1236 stdinused--;
1237
1238 if (index+1<myargc && myargv[index+1][0] != '-') {
1239 strcpy (usename, myargv[index+1]);
1240 filename[0] = '\0';
1241 iskipflag = 1; /* ignore next argument */
1242 }
1243 else {
1244 fprintf (stderr, "error: need additional name for file from standard input\n");
1245 continue;
1246 }
1247 }
1248 else {
1249 strcpy (filename, myargv[index]);
1250 strcpy (usename, filename);
1251 }
1252
1253 if (filename[0] == '\0') {
1254 if (((outflags[UUE_POSTTO] > 0) ? 1 : 0) +
1255 ((outflags[UUE_MAILTO] > 0) ? 1 : 0) +
1256 ((outflags[UUE_TOFILE] > 0) ? 1 : 0) > 1) {
1257 fprintf (stderr, "error: can use standard input only once\n");
1258 continue;
1259 }
1260 }
1261 else if ((testit = fopen (myargv[index], "r")) == NULL) {
1262 fprintf (stderr, "error: '%s' unreadable.\n", myargv[index]);
1263 continue;
1264 }
1265 else
1266 fclose (testit);
1267
1268 fileflag = 0;
1269
1270 #ifdef HAVE_POPEN
1271 /*
1272 * post it
1273 */
1274
1275 if (outflags[UUE_POSTTO] > 0) {
1276 fileflag++;
1277 SendAFile ((filename[0])?NULL:stdin,
1278 (filename[0])?filename:NULL,
1279 encoding, linperfile, usename,
1280 myargv[outflags[UUE_POSTTO]],
1281 (subject>0)?myargv[subject]:NULL,
1282 (from>0)?myargv[from]:NULL,
1283 (replyto>0)?myargv[replyto]:NULL,
1284 0);
1285 }
1286
1287 /*
1288 * mail it separately to each recepient
1289 */
1290
1291 if (outflags[UUE_MAILTO] > 0) {
1292 fileflag++;
1293 SendAFile ((filename[0])?NULL:stdin,
1294 (filename[0])?filename:NULL,
1295 encoding, linperfile, usename,
1296 myargv[outflags[UUE_MAILTO]],
1297 (subject>0)?myargv[subject]:NULL,
1298 (from>0)?myargv[from]:NULL,
1299 (replyto>0)?myargv[replyto]:NULL,
1300 1);
1301 }
1302 #endif
1303
1304 /*
1305 * store output into a file
1306 */
1307 if (outflags[UUE_TOFILE] > 0 || outflags[UUE_TOFILE] == -42) {
1308 fileflag++;
1309 UUEncodeToFile ((filename[0])?NULL:stdin,
1310 (filename[0])?filename:NULL,
1311 encoding, usename,
1312 NULL, linperfile);
1313 }
1314
1315 /*
1316 * send it to stdout
1317 */
1318 if (tostdout) {
1319 fileflag++;
1320 UUEncodeToStream (stdout,
1321 (filename[0])?NULL:stdin,
1322 (filename[0])?filename:NULL,
1323 encoding, usename, 0);
1324 }
1325
1326 if (fileflag > 0)
1327 count++;
1328
1329 } /* end file processing */
1330 } /* end loop */
1331
1332 uuenview_end:
1333 if (UUISATTY(stderr)) {
1334 fprintf (stderr, "%70s\r", "");
1335 fflush (stderr);
1336 }
1337
1338 if (count==0) {
1339 fprintf (stderr, "error: no files.\n");
1340 }
1341
1342 UUCleanUp ();
1343
1344 return 0;
1345 }
1346
1347
1348