]>
diplodocus.org Git - nmh/blob - uip/whatnowsbr.c
3 * whatnowsbr.c -- the WhatNow shell
13 static struct swit whatnowswitches
[] = {
15 { "draftfolder +folder", 0 },
17 { "draftmessage msg", 0 },
19 { "nodraftfolder", 0 },
21 { "editor editor", 0 },
25 { "prompt string", 4 },
34 * Options at the "whatnow" prompt
36 static struct swit aleqs
[] = {
38 { "edit [<editor> <switches>]", 0 },
40 { "refile [<switches>] +folder", 0 },
42 { "mime [<switches>]", 0 },
44 { "display [<switches>]", 0 },
46 { "list [<switches>]", 0 },
48 { "send [<switches>]", 0 },
50 { "push [<switches>]", 0 },
52 { "whom [<switches>]", 0 },
54 { "quit [-delete]", 0 },
60 static char *myprompt
= "\nWhat now? ";
65 static int editfile (char **, char **, char *, int, struct msgs
*,
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 *);
75 static int copyf (char *, char *);
80 WhatNow (int argc
, char **argv
)
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
;
89 invo_name
= r1bindex (argv
[0], '/');
91 /* read user profile/context */
94 arguments
= getarguments (invo_name
, argc
, argv
, 1);
97 while ((cp
= *argp
++)) {
99 switch (smatch (++cp
, whatnowswitches
)) {
101 ambigsw (cp
, whatnowswitches
);
104 adios (NULL
, "-%s unknown", cp
);
107 snprintf (buf
, sizeof(buf
), "%s [switches] [file]", invo_name
);
108 print_help (buf
, whatnowswitches
, 1);
111 print_version(invo_name
);
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
);
124 adios (NULL
, "only one draft message at a time!");
125 if (!(dmsg
= *argp
++) || *dmsg
== '-')
126 adios (NULL
, "missing argument to %s", argp
[-2]);
134 if (!(ed
= *argp
++) || *ed
== '-')
135 adios (NULL
, "missing argument to %s", argp
[-2]);
143 if (!(myprompt
= *argp
++) || *myprompt
== '-')
144 adios (NULL
, "missing argument to %s", argp
[-2]);
149 adios (NULL
, "only one draft at a time!");
154 if ((drft
== NULL
&& (drft
= getenv ("mhdraft")) == NULL
) || *drft
== 0)
155 drft
= getcpy (m_draft (dfolder
, dmsg
, 1, &isdf
));
157 msgnam
= (cp
= getenv ("mhaltmsg")) && *cp
? getcpy (cp
) : NULL
;
159 if ((cp
= getenv ("mhuse")) && *cp
)
162 if (ed
== NULL
&& ((ed
= getenv ("mheditor")) == NULL
|| *ed
== 0)) {
167 /* start editing the draft, unless -noedit was given */
168 if (!nedit
&& editfile (&ed
, NULL
, drft
, use
, NULL
, msgnam
, NULL
, 1) < 0)
171 snprintf (prompt
, sizeof(prompt
), myprompt
, invo_name
);
173 if (!(argp
= getans (prompt
, aleqs
))) {
177 switch (smatch (*argp
, aleqs
)) {
179 /* display the message being replied to, or distributed */
181 showfile (++argp
, msgnam
);
183 advise (NULL
, "no alternate message to display");
187 /* Translate MIME composition file */
188 buildfile (++argp
, drft
);
192 /* Call an editor on the draft file */
195 if (editfile (&ed
, argp
, drft
, NOUSE
, NULL
, msgnam
, NULL
, 1) == NOTOK
)
200 /* display the draft file */
201 showfile (++argp
, drft
);
205 /* Check to whom the draft would be sent */
206 whomfile (++argp
, drft
);
210 /* Quit, and possibly delete the draft */
211 if (*++argp
&& (*argp
[0] == 'd' ||
212 ((*argp
)[0] == '-' && (*argp
)[1] == 'd'))) {
215 if (stat (drft
, &st
) != NOTOK
)
216 advise (NULL
, "draft left on %s", drft
);
221 /* Delete draft and exit */
226 /* Send draft in background */
227 if (sendfile (++argp
, drft
, 1))
233 sendfile (++argp
, drft
, 0);
237 /* Refile the draft */
238 if (refile (++argp
, drft
) == 0)
243 /* Unknown command */
244 advise (NULL
, "say what?");
255 static int reedit
= 0; /* have we been here before? */
256 static char *edsave
= NULL
; /* the editor we used previously */
260 editfile (char **ed
, char **arg
, char *file
, int use
, struct msgs
*mp
,
261 char *altmsg
, char *cwd
, int save_editor
)
263 int pid
, status
, vecp
;
264 char altpath
[BUFSIZ
], linkpath
[BUFSIZ
];
265 char *cp
, *vec
[MAXARGS
];
271 int oumask
; /* PJS: for setting permissions on symlinks. */
273 #endif /* HAVE_LSTAT */
275 /* Was there a previous edit session? */
277 if (!*ed
) { /* no explicit editor */
278 *ed
= edsave
; /* so use the previous one */
279 if ((cp
= r1bindex (*ed
, '/')) == NULL
)
282 /* unless we've specified it via "editor-next" */
283 cp
= concat (cp
, "-next", NULL
);
284 if ((cp
= context_find (cp
)) != NULL
)
288 /* set initial editor */
289 if (*ed
== NULL
&& (*ed
= context_find ("editor")) == NULL
)
294 if (mp
== NULL
|| *altmsg
== '/' || cwd
== NULL
)
295 strncpy (altpath
, altmsg
, sizeof(altpath
));
297 snprintf (altpath
, sizeof(altpath
), "%s/%s", mp
->foldpath
, altmsg
);
299 strncpy (linkpath
, LINK
, sizeof(linkpath
));
301 snprintf (linkpath
, sizeof(linkpath
), "%s/%s", cwd
, LINK
);
307 if (link (altpath
, linkpath
) == NOTOK
) {
309 /* I don't think permission on symlinks matters /JLR */
310 oumask
= umask(0044); /* PJS: else symlinks are world 'r' */
312 symlink (altpath
, linkpath
);
314 umask(oumask
); /* PJS: else symlinks are world 'r' */
320 #else /* not HAVE_LSTAT */
321 link (altpath
, linkpath
);
322 #endif /* not HAVE_LSTAT */
325 context_save (); /* save the context file */
328 switch (pid
= vfork ()) {
330 advise ("fork", "unable to");
339 m_putenv ("mhfolder", mp
->foldpath
);
340 m_putenv ("editalt", altpath
);
344 vec
[vecp
++] = r1bindex (*ed
, '/');
347 vec
[vecp
++] = *arg
++;
352 fprintf (stderr
, "unable to exec ");
357 if ((status
= pidwait (pid
, NOTOK
))) {
359 if ((cp
= r1bindex (*ed
, '/'))
360 && strcmp (cp
, "vi") == 0
361 && (status
& 0x00ff) == 0)
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
);
371 advise (NULL
, "problems with edit--%s preserved", file
);
373 status
= -2; /* maybe "reedit ? -2 : -1"? */
386 ? lstat (linkpath
, &st
) != NOTOK
387 && S_ISREG(st
.st_mode
)
388 && copyf (linkpath
, altpath
) == NOTOK
389 : stat (linkpath
, &st
) != NOTOK
391 && (unlink (altpath
) == NOTOK
392 || link (linkpath
, altpath
) == NOTOK
)))
393 advise (linkpath
, "unable to update %s from", altmsg
);
394 #else /* HAVE_LSTAT */
398 && stat (linkpath
, &st
) != NOTOK
400 && (unlink (altpath
) == NOTOK
401 || link (linkpath
, altpath
) == NOTOK
))
402 advise (linkpath
, "unable to update %s from", altmsg
);
403 #endif /* HAVE_LSTAT */
406 /* normally, we remember which editor we used */
408 edsave
= getcpy (*ed
);
420 copyf (char *ifile
, char *ofile
)
425 if ((in
= open (ifile
, O_RDONLY
)) == NOTOK
)
427 if ((out
= open (ofile
, O_WRONLY
| O_TRUNC
)) == NOTOK
) {
428 admonish (ofile
, "unable to open and truncate");
433 while ((i
= read (in
, buffer
, sizeof(buffer
))) > OK
)
434 if (write (out
, buffer
, i
) != i
) {
435 advise (ofile
, "may have damaged");
444 #endif /* HAVE_LSTAT */
452 sendfile (char **arg
, char *file
, int pushsw
)
456 char *cp
, *sp
, *vec
[MAXARGS
];
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
))
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)))
474 * If the sendproc is the nmh command `send', then we call
475 * those routines directly rather than exec'ing the command.
477 if (strcmp (sp
= r1bindex (sendproc
, '/'), "send") == 0) {
479 sendit (invo_name
= sp
, arg
, file
, pushsw
);
484 context_save (); /* save the context file */
487 for (i
= 0; (child_id
= vfork()) == NOTOK
&& i
< 5; i
++)
491 advise (NULL
, "unable to fork, so sending directly...");
494 vec
[vecp
++] = invo_name
;
496 vec
[vecp
++] = "-push";
499 vec
[vecp
++] = *arg
++;
503 execvp (sendproc
, vec
);
504 fprintf (stderr
, "unable to exec ");
509 if (pidwait(child_id
, OK
) == 0)
517 * Translate MIME composition file (call buildmimeproc)
521 buildfile (char **argp
, char *file
)
528 /* allocate space for arguments */
534 if ((args
= (char **) malloc((i
+ 2) * sizeof(char *))) == NULL
)
535 adios (NULL
, "unable to malloc memory");
538 * For backward compatibility, we need to add -build
539 * if we are using mhn as buildmimeproc
542 if (strcmp (r1bindex (ed
, '/'), "mhn") == 0)
543 args
[i
++] = "-build";
545 /* copy any other arguments */
546 while (argp
&& *argp
)
550 i
= editfile (&ed
, args
, file
, NOUSE
, NULL
, NULL
, NULL
, 0);
553 return (i
? NOTOK
: OK
);
558 * Check if draft is a mhbuild composition file
562 check_draft (char *msgnam
)
565 char buf
[BUFSIZ
], name
[NAMESZ
];
568 if ((fp
= fopen (msgnam
, "r")) == NULL
)
571 switch (state
= m_getfld (state
, name
, buf
, sizeof(buf
), fp
)) {
576 * If draft already contains any of the
577 * Content-XXX fields, then assume it already
580 if (uprf (name
, XXX_FIELD_PRF
)) {
584 while (state
== FLDPLUS
)
585 state
= m_getfld (state
, name
, buf
, sizeof(buf
), fp
);
592 for (bp
= buf
; *bp
; bp
++)
593 if (*bp
!= ' ' && *bp
!= '\t' && *bp
!= '\n') {
598 state
= m_getfld (state
, name
, buf
, sizeof(buf
), fp
);
599 } while (state
== BODY
);
609 static struct swit sendswitches
[] = {
611 { "alias aliasfile", 0 },
615 { "filter filterfile", 0 },
639 { "split seconds", 0 },
653 { "width columns", 0 },
654 #define SVERSIONSW 22
658 #define BITSTUFFSW 24
659 { "dashstuffing", -12 },
660 #define NBITSTUFFSW 25
661 { "nodashstuffing", -14 },
671 { "client host", -6 },
673 { "server host", -6 },
677 { "draftfolder +folder", -6 },
679 { "draftmessage msg", -6 },
681 { "nodraftfolder", -3 },
686 extern int debugsw
; /* from sendsbr.c */
694 extern char *altmsg
; /* .. */
695 extern char *annotext
;
696 extern char *distfile
;
700 sendit (char *sp
, char **arg
, char *file
, int pushed
)
703 char *cp
, buf
[BUFSIZ
], **argp
;
704 char **arguments
, *vec
[MAXARGS
];
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.
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.
734 copyip (arg
, vec
+1, MAXARGS
-1);
741 * Merge any arguments from command line (now in vec)
742 * and arguments from profile.
744 arguments
= getarguments (sp
, n
, vec
, 1);
756 vecp
= 1; /* we'll get the zero'th element later */
757 vec
[vecp
++] = "-library";
758 vec
[vecp
++] = getcpy (m_maildir (""));
760 while ((cp
= *argp
++)) {
762 switch (smatch (++cp
, sendswitches
)) {
764 ambigsw (cp
, sendswitches
);
767 advise (NULL
, "-%s unknown\n", cp
);
771 snprintf (buf
, sizeof(buf
), "%s [switches]", sp
);
772 print_help (buf
, sendswitches
, 1);
775 print_version (invo_name
);
786 if (!(cp
= *argp
++) || sscanf (cp
, "%d", &splitsw
) != 1) {
787 advise (NULL
, "missing argument to %s", argp
[-2]);
815 debugsw
++; /* fall */
841 if (!(cp
= *argp
++) || *cp
== '-') {
842 advise (NULL
, "missing argument to %s", argp
[-2]);
850 if (!(cp
= *argp
++) || *cp
== '-') {
851 advise (NULL
, "missing argument to %s", argp
[-2]);
858 advise (NULL
, "usage: %s [switches]", sp
);
862 /* allow Aliasfile: profile entry */
863 if ((cp
= context_find ("Aliasfile"))) {
867 for (ap
= brkstring (dp
, " ", "\n"); ap
&& *ap
; ap
++) {
868 vec
[vecp
++] = "-alias";
873 if ((cp
= getenv ("SIGNATURE")) == NULL
|| *cp
== 0)
874 if ((cp
= context_find ("signature")) && *cp
)
875 m_putenv ("SIGNATURE", cp
);
878 snprintf (buf
, sizeof(buf
), "%s/.signature", mypath
);
879 if ((fp
= fopen (buf
, "r")) != NULL
880 && fgets (buf
, sizeof(buf
), fp
) != NULL
) {
882 if (cp
= strchr (buf
, '\n'))
884 m_putenv ("SIGNATURE", buf
);
889 if ((annotext
= getenv ("mhannotate")) == NULL
|| *annotext
== 0)
891 if ((altmsg
= getenv ("mhaltmsg")) == NULL
|| *altmsg
== 0)
893 if (annotext
&& ((cp
= getenv ("mhinplace")) != NULL
&& *cp
!= 0))
896 if ((cp
= getenv ("mhdist"))
899 && (distsw
= atoi (cp
))
900 #endif /* not lint */
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
);
910 if (altmsg
== NULL
|| stat (altmsg
, &st
) == NOTOK
) {
915 if ((pushsw
= pushed
))
918 vec
[0] = r1bindex (postproc
, '/');
921 if (sendsbr (vec
, vecp
, file
, &st
, 1) == OK
)
930 whomfile (char **arg
, char *file
)
936 context_save (); /* save the context file */
939 switch (pid
= vfork ()) {
941 advise ("fork", "unable to");
946 vec
[vecp
++] = r1bindex (whomproc
, '/');
950 vec
[vecp
++] = *arg
++;
953 execvp (whomproc
, vec
);
954 fprintf (stderr
, "unable to exec ");
956 _exit (-1); /* NOTREACHED */
959 return (pidwait (pid
, NOTOK
) & 0377 ? 1 : 0);
965 * Remove the draft file
969 removefile (char *drft
)
971 if (unlink (drft
) == NOTOK
)
972 adios (drft
, "unable to unlink");