Whoever originally added the -help switch to all the commands got too cute and
[mmh] / uip / whatnowsbr.c
1
2 /*
3  * whatnowsbr.c -- the WhatNow shell
4  *
5  * $Id$
6  */
7
8 #include <h/mh.h>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <h/mime.h>
12
13 static struct swit whatnowswitches[] = {
14 #define DFOLDSW                 0
15     { "draftfolder +folder", 0 },
16 #define DMSGSW                  1
17     { "draftmessage msg", 0 },
18 #define NDFLDSW                 2
19     { "nodraftfolder", 0 },
20 #define EDITRSW                 3
21     { "editor editor", 0 },
22 #define NEDITSW                 4
23     { "noedit", 0 },
24 #define PRMPTSW                 5
25     { "prompt string", 4 },
26 #define VERSIONSW               6
27     { "version", 0 },
28 #define HELPSW                  7
29     { "help", 0 },
30     { NULL, 0 }
31 };
32
33 /*
34  * Options at the "whatnow" prompt
35  */
36 static struct swit aleqs[] = {
37 #define EDITSW                         0
38     { "edit [<editor> <switches>]", 0 },
39 #define REFILEOPT                      1
40     { "refile [<switches>] +folder", 0 },
41 #define BUILDMIMESW                    2
42     { "mime [<switches>]", 0 },
43 #define DISPSW                         3
44     { "display [<switches>]", 0 },
45 #define LISTSW                         4
46     { "list [<switches>]", 0 },
47 #define SENDSW                         5
48     { "send [<switches>]", 0 },
49 #define PUSHSW                         6
50     { "push [<switches>]", 0 },
51 #define WHOMSW                         7
52     { "whom [<switches>]", 0 },
53 #define QUITSW                         8
54     { "quit [-delete]", 0 },
55 #define DELETESW                       9
56     { "delete", 0 },
57     { NULL, 0 }
58 };
59
60 static char *myprompt = "\nWhat now? ";
61
62 /*
63  * static prototypes
64  */
65 static int editfile (char **, char **, char *, int, struct msgs *,
66         char *, char *, int);
67 static int sendfile (char **, char *, int);
68 static void sendit (char *, char **, char *, int);
69 static int buildfile (char **, char *);
70 static int check_draft (char *);
71 static int whomfile (char **, char *);
72 static int removefile (char *);
73
74 #ifdef HAVE_LSTAT
75 static int copyf (char *, char *);
76 #endif
77
78
79 int
80 WhatNow (int argc, char **argv)
81 {
82     int isdf = 0, nedit = 0, use = 0;
83     char *cp, *dfolder = NULL, *dmsg = NULL;
84     char *ed = NULL, *drft = NULL, *msgnam = NULL;
85     char buf[BUFSIZ], prompt[BUFSIZ];
86     char **argp, **arguments;
87     struct stat st;
88
89     invo_name = r1bindex (argv[0], '/');
90
91     /* read user profile/context */
92     context_read();
93
94     arguments = getarguments (invo_name, argc, argv, 1);
95     argp = arguments;
96
97     while ((cp = *argp++)) {
98         if (*cp == '-') {
99             switch (smatch (++cp, whatnowswitches)) {
100             case AMBIGSW: 
101                 ambigsw (cp, whatnowswitches);
102                 done (1);
103             case UNKWNSW: 
104                 adios (NULL, "-%s unknown", cp);
105
106             case HELPSW: 
107                 snprintf (buf, sizeof(buf), "%s [switches] [file]", invo_name);
108                 print_help (buf, whatnowswitches, 1);
109                 done (1);
110             case VERSIONSW:
111                 print_version(invo_name);
112                 done (1);
113
114             case DFOLDSW: 
115                 if (dfolder)
116                     adios (NULL, "only one draft folder at a time!");
117                 if (!(cp = *argp++) || *cp == '-')
118                     adios (NULL, "missing argument to %s", argp[-2]);
119                 dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp,
120                                 *cp != '@' ? TFOLDER : TSUBCWF);
121                 continue;
122             case DMSGSW: 
123                 if (dmsg)
124                     adios (NULL, "only one draft message at a time!");
125                 if (!(dmsg = *argp++) || *dmsg == '-')
126                     adios (NULL, "missing argument to %s", argp[-2]);
127                 continue;
128             case NDFLDSW: 
129                 dfolder = NULL;
130                 isdf = NOTOK;
131                 continue;
132
133             case EDITRSW: 
134                 if (!(ed = *argp++) || *ed == '-')
135                     adios (NULL, "missing argument to %s", argp[-2]);
136                 nedit = 0;
137                 continue;
138             case NEDITSW: 
139                 nedit++;
140                 continue;
141
142             case PRMPTSW:
143                 if (!(myprompt = *argp++) || *myprompt == '-')
144                     adios (NULL, "missing argument to %s", argp[-2]);
145                 continue;
146             }
147         }
148         if (drft)
149             adios (NULL, "only one draft at a time!");
150         else
151             drft = cp;
152     }
153
154     if ((drft == NULL && (drft = getenv ("mhdraft")) == NULL) || *drft == 0)
155         drft = getcpy (m_draft (dfolder, dmsg, 1, &isdf));
156
157     msgnam = (cp = getenv ("mhaltmsg")) && *cp ? getcpy (cp) : NULL;
158
159     if ((cp = getenv ("mhuse")) && *cp)
160         use = atoi (cp);
161
162     if (ed == NULL && ((ed = getenv ("mheditor")) == NULL || *ed == 0)) {
163         ed = NULL;
164         nedit++;
165     }
166
167     /* start editing the draft, unless -noedit was given */
168     if (!nedit && editfile (&ed, NULL, drft, use, NULL, msgnam, NULL, 1) < 0)
169         done (1);
170
171     snprintf (prompt, sizeof(prompt), myprompt, invo_name);
172     for (;;) {
173         if (!(argp = getans (prompt, aleqs))) {
174             unlink (LINK);
175             done (1);
176         }
177         switch (smatch (*argp, aleqs)) {
178         case DISPSW:
179             /* display the message being replied to, or distributed */
180             if (msgnam)
181                 showfile (++argp, msgnam);
182             else
183                 advise (NULL, "no alternate message to display");
184             break;
185
186         case BUILDMIMESW:
187             /* Translate MIME composition file */
188             buildfile (++argp, drft);
189             break;
190
191         case EDITSW:
192             /* Call an editor on the draft file */
193             if (*++argp)
194                 ed = *argp++;
195             if (editfile (&ed, argp, drft, NOUSE, NULL, msgnam, NULL, 1) == NOTOK)
196                 done (1);
197             break;
198
199         case LISTSW: 
200             /* display the draft file */
201             showfile (++argp, drft);
202             break;
203
204         case WHOMSW:
205             /* Check to whom the draft would be sent */
206             whomfile (++argp, drft);
207             break;
208
209         case QUITSW:
210             /* Quit, and possibly delete the draft */
211             if (*++argp && (*argp[0] == 'd' ||
212                 ((*argp)[0] == '-' && (*argp)[1] == 'd'))) {
213                 removefile (drft);
214             } else {
215                 if (stat (drft, &st) != NOTOK)
216                     advise (NULL, "draft left on %s", drft);
217             }
218             done (1);
219
220         case DELETESW:
221             /* Delete draft and exit */
222             removefile (drft);
223             done (1);
224
225         case PUSHSW:
226             /* Send draft in background */
227             if (sendfile (++argp, drft, 1))
228                 done (1);
229             break;
230
231         case SENDSW: 
232             /* Send draft */
233             sendfile (++argp, drft, 0);
234             break;
235
236         case REFILEOPT: 
237             /* Refile the draft */
238             if (refile (++argp, drft) == 0)
239                 done (0);
240             break;
241
242         default: 
243             /* Unknown command */
244             advise (NULL, "say what?");
245             break;
246         }
247     }
248     /*NOTREACHED*/
249 }
250
251 /*
252  * EDIT
253  */
254
255 static int  reedit = 0;         /* have we been here before?     */
256 static char *edsave = NULL;     /* the editor we used previously */
257
258
259 static int
260 editfile (char **ed, char **arg, char *file, int use, struct msgs *mp,
261           char *altmsg, char *cwd, int save_editor)
262 {
263     int pid, status, vecp;
264     char altpath[BUFSIZ], linkpath[BUFSIZ];
265     char *cp, *vec[MAXARGS];
266     struct stat st;
267
268 #ifdef HAVE_LSTAT
269     int slinked;
270 #if 0
271     int oumask; /* PJS: for setting permissions on symlinks. */
272 #endif
273 #endif /* HAVE_LSTAT */
274
275     /* Was there a previous edit session? */
276     if (reedit) {
277         if (!*ed) {             /* no explicit editor      */
278             *ed = edsave;       /* so use the previous one */
279             if ((cp = r1bindex (*ed, '/')) == NULL)
280                 cp = *ed;
281
282             /* unless we've specified it via "editor-next" */
283             cp = concat (cp, "-next", NULL);
284             if ((cp = context_find (cp)) != NULL)
285                 *ed = cp;
286         }
287     } else {
288         /* set initial editor */
289         if (*ed == NULL && (*ed = context_find ("editor")) == NULL)
290             *ed = defaulteditor;
291     }
292
293     if (altmsg) {
294         if (mp == NULL || *altmsg == '/' || cwd == NULL)
295             strncpy (altpath, altmsg, sizeof(altpath));
296         else
297             snprintf (altpath, sizeof(altpath), "%s/%s", mp->foldpath, altmsg);
298         if (cwd == NULL)
299             strncpy (linkpath, LINK, sizeof(linkpath));
300         else
301             snprintf (linkpath, sizeof(linkpath), "%s/%s", cwd, LINK);
302     }
303
304     if (altmsg) {
305         unlink (linkpath);
306 #ifdef HAVE_LSTAT
307         if (link (altpath, linkpath) == NOTOK) {
308 #if 0
309             /* I don't think permission on symlinks matters /JLR */
310             oumask = umask(0044);       /* PJS: else symlinks are world 'r' */
311 #endif
312             symlink (altpath, linkpath);
313 #if 0
314             umask(oumask);              /* PJS: else symlinks are world 'r' */
315 #endif
316             slinked = 1;
317         } else {
318             slinked = 0;
319         }
320 #else /* not HAVE_LSTAT */
321         link (altpath, linkpath);
322 #endif /* not HAVE_LSTAT */
323     }
324
325     context_save ();    /* save the context file */
326     fflush (stdout);
327
328     switch (pid = vfork ()) {
329         case NOTOK: 
330             advise ("fork", "unable to");
331             status = NOTOK;
332             break;
333
334         case OK: 
335             if (cwd)
336                 chdir (cwd);
337             if (altmsg) {
338                 if (mp)
339                     m_putenv ("mhfolder", mp->foldpath);
340                 m_putenv ("editalt", altpath);
341             }
342
343             vecp = 0;
344             vec[vecp++] = r1bindex (*ed, '/');
345             if (arg)
346                 while (*arg)
347                     vec[vecp++] = *arg++;
348             vec[vecp++] = file;
349             vec[vecp] = NULL;
350
351             execvp (*ed, vec);
352             fprintf (stderr, "unable to exec ");
353             perror (*ed);
354             _exit (-1);
355
356         default: 
357             if ((status = pidwait (pid, NOTOK))) {
358 #ifdef ATTVIBUG
359                 if ((cp = r1bindex (*ed, '/'))
360                         && strcmp (cp, "vi") == 0
361                         && (status & 0x00ff) == 0)
362                     status = 0;
363                 else {
364 #endif
365                 if (((status & 0xff00) != 0xff00)
366                     && (!reedit || (status & 0x00ff))) {
367                     if (!use && (status & 0xff00) &&
368                             (rename (file, cp = m_backup (file)) != NOTOK)) {
369                         advise (NULL, "problems with edit--draft left in %s", cp);
370                     } else {
371                         advise (NULL, "problems with edit--%s preserved", file);
372                     }
373                 }
374                 status = -2;    /* maybe "reedit ? -2 : -1"? */
375                 break;
376 #ifdef ATTVIBUG
377                 }
378 #endif
379             }
380
381             reedit++;
382 #ifdef HAVE_LSTAT
383             if (altmsg
384                     && mp
385                     && !is_readonly(mp)
386                     && (slinked
387                            ? lstat (linkpath, &st) != NOTOK
388                                 && S_ISREG(st.st_mode)
389                                 && copyf (linkpath, altpath) == NOTOK
390                            : stat (linkpath, &st) != NOTOK
391                                 && st.st_nlink == 1
392                                 && (unlink (altpath) == NOTOK
393                                         || link (linkpath, altpath) == NOTOK)))
394                 advise (linkpath, "unable to update %s from", altmsg);
395 #else /* HAVE_LSTAT */
396             if (altmsg
397                     && mp
398                     && !is_readonly(mp)
399                     && stat (linkpath, &st) != NOTOK
400                     && st.st_nlink == 1
401                     && (unlink (altpath) == NOTOK
402                         || link (linkpath, altpath) == NOTOK))
403                 advise (linkpath, "unable to update %s from", altmsg);
404 #endif /* HAVE_LSTAT */
405     }
406
407     /* normally, we remember which editor we used */
408     if (save_editor)
409         edsave = getcpy (*ed);
410
411     *ed = NULL;
412     if (altmsg)
413         unlink (linkpath);
414
415     return status;
416 }
417
418
419 #ifdef HAVE_LSTAT
420 static int
421 copyf (char *ifile, char *ofile)
422 {
423     int i, in, out;
424     char buffer[BUFSIZ];
425
426     if ((in = open (ifile, O_RDONLY)) == NOTOK)
427         return NOTOK;
428     if ((out = open (ofile, O_WRONLY | O_TRUNC)) == NOTOK) {
429         admonish (ofile, "unable to open and truncate");
430         close (in);
431         return NOTOK;
432     }
433
434     while ((i = read (in, buffer, sizeof(buffer))) > OK)
435         if (write (out, buffer, i) != i) {
436             advise (ofile, "may have damaged");
437             i = NOTOK;
438             break;
439         }
440
441     close (in);
442     close (out);
443     return i;
444 }
445 #endif /* HAVE_LSTAT */
446
447
448 /*
449  * SEND
450  */
451
452 static int
453 sendfile (char **arg, char *file, int pushsw)
454 {
455     pid_t child_id;
456     int i, vecp;
457     char *cp, *sp, *vec[MAXARGS];
458
459     /* Translate MIME composition file, if necessary */
460     if ((cp = context_find ("automimeproc"))
461             && (!strcmp (cp, "1"))
462             && !getenv ("NOMHNPROC")
463             && check_draft (file)
464             && (buildfile (NULL, file) == NOTOK))
465         return 0;
466
467     /* For backwards compatibility */
468     if ((cp = context_find ("automhnproc"))
469             && !getenv ("NOMHNPROC")
470             && check_draft (file)
471             && (i = editfile (&cp, NULL, file, NOUSE, NULL, NULL, NULL, 0)))
472         return 0;
473
474     /*
475      * If the sendproc is the nmh command `send', then we call
476      * those routines directly rather than exec'ing the command.
477      */
478     if (strcmp (sp = r1bindex (sendproc, '/'), "send") == 0) {
479         cp = invo_name;
480         sendit (invo_name = sp, arg, file, pushsw);
481         invo_name = cp;
482         return 1;
483     }
484
485     context_save ();    /* save the context file */
486     fflush (stdout);
487
488     for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++)
489         sleep (5);
490     switch (child_id) {
491         case NOTOK: 
492             advise (NULL, "unable to fork, so sending directly...");
493         case OK: 
494             vecp = 0;
495             vec[vecp++] = invo_name;
496             if (pushsw)
497                 vec[vecp++] = "-push";
498             if (arg)
499                 while (*arg)
500                     vec[vecp++] = *arg++;
501             vec[vecp++] = file;
502             vec[vecp] = NULL;
503
504             execvp (sendproc, vec);
505             fprintf (stderr, "unable to exec ");
506             perror (sendproc);
507             _exit (-1);
508
509         default: 
510             if (pidwait(child_id, OK) == 0)
511                 done (0);
512             return 1;
513     }
514 }
515
516
517 /*
518  * Translate MIME composition file (call buildmimeproc)
519  */
520
521 static int
522 buildfile (char **argp, char *file)
523 {
524     int i;
525     char **args, *ed;
526
527     ed = buildmimeproc;
528
529     /* allocate space for arguments */
530     i = 0;
531     if (argp) {
532         while (argp[i])
533             i++;
534     }
535     if ((args = (char **) malloc((i + 2) * sizeof(char *))) == NULL)
536         adios (NULL, "unable to malloc memory");
537
538     /*
539      * For backward compatibility, we need to add -build
540      * if we are using mhn as buildmimeproc
541      */
542     i = 0;
543     if (strcmp (r1bindex (ed, '/'), "mhn") == 0)
544         args[i++] = "-build";
545
546     /* copy any other arguments */
547     while (argp && *argp)
548         args[i++] = *argp++;
549     args[i] = NULL;
550
551     i = editfile (&ed, args, file, NOUSE, NULL, NULL, NULL, 0);
552     free (args);
553
554     return (i ? NOTOK : OK);
555 }
556
557
558 /*
559  *  Check if draft is a mhbuild composition file
560  */
561
562 static int
563 check_draft (char *msgnam)
564 {
565     int state;
566     char buf[BUFSIZ], name[NAMESZ];
567     FILE *fp;
568
569     if ((fp = fopen (msgnam, "r")) == NULL)
570         return 0;
571     for (state = FLD;;)
572         switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) {
573             case FLD:
574             case FLDPLUS:
575             case FLDEOF:
576                 /*
577                  * If draft already contains any of the
578                  * Content-XXX fields, then assume it already
579                  * been converted.
580                  */
581                 if (uprf (name, XXX_FIELD_PRF)) {
582                     fclose (fp);
583                     return 0;
584                 }
585                 while (state == FLDPLUS)
586                     state = m_getfld (state, name, buf, sizeof(buf), fp);
587                 break;
588
589             case BODY:
590                 do {
591                     char *bp;
592
593                     for (bp = buf; *bp; bp++)
594                         if (*bp != ' ' && *bp != '\t' && *bp != '\n') {
595                             fclose (fp);
596                             return 1;
597                         }
598
599                     state = m_getfld (state, name, buf, sizeof(buf), fp);
600                 } while (state == BODY);
601                 /* and fall... */
602
603             default:
604                 fclose (fp);
605                 return 0;
606         }
607 }
608
609
610 static struct swit  sendswitches[] = {
611 #define ALIASW            0
612     { "alias aliasfile", 0 },
613 #define DEBUGSW           1
614     { "debug", -5 },
615 #define FILTSW            2
616     { "filter filterfile", 0 },
617 #define NFILTSW           3
618     { "nofilter", 0 },
619 #define FRMTSW            4
620     { "format", 0 },
621 #define NFRMTSW           5
622     { "noformat", 0 },
623 #define FORWSW            6
624     { "forward", 0 },
625 #define NFORWSW           7
626     { "noforward", 0 },
627 #define MIMESW            8
628     { "mime", 0 },
629 #define NMIMESW           9
630     { "nomime", 0 },
631 #define MSGDSW           10
632     { "msgid", 0 },
633 #define NMSGDSW          11
634     { "nomsgid", 0 },
635 #define SPSHSW           12
636     { "push", 0 },
637 #define NSPSHSW          13
638     { "nopush", 0 },
639 #define SPLITSW          14
640     { "split seconds", 0 },
641 #define UNIQSW           15
642     { "unique", -6 },
643 #define NUNIQSW          16
644     { "nounique", -8 },
645 #define VERBSW           17
646     { "verbose", 0 },
647 #define NVERBSW          18
648     { "noverbose", 0 },
649 #define WATCSW           19
650     { "watch", 0 },
651 #define NWATCSW          20
652     { "nowatch", 0 },
653 #define WIDTHSW          21
654     { "width columns", 0 },
655 #define SVERSIONSW       22
656     { "version", 0 },
657 #define SHELPSW          23
658     { "help", 0 },
659 #define BITSTUFFSW       24
660     { "dashstuffing", -12 },
661 #define NBITSTUFFSW      25
662     { "nodashstuffing", -14 },
663 #define MAILSW           26
664     { "mail", -4 },
665 #define SAMLSW           27
666     { "saml", -4 },
667 #define SSNDSW           28
668     { "send", -4 },
669 #define SOMLSW           29
670     { "soml", -4 },
671 #define CLIESW           30
672     { "client host", -6 },
673 #define SERVSW           31
674     { "server host", -6 },
675 #define SNOOPSW          32
676     { "snoop", -5 },
677 #define SDRFSW           33
678     { "draftfolder +folder", -6 },
679 #define SDRMSW           34
680     { "draftmessage msg", -6 },
681 #define SNDRFSW          35
682     { "nodraftfolder", -3 },
683     { NULL, 0 }
684 };
685
686
687 extern int debugsw;             /* from sendsbr.c */
688 extern int forwsw;
689 extern int inplace;
690 extern int pushsw;
691 extern int splitsw;
692 extern int unique;
693 extern int verbsw;
694
695 extern char *altmsg;            /*  .. */
696 extern char *annotext;
697 extern char *distfile;
698
699
700 static void
701 sendit (char *sp, char **arg, char *file, int pushed)
702 {
703     int vecp, n = 1;
704     char *cp, buf[BUFSIZ], **argp;
705     char **arguments, *vec[MAXARGS];
706     struct stat st;
707
708 #ifndef lint
709     int distsw = 0;
710 #endif
711 #ifdef UCI
712     FILE *fp;
713 #endif
714
715     /*
716      * Make sure these are defined.  In particular, we need
717      * vec[1] to be NULL, in case "arg" is NULL below.  It
718      * doesn't matter what is the value of vec[0], but we
719      * set it to NULL, to help catch "off-by-one" errors.
720      */
721     vec[0] = NULL;
722     vec[1] = NULL;
723
724     /*
725      * Temporarily copy arg to vec, since the brkstring() call in
726      * getarguments() will wipe it out before it is merged in.
727      * Also, we skip the first element of vec, since getarguments()
728      * skips it.  Then we count the number of arguments
729      * copied.  The value of "n" will be one greater than
730      * this in order to simulate the standard argc/argv.
731      */
732     if (arg) {
733         char **bp;
734
735         copyip (arg, vec+1, MAXARGS-1);
736         bp = vec+1;
737         while (*bp++)
738             n++;
739     }
740
741     /*
742      * Merge any arguments from command line (now in vec)
743      * and arguments from profile.
744      */
745     arguments = getarguments (sp, n, vec, 1);
746     argp = arguments;
747
748     debugsw = 0;
749     forwsw = 1;
750     inplace = 1;
751     unique = 0;
752
753     altmsg = NULL;
754     annotext = NULL;
755     distfile = NULL;
756
757     vecp = 1;                   /* we'll get the zero'th element later */
758     vec[vecp++] = "-library";
759     vec[vecp++] = getcpy (m_maildir (""));
760
761     while ((cp = *argp++)) {
762         if (*cp == '-') {
763             switch (smatch (++cp, sendswitches)) {
764                 case AMBIGSW: 
765                     ambigsw (cp, sendswitches);
766                     return;
767                 case UNKWNSW: 
768                     advise (NULL, "-%s unknown\n", cp);
769                     return;
770
771                 case SHELPSW: 
772                     snprintf (buf, sizeof(buf), "%s [switches]", sp);
773                     print_help (buf, sendswitches, 1);
774                     return;
775                 case SVERSIONSW:
776                     print_version (invo_name);
777                     return;
778
779                 case SPSHSW: 
780                     pushed++;
781                     continue;
782                 case NSPSHSW: 
783                     pushed = 0;
784                     continue;
785
786                 case SPLITSW: 
787                     if (!(cp = *argp++) || sscanf (cp, "%d", &splitsw) != 1) {
788                         advise (NULL, "missing argument to %s", argp[-2]);
789                         return;
790                     }
791                     continue;
792
793                 case UNIQSW: 
794                     unique++;
795                     continue;
796                 case NUNIQSW: 
797                     unique = 0;
798                     continue;
799                 case FORWSW: 
800                     forwsw++;
801                     continue;
802                 case NFORWSW: 
803                     forwsw = 0;
804                     continue;
805
806                 case VERBSW: 
807                     verbsw++;
808                     vec[vecp++] = --cp;
809                     continue;
810                 case NVERBSW:
811                     verbsw = 0;
812                     vec[vecp++] = --cp;
813                     continue;
814
815                 case DEBUGSW: 
816                     debugsw++;  /* fall */
817                 case NFILTSW: 
818                 case FRMTSW: 
819                 case NFRMTSW: 
820                 case BITSTUFFSW:
821                 case NBITSTUFFSW:
822                 case MIMESW: 
823                 case NMIMESW: 
824                 case MSGDSW: 
825                 case NMSGDSW: 
826                 case WATCSW: 
827                 case NWATCSW: 
828                 case MAILSW: 
829                 case SAMLSW: 
830                 case SSNDSW: 
831                 case SOMLSW: 
832                 case SNOOPSW: 
833                     vec[vecp++] = --cp;
834                     continue;
835
836                 case ALIASW: 
837                 case FILTSW: 
838                 case WIDTHSW: 
839                 case CLIESW: 
840                 case SERVSW: 
841                     vec[vecp++] = --cp;
842                     if (!(cp = *argp++) || *cp == '-') {
843                         advise (NULL, "missing argument to %s", argp[-2]);
844                         return;
845                     }
846                     vec[vecp++] = cp;
847                     continue;
848
849                 case SDRFSW: 
850                 case SDRMSW: 
851                     if (!(cp = *argp++) || *cp == '-') {
852                         advise (NULL, "missing argument to %s", argp[-2]);
853                         return;
854                     }
855                 case SNDRFSW: 
856                     continue;
857             }
858         }
859         advise (NULL, "usage: %s [switches]", sp);
860         return;
861     }
862
863     /* allow Aliasfile: profile entry */
864     if ((cp = context_find ("Aliasfile"))) {
865         char **ap, *dp;
866
867         dp = getcpy (cp);
868         for (ap = brkstring (dp, " ", "\n"); ap && *ap; ap++) {
869             vec[vecp++] = "-alias";
870             vec[vecp++] = *ap;
871         }
872     }
873
874     if ((cp = getenv ("SIGNATURE")) == NULL || *cp == 0)
875         if ((cp = context_find ("signature")) && *cp)
876             m_putenv ("SIGNATURE", cp);
877 #ifdef UCI
878         else {
879             snprintf (buf, sizeof(buf), "%s/.signature", mypath);
880             if ((fp = fopen (buf, "r")) != NULL
881                 && fgets (buf, sizeof(buf), fp) != NULL) {
882                     fclose (fp);
883                     if (cp = strchr (buf, '\n'))
884                         *cp = 0;
885                     m_putenv ("SIGNATURE", buf);
886             }
887         }
888 #endif /* UCI */
889
890     if ((annotext = getenv ("mhannotate")) == NULL || *annotext == 0)
891         annotext = NULL;
892     if ((altmsg = getenv ("mhaltmsg")) == NULL || *altmsg == 0)
893         altmsg = NULL;
894     if (annotext && ((cp = getenv ("mhinplace")) != NULL && *cp != 0))
895         inplace = atoi (cp);
896
897     if ((cp = getenv ("mhdist"))
898             && *cp
899 #ifndef lint
900             && (distsw = atoi (cp))
901 #endif /* not lint */
902             && altmsg) {
903         vec[vecp++] = "-dist";
904         distfile = getcpy (m_scratch (altmsg, invo_name));
905         if (link (altmsg, distfile) == NOTOK)
906             adios (distfile, "unable to link %s to", altmsg);
907     } else {
908         distfile = NULL;
909     }
910
911     if (altmsg == NULL || stat (altmsg, &st) == NOTOK) {
912         st.st_mtime = 0;
913         st.st_dev = 0;
914         st.st_ino = 0;
915     }
916     if ((pushsw = pushed))
917         push ();
918
919     vec[0] = r1bindex (postproc, '/');
920     closefds (3);
921
922     if (sendsbr (vec, vecp, file, &st, 1) == OK)
923         done (0);
924 }
925
926 /*
927  * WHOM
928  */
929
930 static int
931 whomfile (char **arg, char *file)
932 {
933     pid_t pid;
934     int vecp;
935     char *vec[MAXARGS];
936
937     context_save ();    /* save the context file */
938     fflush (stdout);
939
940     switch (pid = vfork ()) {
941         case NOTOK: 
942             advise ("fork", "unable to");
943             return 1;
944
945         case OK: 
946             vecp = 0;
947             vec[vecp++] = r1bindex (whomproc, '/');
948             vec[vecp++] = file;
949             if (arg)
950                 while (*arg)
951                     vec[vecp++] = *arg++;
952             vec[vecp] = NULL;
953
954             execvp (whomproc, vec);
955             fprintf (stderr, "unable to exec ");
956             perror (whomproc);
957             _exit (-1);         /* NOTREACHED */
958
959         default: 
960             return (pidwait (pid, NOTOK) & 0377 ? 1 : 0);
961     }
962 }
963
964
965 /*
966  * Remove the draft file
967  */
968
969 static int
970 removefile (char *drft)
971 {
972     if (unlink (drft) == NOTOK)
973         adios (drft, "unable to unlink");
974
975     return OK;
976 }