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