Initial revision
[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", 4 },
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                 status = -2;    /* maybe "reedit ? -2 : -1"? */
374                 break;
375 #ifdef ATTVIBUG
376                 }
377 #endif
378             }
379
380             reedit++;
381 #ifdef HAVE_LSTAT
382             if (altmsg
383                     && mp
384                     && !is_readonly(mp)
385                     && (slinked
386                            ? lstat (linkpath, &st) != NOTOK
387                                 && S_ISREG(st.st_mode)
388                                 && copyf (linkpath, altpath) == NOTOK
389                            : stat (linkpath, &st) != NOTOK
390                                 && st.st_nlink == 1
391                                 && (unlink (altpath) == NOTOK
392                                         || link (linkpath, altpath) == NOTOK)))
393                 advise (linkpath, "unable to update %s from", altmsg);
394 #else /* HAVE_LSTAT */
395             if (altmsg
396                     && mp
397                     && !is_readonly(mp)
398                     && stat (linkpath, &st) != NOTOK
399                     && st.st_nlink == 1
400                     && (unlink (altpath) == NOTOK
401                         || link (linkpath, altpath) == NOTOK))
402                 advise (linkpath, "unable to update %s from", altmsg);
403 #endif /* HAVE_LSTAT */
404     }
405
406     /* normally, we remember which editor we used */
407     if (save_editor)
408         edsave = getcpy (*ed);
409
410     *ed = NULL;
411     if (altmsg)
412         unlink (linkpath);
413
414     return status;
415 }
416
417
418 #ifdef HAVE_LSTAT
419 static int
420 copyf (char *ifile, char *ofile)
421 {
422     int i, in, out;
423     char buffer[BUFSIZ];
424
425     if ((in = open (ifile, O_RDONLY)) == NOTOK)
426         return NOTOK;
427     if ((out = open (ofile, O_WRONLY | O_TRUNC)) == NOTOK) {
428         admonish (ofile, "unable to open and truncate");
429         close (in);
430         return NOTOK;
431     }
432
433     while ((i = read (in, buffer, sizeof(buffer))) > OK)
434         if (write (out, buffer, i) != i) {
435             advise (ofile, "may have damaged");
436             i = NOTOK;
437             break;
438         }
439
440     close (in);
441     close (out);
442     return i;
443 }
444 #endif /* HAVE_LSTAT */
445
446
447 /*
448  * SEND
449  */
450
451 static int
452 sendfile (char **arg, char *file, int pushsw)
453 {
454     pid_t child_id;
455     int i, vecp;
456     char *cp, *sp, *vec[MAXARGS];
457
458     /* Translate MIME composition file, if necessary */
459     if ((cp = context_find ("automimeproc"))
460             && (!strcmp (cp, "1"))
461             && !getenv ("NOMHNPROC")
462             && check_draft (file)
463             && (buildfile (NULL, file) == NOTOK))
464         return 0;
465
466     /* For backwards compatibility */
467     if ((cp = context_find ("automhnproc"))
468             && !getenv ("NOMHNPROC")
469             && check_draft (file)
470             && (i = editfile (&cp, NULL, file, NOUSE, NULL, NULL, NULL, 0)))
471         return 0;
472
473     /*
474      * If the sendproc is the nmh command `send', then we call
475      * those routines directly rather than exec'ing the command.
476      */
477     if (strcmp (sp = r1bindex (sendproc, '/'), "send") == 0) {
478         cp = invo_name;
479         sendit (invo_name = sp, arg, file, pushsw);
480         invo_name = cp;
481         return 1;
482     }
483
484     context_save ();    /* save the context file */
485     fflush (stdout);
486
487     for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++)
488         sleep (5);
489     switch (child_id) {
490         case NOTOK: 
491             advise (NULL, "unable to fork, so sending directly...");
492         case OK: 
493             vecp = 0;
494             vec[vecp++] = invo_name;
495             if (pushsw)
496                 vec[vecp++] = "-push";
497             if (arg)
498                 while (*arg)
499                     vec[vecp++] = *arg++;
500             vec[vecp++] = file;
501             vec[vecp] = NULL;
502
503             execvp (sendproc, vec);
504             fprintf (stderr, "unable to exec ");
505             perror (sendproc);
506             _exit (-1);
507
508         default: 
509             if (pidwait(child_id, OK) == 0)
510                 done (0);
511             return 1;
512     }
513 }
514
515
516 /*
517  * Translate MIME composition file (call buildmimeproc)
518  */
519
520 static int
521 buildfile (char **argp, char *file)
522 {
523     int i;
524     char **args, *ed;
525
526     ed = buildmimeproc;
527
528     /* allocate space for arguments */
529     i = 0;
530     if (argp) {
531         while (argp[i])
532             i++;
533     }
534     if ((args = (char **) malloc((i + 2) * sizeof(char *))) == NULL)
535         adios (NULL, "unable to malloc memory");
536
537     /*
538      * For backward compatibility, we need to add -build
539      * if we are using mhn as buildmimeproc
540      */
541     i = 0;
542     if (strcmp (r1bindex (ed, '/'), "mhn") == 0)
543         args[i++] = "-build";
544
545     /* copy any other arguments */
546     while (argp && *argp)
547         args[i++] = *argp++;
548     args[i] = NULL;
549
550     i = editfile (&ed, args, file, NOUSE, NULL, NULL, NULL, 0);
551     free (args);
552
553     return (i ? NOTOK : OK);
554 }
555
556
557 /*
558  *  Check if draft is a mhbuild composition file
559  */
560
561 static int
562 check_draft (char *msgnam)
563 {
564     int state;
565     char buf[BUFSIZ], name[NAMESZ];
566     FILE *fp;
567
568     if ((fp = fopen (msgnam, "r")) == NULL)
569         return 0;
570     for (state = FLD;;)
571         switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) {
572             case FLD:
573             case FLDPLUS:
574             case FLDEOF:
575                 /*
576                  * If draft already contains any of the
577                  * Content-XXX fields, then assume it already
578                  * been converted.
579                  */
580                 if (uprf (name, XXX_FIELD_PRF)) {
581                     fclose (fp);
582                     return 0;
583                 }
584                 while (state == FLDPLUS)
585                     state = m_getfld (state, name, buf, sizeof(buf), fp);
586                 break;
587
588             case BODY:
589                 do {
590                     char *bp;
591
592                     for (bp = buf; *bp; bp++)
593                         if (*bp != ' ' && *bp != '\t' && *bp != '\n') {
594                             fclose (fp);
595                             return 1;
596                         }
597
598                     state = m_getfld (state, name, buf, sizeof(buf), fp);
599                 } while (state == BODY);
600                 /* and fall... */
601
602             default:
603                 fclose (fp);
604                 return 0;
605         }
606 }
607
608
609 static struct swit  sendswitches[] = {
610 #define ALIASW            0
611     { "alias aliasfile", 0 },
612 #define DEBUGSW           1
613     { "debug", -5 },
614 #define FILTSW            2
615     { "filter filterfile", 0 },
616 #define NFILTSW           3
617     { "nofilter", 0 },
618 #define FRMTSW            4
619     { "format", 0 },
620 #define NFRMTSW           5
621     { "noformat", 0 },
622 #define FORWSW            6
623     { "forward", 0 },
624 #define NFORWSW           7
625     { "noforward", 0 },
626 #define MIMESW            8
627     { "mime", 0 },
628 #define NMIMESW           9
629     { "nomime", 0 },
630 #define MSGDSW           10
631     { "msgid", 0 },
632 #define NMSGDSW          11
633     { "nomsgid", 0 },
634 #define SPSHSW           12
635     { "push", 0 },
636 #define NSPSHSW          13
637     { "nopush", 0 },
638 #define SPLITSW          14
639     { "split seconds", 0 },
640 #define UNIQSW           15
641     { "unique", -6 },
642 #define NUNIQSW          16
643     { "nounique", -8 },
644 #define VERBSW           17
645     { "verbose", 0 },
646 #define NVERBSW          18
647     { "noverbose", 0 },
648 #define WATCSW           19
649     { "watch", 0 },
650 #define NWATCSW          20
651     { "nowatch", 0 },
652 #define WIDTHSW          21
653     { "width columns", 0 },
654 #define SVERSIONSW       22
655     { "version", 0 },
656 #define SHELPSW          23
657     { "help", 4 },
658 #define BITSTUFFSW       24
659     { "dashstuffing", -12 },
660 #define NBITSTUFFSW      25
661     { "nodashstuffing", -14 },
662 #define MAILSW           26
663     { "mail", -4 },
664 #define SAMLSW           27
665     { "saml", -4 },
666 #define SSNDSW           28
667     { "send", -4 },
668 #define SOMLSW           29
669     { "soml", -4 },
670 #define CLIESW           30
671     { "client host", -6 },
672 #define SERVSW           31
673     { "server host", -6 },
674 #define SNOOPSW          32
675     { "snoop", -5 },
676 #define SDRFSW           33
677     { "draftfolder +folder", -6 },
678 #define SDRMSW           34
679     { "draftmessage msg", -6 },
680 #define SNDRFSW          35
681     { "nodraftfolder", -3 },
682     { NULL, 0 }
683 };
684
685
686 extern int debugsw;             /* from sendsbr.c */
687 extern int forwsw;
688 extern int inplace;
689 extern int pushsw;
690 extern int splitsw;
691 extern int unique;
692 extern int verbsw;
693
694 extern char *altmsg;            /*  .. */
695 extern char *annotext;
696 extern char *distfile;
697
698
699 static void
700 sendit (char *sp, char **arg, char *file, int pushed)
701 {
702     int vecp, n = 1;
703     char *cp, buf[BUFSIZ], **argp;
704     char **arguments, *vec[MAXARGS];
705     struct stat st;
706
707 #ifndef lint
708     int distsw = 0;
709 #endif
710 #ifdef UCI
711     FILE *fp;
712 #endif
713
714     /*
715      * Make sure these are defined.  In particular, we need
716      * vec[1] to be NULL, in case "arg" is NULL below.  It
717      * doesn't matter what is the value of vec[0], but we
718      * set it to NULL, to help catch "off-by-one" errors.
719      */
720     vec[0] = NULL;
721     vec[1] = NULL;
722
723     /*
724      * Temporarily copy arg to vec, since the brkstring() call in
725      * getarguments() will wipe it out before it is merged in.
726      * Also, we skip the first element of vec, since getarguments()
727      * skips it.  Then we count the number of arguments
728      * copied.  The value of "n" will be one greater than
729      * this in order to simulate the standard argc/argv.
730      */
731     if (arg) {
732         char **bp;
733
734         copyip (arg, vec+1, MAXARGS-1);
735         bp = vec+1;
736         while (*bp++)
737             n++;
738     }
739
740     /*
741      * Merge any arguments from command line (now in vec)
742      * and arguments from profile.
743      */
744     arguments = getarguments (sp, n, vec, 1);
745     argp = arguments;
746
747     debugsw = 0;
748     forwsw = 1;
749     inplace = 1;
750     unique = 0;
751
752     altmsg = NULL;
753     annotext = NULL;
754     distfile = NULL;
755
756     vecp = 1;                   /* we'll get the zero'th element later */
757     vec[vecp++] = "-library";
758     vec[vecp++] = getcpy (m_maildir (""));
759
760     while ((cp = *argp++)) {
761         if (*cp == '-') {
762             switch (smatch (++cp, sendswitches)) {
763                 case AMBIGSW: 
764                     ambigsw (cp, sendswitches);
765                     return;
766                 case UNKWNSW: 
767                     advise (NULL, "-%s unknown\n", cp);
768                     return;
769
770                 case SHELPSW: 
771                     snprintf (buf, sizeof(buf), "%s [switches]", sp);
772                     print_help (buf, sendswitches, 1);
773                     return;
774                 case SVERSIONSW:
775                     print_version (invo_name);
776                     return;
777
778                 case SPSHSW: 
779                     pushed++;
780                     continue;
781                 case NSPSHSW: 
782                     pushed = 0;
783                     continue;
784
785                 case SPLITSW: 
786                     if (!(cp = *argp++) || sscanf (cp, "%d", &splitsw) != 1) {
787                         advise (NULL, "missing argument to %s", argp[-2]);
788                         return;
789                     }
790                     continue;
791
792                 case UNIQSW: 
793                     unique++;
794                     continue;
795                 case NUNIQSW: 
796                     unique = 0;
797                     continue;
798                 case FORWSW: 
799                     forwsw++;
800                     continue;
801                 case NFORWSW: 
802                     forwsw = 0;
803                     continue;
804
805                 case VERBSW: 
806                     verbsw++;
807                     vec[vecp++] = --cp;
808                     continue;
809                 case NVERBSW:
810                     verbsw = 0;
811                     vec[vecp++] = --cp;
812                     continue;
813
814                 case DEBUGSW: 
815                     debugsw++;  /* fall */
816                 case NFILTSW: 
817                 case FRMTSW: 
818                 case NFRMTSW: 
819                 case BITSTUFFSW:
820                 case NBITSTUFFSW:
821                 case MIMESW: 
822                 case NMIMESW: 
823                 case MSGDSW: 
824                 case NMSGDSW: 
825                 case WATCSW: 
826                 case NWATCSW: 
827                 case MAILSW: 
828                 case SAMLSW: 
829                 case SSNDSW: 
830                 case SOMLSW: 
831                 case SNOOPSW: 
832                     vec[vecp++] = --cp;
833                     continue;
834
835                 case ALIASW: 
836                 case FILTSW: 
837                 case WIDTHSW: 
838                 case CLIESW: 
839                 case SERVSW: 
840                     vec[vecp++] = --cp;
841                     if (!(cp = *argp++) || *cp == '-') {
842                         advise (NULL, "missing argument to %s", argp[-2]);
843                         return;
844                     }
845                     vec[vecp++] = cp;
846                     continue;
847
848                 case SDRFSW: 
849                 case SDRMSW: 
850                     if (!(cp = *argp++) || *cp == '-') {
851                         advise (NULL, "missing argument to %s", argp[-2]);
852                         return;
853                     }
854                 case SNDRFSW: 
855                     continue;
856             }
857         }
858         advise (NULL, "usage: %s [switches]", sp);
859         return;
860     }
861
862     /* allow Aliasfile: profile entry */
863     if ((cp = context_find ("Aliasfile"))) {
864         char **ap, *dp;
865
866         dp = getcpy (cp);
867         for (ap = brkstring (dp, " ", "\n"); ap && *ap; ap++) {
868             vec[vecp++] = "-alias";
869             vec[vecp++] = *ap;
870         }
871     }
872
873     if ((cp = getenv ("SIGNATURE")) == NULL || *cp == 0)
874         if ((cp = context_find ("signature")) && *cp)
875             m_putenv ("SIGNATURE", cp);
876 #ifdef UCI
877         else {
878             snprintf (buf, sizeof(buf), "%s/.signature", mypath);
879             if ((fp = fopen (buf, "r")) != NULL
880                 && fgets (buf, sizeof(buf), fp) != NULL) {
881                     fclose (fp);
882                     if (cp = strchr (buf, '\n'))
883                         *cp = 0;
884                     m_putenv ("SIGNATURE", buf);
885             }
886         }
887 #endif /* UCI */
888
889     if ((annotext = getenv ("mhannotate")) == NULL || *annotext == 0)
890         annotext = NULL;
891     if ((altmsg = getenv ("mhaltmsg")) == NULL || *altmsg == 0)
892         altmsg = NULL;
893     if (annotext && ((cp = getenv ("mhinplace")) != NULL && *cp != 0))
894         inplace = atoi (cp);
895
896     if ((cp = getenv ("mhdist"))
897             && *cp
898 #ifndef lint
899             && (distsw = atoi (cp))
900 #endif /* not lint */
901             && altmsg) {
902         vec[vecp++] = "-dist";
903         distfile = getcpy (m_scratch (altmsg, invo_name));
904         if (link (altmsg, distfile) == NOTOK)
905             adios (distfile, "unable to link %s to", altmsg);
906     } else {
907         distfile = NULL;
908     }
909
910     if (altmsg == NULL || stat (altmsg, &st) == NOTOK) {
911         st.st_mtime = 0;
912         st.st_dev = 0;
913         st.st_ino = 0;
914     }
915     if ((pushsw = pushed))
916         push ();
917
918     vec[0] = r1bindex (postproc, '/');
919     closefds (3);
920
921     if (sendsbr (vec, vecp, file, &st, 1) == OK)
922         done (0);
923 }
924
925 /*
926  * WHOM
927  */
928
929 static int
930 whomfile (char **arg, char *file)
931 {
932     pid_t pid;
933     int vecp;
934     char *vec[MAXARGS];
935
936     context_save ();    /* save the context file */
937     fflush (stdout);
938
939     switch (pid = vfork ()) {
940         case NOTOK: 
941             advise ("fork", "unable to");
942             return 1;
943
944         case OK: 
945             vecp = 0;
946             vec[vecp++] = r1bindex (whomproc, '/');
947             vec[vecp++] = file;
948             if (arg)
949                 while (*arg)
950                     vec[vecp++] = *arg++;
951             vec[vecp] = NULL;
952
953             execvp (whomproc, vec);
954             fprintf (stderr, "unable to exec ");
955             perror (whomproc);
956             _exit (-1);         /* NOTREACHED */
957
958         default: 
959             return (pidwait (pid, NOTOK) & 0377 ? 1 : 0);
960     }
961 }
962
963
964 /*
965  * Remove the draft file
966  */
967
968 static int
969 removefile (char *drft)
970 {
971     if (unlink (drft) == NOTOK)
972         adios (drft, "unable to unlink");
973
974     return OK;
975 }