]>
diplodocus.org Git - nmh/blob - uip/whatnowsbr.c
3 * whatnowsbr.c -- the WhatNow shell
7 * This code is Copyright (c) 2002, by the authors of nmh. See the
8 * COPYRIGHT file in the root directory of the nmh distribution for
9 * complete copyright information.
17 static struct swit whatnowswitches
[] = {
19 { "draftfolder +folder", 0 },
21 { "draftmessage msg", 0 },
23 { "nodraftfolder", 0 },
25 { "editor editor", 0 },
29 { "prompt string", 4 },
38 * Options at the "whatnow" prompt
40 static struct swit aleqs
[] = {
42 { "edit [<editor> <switches>]", 0 },
44 { "refile [<switches>] +folder", 0 },
46 { "mime [<switches>]", 0 },
48 { "display [<switches>]", 0 },
50 { "list [<switches>]", 0 },
52 { "send [<switches>]", 0 },
54 { "push [<switches>]", 0 },
56 { "whom [<switches>]", 0 },
58 { "quit [-delete]", 0 },
64 static char *myprompt
= "\nWhat now? ";
69 static int editfile (char **, char **, char *, int, struct msgs
*,
71 static int sendfile (char **, char *, int);
72 static void sendit (char *, char **, char *, int);
73 static int buildfile (char **, char *);
74 static int check_draft (char *);
75 static int whomfile (char **, char *);
76 static int removefile (char *);
79 static int copyf (char *, char *);
84 WhatNow (int argc
, char **argv
)
86 int isdf
= 0, nedit
= 0, use
= 0;
87 char *cp
, *dfolder
= NULL
, *dmsg
= NULL
;
88 char *ed
= NULL
, *drft
= NULL
, *msgnam
= NULL
;
89 char buf
[BUFSIZ
], prompt
[BUFSIZ
];
90 char **argp
, **arguments
;
93 invo_name
= r1bindex (argv
[0], '/');
95 /* read user profile/context */
98 arguments
= getarguments (invo_name
, argc
, argv
, 1);
101 while ((cp
= *argp
++)) {
103 switch (smatch (++cp
, whatnowswitches
)) {
105 ambigsw (cp
, whatnowswitches
);
108 adios (NULL
, "-%s unknown", cp
);
111 snprintf (buf
, sizeof(buf
), "%s [switches] [file]", invo_name
);
112 print_help (buf
, whatnowswitches
, 1);
115 print_version(invo_name
);
120 adios (NULL
, "only one draft folder at a time!");
121 if (!(cp
= *argp
++) || *cp
== '-')
122 adios (NULL
, "missing argument to %s", argp
[-2]);
123 dfolder
= path (*cp
== '+' || *cp
== '@' ? cp
+ 1 : cp
,
124 *cp
!= '@' ? TFOLDER
: TSUBCWF
);
128 adios (NULL
, "only one draft message at a time!");
129 if (!(dmsg
= *argp
++) || *dmsg
== '-')
130 adios (NULL
, "missing argument to %s", argp
[-2]);
138 if (!(ed
= *argp
++) || *ed
== '-')
139 adios (NULL
, "missing argument to %s", argp
[-2]);
147 if (!(myprompt
= *argp
++) || *myprompt
== '-')
148 adios (NULL
, "missing argument to %s", argp
[-2]);
153 adios (NULL
, "only one draft at a time!");
158 if ((drft
== NULL
&& (drft
= getenv ("mhdraft")) == NULL
) || *drft
== 0)
159 drft
= getcpy (m_draft (dfolder
, dmsg
, 1, &isdf
));
161 msgnam
= (cp
= getenv ("mhaltmsg")) && *cp
? getcpy (cp
) : NULL
;
163 if ((cp
= getenv ("mhuse")) && *cp
)
166 if (ed
== NULL
&& ((ed
= getenv ("mheditor")) == NULL
|| *ed
== 0)) {
171 /* start editing the draft, unless -noedit was given */
172 if (!nedit
&& editfile (&ed
, NULL
, drft
, use
, NULL
, msgnam
, NULL
, 1) < 0)
175 snprintf (prompt
, sizeof(prompt
), myprompt
, invo_name
);
177 if (!(argp
= getans (prompt
, aleqs
))) {
181 switch (smatch (*argp
, aleqs
)) {
183 /* display the message being replied to, or distributed */
185 showfile (++argp
, msgnam
);
187 advise (NULL
, "no alternate message to display");
191 /* Translate MIME composition file */
192 buildfile (++argp
, drft
);
196 /* Call an editor on the draft file */
199 if (editfile (&ed
, argp
, drft
, NOUSE
, NULL
, msgnam
, NULL
, 1) == NOTOK
)
204 /* display the draft file */
205 showfile (++argp
, drft
);
209 /* Check to whom the draft would be sent */
210 whomfile (++argp
, drft
);
214 /* Quit, and possibly delete the draft */
215 if (*++argp
&& (*argp
[0] == 'd' ||
216 ((*argp
)[0] == '-' && (*argp
)[1] == 'd'))) {
219 if (stat (drft
, &st
) != NOTOK
)
220 advise (NULL
, "draft left on %s", drft
);
225 /* Delete draft and exit */
230 /* Send draft in background */
231 if (sendfile (++argp
, drft
, 1))
237 sendfile (++argp
, drft
, 0);
241 /* Refile the draft */
242 if (refile (++argp
, drft
) == 0)
247 /* Unknown command */
248 advise (NULL
, "say what?");
259 static int reedit
= 0; /* have we been here before? */
260 static char *edsave
= NULL
; /* the editor we used previously */
264 editfile (char **ed
, char **arg
, char *file
, int use
, struct msgs
*mp
,
265 char *altmsg
, char *cwd
, int save_editor
)
267 int pid
, status
, vecp
;
268 char altpath
[BUFSIZ
], linkpath
[BUFSIZ
];
269 char *cp
, *vec
[MAXARGS
];
275 int oumask
; /* PJS: for setting permissions on symlinks. */
277 #endif /* HAVE_LSTAT */
279 /* Was there a previous edit session? */
281 if (!*ed
) { /* no explicit editor */
282 *ed
= edsave
; /* so use the previous one */
283 if ((cp
= r1bindex (*ed
, '/')) == NULL
)
286 /* unless we've specified it via "editor-next" */
287 cp
= concat (cp
, "-next", NULL
);
288 if ((cp
= context_find (cp
)) != NULL
)
292 /* set initial editor */
293 if (*ed
== NULL
&& (*ed
= context_find ("editor")) == NULL
)
298 if (mp
== NULL
|| *altmsg
== '/' || cwd
== NULL
)
299 strncpy (altpath
, altmsg
, sizeof(altpath
));
301 snprintf (altpath
, sizeof(altpath
), "%s/%s", mp
->foldpath
, altmsg
);
303 strncpy (linkpath
, LINK
, sizeof(linkpath
));
305 snprintf (linkpath
, sizeof(linkpath
), "%s/%s", cwd
, LINK
);
311 if (link (altpath
, linkpath
) == NOTOK
) {
313 /* I don't think permission on symlinks matters /JLR */
314 oumask
= umask(0044); /* PJS: else symlinks are world 'r' */
316 symlink (altpath
, linkpath
);
318 umask(oumask
); /* PJS: else symlinks are world 'r' */
324 #else /* not HAVE_LSTAT */
325 link (altpath
, linkpath
);
326 #endif /* not HAVE_LSTAT */
329 context_save (); /* save the context file */
332 switch (pid
= vfork ()) {
334 advise ("fork", "unable to");
343 m_putenv ("mhfolder", mp
->foldpath
);
344 m_putenv ("editalt", altpath
);
348 vec
[vecp
++] = r1bindex (*ed
, '/');
351 vec
[vecp
++] = *arg
++;
356 fprintf (stderr
, "unable to exec ");
361 if ((status
= pidwait (pid
, NOTOK
))) {
363 if ((cp
= r1bindex (*ed
, '/'))
364 && strcmp (cp
, "vi") == 0
365 && (status
& 0x00ff) == 0)
369 if (((status
& 0xff00) != 0xff00)
370 && (!reedit
|| (status
& 0x00ff))) {
371 if (!use
&& (status
& 0xff00) &&
372 (rename (file
, cp
= m_backup (file
)) != NOTOK
)) {
373 advise (NULL
, "problems with edit--draft left in %s", cp
);
375 advise (NULL
, "problems with edit--%s preserved", file
);
378 status
= -2; /* maybe "reedit ? -2 : -1"? */
391 ? lstat (linkpath
, &st
) != NOTOK
392 && S_ISREG(st
.st_mode
)
393 && copyf (linkpath
, altpath
) == NOTOK
394 : stat (linkpath
, &st
) != NOTOK
396 && (unlink (altpath
) == NOTOK
397 || link (linkpath
, altpath
) == NOTOK
)))
398 advise (linkpath
, "unable to update %s from", altmsg
);
399 #else /* HAVE_LSTAT */
403 && stat (linkpath
, &st
) != NOTOK
405 && (unlink (altpath
) == NOTOK
406 || link (linkpath
, altpath
) == NOTOK
))
407 advise (linkpath
, "unable to update %s from", altmsg
);
408 #endif /* HAVE_LSTAT */
411 /* normally, we remember which editor we used */
413 edsave
= getcpy (*ed
);
425 copyf (char *ifile
, char *ofile
)
430 if ((in
= open (ifile
, O_RDONLY
)) == NOTOK
)
432 if ((out
= open (ofile
, O_WRONLY
| O_TRUNC
)) == NOTOK
) {
433 admonish (ofile
, "unable to open and truncate");
438 while ((i
= read (in
, buffer
, sizeof(buffer
))) > OK
)
439 if (write (out
, buffer
, i
) != i
) {
440 advise (ofile
, "may have damaged");
449 #endif /* HAVE_LSTAT */
457 sendfile (char **arg
, char *file
, int pushsw
)
461 char *cp
, *sp
, *vec
[MAXARGS
];
463 /* Translate MIME composition file, if necessary */
464 if ((cp
= context_find ("automimeproc"))
465 && (!strcmp (cp
, "1"))
466 && !getenv ("NOMHNPROC")
467 && check_draft (file
)
468 && (buildfile (NULL
, file
) == NOTOK
))
471 /* For backwards compatibility */
472 if ((cp
= context_find ("automhnproc"))
473 && !getenv ("NOMHNPROC")
474 && check_draft (file
)
475 && (i
= editfile (&cp
, NULL
, file
, NOUSE
, NULL
, NULL
, NULL
, 0)))
479 * If the sendproc is the nmh command `send', then we call
480 * those routines directly rather than exec'ing the command.
482 if (strcmp (sp
= r1bindex (sendproc
, '/'), "send") == 0) {
484 sendit (invo_name
= sp
, arg
, file
, pushsw
);
489 context_save (); /* save the context file */
492 for (i
= 0; (child_id
= vfork()) == NOTOK
&& i
< 5; i
++)
496 advise (NULL
, "unable to fork, so sending directly...");
499 vec
[vecp
++] = invo_name
;
501 vec
[vecp
++] = "-push";
504 vec
[vecp
++] = *arg
++;
508 execvp (sendproc
, vec
);
509 fprintf (stderr
, "unable to exec ");
514 if (pidwait(child_id
, OK
) == 0)
522 * Translate MIME composition file (call buildmimeproc)
526 buildfile (char **argp
, char *file
)
533 /* allocate space for arguments */
539 if ((args
= (char **) malloc((i
+ 2) * sizeof(char *))) == NULL
)
540 adios (NULL
, "unable to malloc memory");
543 * For backward compatibility, we need to add -build
544 * if we are using mhn as buildmimeproc
547 if (strcmp (r1bindex (ed
, '/'), "mhn") == 0)
548 args
[i
++] = "-build";
550 /* copy any other arguments */
551 while (argp
&& *argp
)
555 i
= editfile (&ed
, args
, file
, NOUSE
, NULL
, NULL
, NULL
, 0);
558 return (i
? NOTOK
: OK
);
563 * Check if draft is a mhbuild composition file
567 check_draft (char *msgnam
)
570 char buf
[BUFSIZ
], name
[NAMESZ
];
573 if ((fp
= fopen (msgnam
, "r")) == NULL
)
576 switch (state
= m_getfld (state
, name
, buf
, sizeof(buf
), fp
)) {
581 * If draft already contains any of the
582 * Content-XXX fields, then assume it already
585 if (uprf (name
, XXX_FIELD_PRF
)) {
589 while (state
== FLDPLUS
)
590 state
= m_getfld (state
, name
, buf
, sizeof(buf
), fp
);
597 for (bp
= buf
; *bp
; bp
++)
598 if (*bp
!= ' ' && *bp
!= '\t' && *bp
!= '\n') {
603 state
= m_getfld (state
, name
, buf
, sizeof(buf
), fp
);
604 } while (state
== BODY
);
615 # define SASLminc(a) (a)
616 #else /* CYRUS_SASL */
617 # define SASLminc(a) 0
618 #endif /* CYRUS_SASL */
620 static struct swit sendswitches
[] = {
622 { "alias aliasfile", 0 },
626 { "filter filterfile", 0 },
650 { "split seconds", 0 },
664 { "width columns", 0 },
665 #define SVERSIONSW 22
669 #define BITSTUFFSW 24
670 { "dashstuffing", -12 },
671 #define NBITSTUFFSW 25
672 { "nodashstuffing", -14 },
682 { "client host", -6 },
684 { "server host", -6 },
688 { "draftfolder +folder", -6 },
690 { "draftmessage msg", -6 },
692 { "nodraftfolder", -3 },
694 { "sasl", SASLminc(-4) },
695 #define SASLMECHSW 37
696 { "saslmech", SASLminc(-5) },
698 { "user", SASLminc(-4) },
703 extern int debugsw
; /* from sendsbr.c */
711 extern char *altmsg
; /* .. */
712 extern char *annotext
;
713 extern char *distfile
;
717 sendit (char *sp
, char **arg
, char *file
, int pushed
)
720 char *cp
, buf
[BUFSIZ
], **argp
;
721 char **arguments
, *vec
[MAXARGS
];
732 * Make sure these are defined. In particular, we need
733 * vec[1] to be NULL, in case "arg" is NULL below. It
734 * doesn't matter what is the value of vec[0], but we
735 * set it to NULL, to help catch "off-by-one" errors.
741 * Temporarily copy arg to vec, since the brkstring() call in
742 * getarguments() will wipe it out before it is merged in.
743 * Also, we skip the first element of vec, since getarguments()
744 * skips it. Then we count the number of arguments
745 * copied. The value of "n" will be one greater than
746 * this in order to simulate the standard argc/argv.
751 copyip (arg
, vec
+1, MAXARGS
-1);
758 * Merge any arguments from command line (now in vec)
759 * and arguments from profile.
761 arguments
= getarguments (sp
, n
, vec
, 1);
773 vecp
= 1; /* we'll get the zero'th element later */
774 vec
[vecp
++] = "-library";
775 vec
[vecp
++] = getcpy (m_maildir (""));
777 while ((cp
= *argp
++)) {
779 switch (smatch (++cp
, sendswitches
)) {
781 ambigsw (cp
, sendswitches
);
784 advise (NULL
, "-%s unknown\n", cp
);
788 snprintf (buf
, sizeof(buf
), "%s [switches]", sp
);
789 print_help (buf
, sendswitches
, 1);
792 print_version (invo_name
);
803 if (!(cp
= *argp
++) || sscanf (cp
, "%d", &splitsw
) != 1) {
804 advise (NULL
, "missing argument to %s", argp
[-2]);
832 debugsw
++; /* fall */
861 if (!(cp
= *argp
++) || *cp
== '-') {
862 advise (NULL
, "missing argument to %s", argp
[-2]);
870 if (!(cp
= *argp
++) || *cp
== '-') {
871 advise (NULL
, "missing argument to %s", argp
[-2]);
878 advise (NULL
, "usage: %s [switches]", sp
);
882 /* allow Aliasfile: profile entry */
883 if ((cp
= context_find ("Aliasfile"))) {
887 for (ap
= brkstring (dp
, " ", "\n"); ap
&& *ap
; ap
++) {
888 vec
[vecp
++] = "-alias";
893 if ((cp
= getenv ("SIGNATURE")) == NULL
|| *cp
== 0)
894 if ((cp
= context_find ("signature")) && *cp
)
895 m_putenv ("SIGNATURE", cp
);
898 snprintf (buf
, sizeof(buf
), "%s/.signature", mypath
);
899 if ((fp
= fopen (buf
, "r")) != NULL
900 && fgets (buf
, sizeof(buf
), fp
) != NULL
) {
902 if (cp
= strchr (buf
, '\n'))
904 m_putenv ("SIGNATURE", buf
);
909 if ((annotext
= getenv ("mhannotate")) == NULL
|| *annotext
== 0)
911 if ((altmsg
= getenv ("mhaltmsg")) == NULL
|| *altmsg
== 0)
913 if (annotext
&& ((cp
= getenv ("mhinplace")) != NULL
&& *cp
!= 0))
916 if ((cp
= getenv ("mhdist"))
919 && (distsw
= atoi (cp
))
920 #endif /* not lint */
922 vec
[vecp
++] = "-dist";
923 distfile
= getcpy (m_scratch (altmsg
, invo_name
));
924 if (link (altmsg
, distfile
) == NOTOK
)
925 adios (distfile
, "unable to link %s to", altmsg
);
930 if (altmsg
== NULL
|| stat (altmsg
, &st
) == NOTOK
) {
935 if ((pushsw
= pushed
))
938 vec
[0] = r1bindex (postproc
, '/');
941 if (sendsbr (vec
, vecp
, file
, &st
, 1) == OK
)
950 whomfile (char **arg
, char *file
)
956 context_save (); /* save the context file */
959 switch (pid
= vfork ()) {
961 advise ("fork", "unable to");
966 vec
[vecp
++] = r1bindex (whomproc
, '/');
970 vec
[vecp
++] = *arg
++;
973 execvp (whomproc
, vec
);
974 fprintf (stderr
, "unable to exec ");
976 _exit (-1); /* NOTREACHED */
979 return (pidwait (pid
, NOTOK
) & 0377 ? 1 : 0);
985 * Remove the draft file
989 removefile (char *drft
)
991 if (unlink (drft
) == NOTOK
)
992 adios (drft
, "unable to unlink");