]>
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
);
374 status
= -2; /* maybe "reedit ? -2 : -1"? */
387 ? lstat (linkpath
, &st
) != NOTOK
388 && S_ISREG(st
.st_mode
)
389 && copyf (linkpath
, altpath
) == NOTOK
390 : stat (linkpath
, &st
) != NOTOK
392 && (unlink (altpath
) == NOTOK
393 || link (linkpath
, altpath
) == NOTOK
)))
394 advise (linkpath
, "unable to update %s from", altmsg
);
395 #else /* HAVE_LSTAT */
399 && stat (linkpath
, &st
) != NOTOK
401 && (unlink (altpath
) == NOTOK
402 || link (linkpath
, altpath
) == NOTOK
))
403 advise (linkpath
, "unable to update %s from", altmsg
);
404 #endif /* HAVE_LSTAT */
407 /* normally, we remember which editor we used */
409 edsave
= getcpy (*ed
);
421 copyf (char *ifile
, char *ofile
)
426 if ((in
= open (ifile
, O_RDONLY
)) == NOTOK
)
428 if ((out
= open (ofile
, O_WRONLY
| O_TRUNC
)) == NOTOK
) {
429 admonish (ofile
, "unable to open and truncate");
434 while ((i
= read (in
, buffer
, sizeof(buffer
))) > OK
)
435 if (write (out
, buffer
, i
) != i
) {
436 advise (ofile
, "may have damaged");
445 #endif /* HAVE_LSTAT */
453 sendfile (char **arg
, char *file
, int pushsw
)
457 char *cp
, *sp
, *vec
[MAXARGS
];
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
))
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)))
475 * If the sendproc is the nmh command `send', then we call
476 * those routines directly rather than exec'ing the command.
478 if (strcmp (sp
= r1bindex (sendproc
, '/'), "send") == 0) {
480 sendit (invo_name
= sp
, arg
, file
, pushsw
);
485 context_save (); /* save the context file */
488 for (i
= 0; (child_id
= vfork()) == NOTOK
&& i
< 5; i
++)
492 advise (NULL
, "unable to fork, so sending directly...");
495 vec
[vecp
++] = invo_name
;
497 vec
[vecp
++] = "-push";
500 vec
[vecp
++] = *arg
++;
504 execvp (sendproc
, vec
);
505 fprintf (stderr
, "unable to exec ");
510 if (pidwait(child_id
, OK
) == 0)
518 * Translate MIME composition file (call buildmimeproc)
522 buildfile (char **argp
, char *file
)
529 /* allocate space for arguments */
535 if ((args
= (char **) malloc((i
+ 2) * sizeof(char *))) == NULL
)
536 adios (NULL
, "unable to malloc memory");
539 * For backward compatibility, we need to add -build
540 * if we are using mhn as buildmimeproc
543 if (strcmp (r1bindex (ed
, '/'), "mhn") == 0)
544 args
[i
++] = "-build";
546 /* copy any other arguments */
547 while (argp
&& *argp
)
551 i
= editfile (&ed
, args
, file
, NOUSE
, NULL
, NULL
, NULL
, 0);
554 return (i
? NOTOK
: OK
);
559 * Check if draft is a mhbuild composition file
563 check_draft (char *msgnam
)
566 char buf
[BUFSIZ
], name
[NAMESZ
];
569 if ((fp
= fopen (msgnam
, "r")) == NULL
)
572 switch (state
= m_getfld (state
, name
, buf
, sizeof(buf
), fp
)) {
577 * If draft already contains any of the
578 * Content-XXX fields, then assume it already
581 if (uprf (name
, XXX_FIELD_PRF
)) {
585 while (state
== FLDPLUS
)
586 state
= m_getfld (state
, name
, buf
, sizeof(buf
), fp
);
593 for (bp
= buf
; *bp
; bp
++)
594 if (*bp
!= ' ' && *bp
!= '\t' && *bp
!= '\n') {
599 state
= m_getfld (state
, name
, buf
, sizeof(buf
), fp
);
600 } while (state
== BODY
);
610 static struct swit sendswitches
[] = {
612 { "alias aliasfile", 0 },
616 { "filter filterfile", 0 },
640 { "split seconds", 0 },
654 { "width columns", 0 },
655 #define SVERSIONSW 22
659 #define BITSTUFFSW 24
660 { "dashstuffing", -12 },
661 #define NBITSTUFFSW 25
662 { "nodashstuffing", -14 },
672 { "client host", -6 },
674 { "server host", -6 },
678 { "draftfolder +folder", -6 },
680 { "draftmessage msg", -6 },
682 { "nodraftfolder", -3 },
687 extern int debugsw
; /* from sendsbr.c */
695 extern char *altmsg
; /* .. */
696 extern char *annotext
;
697 extern char *distfile
;
701 sendit (char *sp
, char **arg
, char *file
, int pushed
)
704 char *cp
, buf
[BUFSIZ
], **argp
;
705 char **arguments
, *vec
[MAXARGS
];
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.
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.
735 copyip (arg
, vec
+1, MAXARGS
-1);
742 * Merge any arguments from command line (now in vec)
743 * and arguments from profile.
745 arguments
= getarguments (sp
, n
, vec
, 1);
757 vecp
= 1; /* we'll get the zero'th element later */
758 vec
[vecp
++] = "-library";
759 vec
[vecp
++] = getcpy (m_maildir (""));
761 while ((cp
= *argp
++)) {
763 switch (smatch (++cp
, sendswitches
)) {
765 ambigsw (cp
, sendswitches
);
768 advise (NULL
, "-%s unknown\n", cp
);
772 snprintf (buf
, sizeof(buf
), "%s [switches]", sp
);
773 print_help (buf
, sendswitches
, 1);
776 print_version (invo_name
);
787 if (!(cp
= *argp
++) || sscanf (cp
, "%d", &splitsw
) != 1) {
788 advise (NULL
, "missing argument to %s", argp
[-2]);
816 debugsw
++; /* fall */
842 if (!(cp
= *argp
++) || *cp
== '-') {
843 advise (NULL
, "missing argument to %s", argp
[-2]);
851 if (!(cp
= *argp
++) || *cp
== '-') {
852 advise (NULL
, "missing argument to %s", argp
[-2]);
859 advise (NULL
, "usage: %s [switches]", sp
);
863 /* allow Aliasfile: profile entry */
864 if ((cp
= context_find ("Aliasfile"))) {
868 for (ap
= brkstring (dp
, " ", "\n"); ap
&& *ap
; ap
++) {
869 vec
[vecp
++] = "-alias";
874 if ((cp
= getenv ("SIGNATURE")) == NULL
|| *cp
== 0)
875 if ((cp
= context_find ("signature")) && *cp
)
876 m_putenv ("SIGNATURE", cp
);
879 snprintf (buf
, sizeof(buf
), "%s/.signature", mypath
);
880 if ((fp
= fopen (buf
, "r")) != NULL
881 && fgets (buf
, sizeof(buf
), fp
) != NULL
) {
883 if (cp
= strchr (buf
, '\n'))
885 m_putenv ("SIGNATURE", buf
);
890 if ((annotext
= getenv ("mhannotate")) == NULL
|| *annotext
== 0)
892 if ((altmsg
= getenv ("mhaltmsg")) == NULL
|| *altmsg
== 0)
894 if (annotext
&& ((cp
= getenv ("mhinplace")) != NULL
&& *cp
!= 0))
897 if ((cp
= getenv ("mhdist"))
900 && (distsw
= atoi (cp
))
901 #endif /* not lint */
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
);
911 if (altmsg
== NULL
|| stat (altmsg
, &st
) == NOTOK
) {
916 if ((pushsw
= pushed
))
919 vec
[0] = r1bindex (postproc
, '/');
922 if (sendsbr (vec
, vecp
, file
, &st
, 1) == OK
)
931 whomfile (char **arg
, char *file
)
937 context_save (); /* save the context file */
940 switch (pid
= vfork ()) {
942 advise ("fork", "unable to");
947 vec
[vecp
++] = r1bindex (whomproc
, '/');
951 vec
[vecp
++] = *arg
++;
954 execvp (whomproc
, vec
);
955 fprintf (stderr
, "unable to exec ");
957 _exit (-1); /* NOTREACHED */
960 return (pidwait (pid
, NOTOK
) & 0377 ? 1 : 0);
966 * Remove the draft file
970 removefile (char *drft
)
972 if (unlink (drft
) == NOTOK
)
973 adios (drft
, "unable to unlink");