2 * forw.c -- forward a message, or group of messages.
4 * This code is Copyright (c) 2002, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
11 #include <h/fmt_scan.h>
16 #define IFORMAT "digest-issue-%s"
17 #define VFORMAT "digest-volume-%s"
19 static struct swit switches[] = {
25 { "draftfolder +folder", 0 },
27 { "draftmessage msg", 0 },
29 { "nodraftfolder", 0 },
31 { "editor editor", 0 },
35 { "filter filterfile", 0 },
37 { "form formfile", 0 },
53 { "issue number", 0 },
55 { "volume number", 0 },
57 { "whatnowproc program", 0 },
59 { "nowhatnowproc", 0 },
61 { "dashstuffing", 0 }, /* interface to mhl */
62 #define NBITSTUFFSW 21
63 { "nodashstuffing", 0 },
69 { "file file", 4 }, /* interface from msh */
73 { "build", 5 }, /* interface from mhe */
79 static struct swit aqrnl[] = {
87 { "refile +folder", 0 },
93 static struct swit aqrl[] = {
97 { "refile +folder", 0 },
101 static char drft[BUFSIZ];
103 static char delim3[] =
104 "\n------------------------------------------------------------\n\n";
105 static char delim4[] = "\n------------------------------\n\n";
108 static struct msgs *mp = NULL; /* used a lot */
114 static void mhl_draft (int, char *, int, int, char *, char *, int);
115 static void copy_draft (int, char *, char *, int, int, int);
116 static void copy_mime_draft (int);
117 static int build_form (char *, char *, int, int);
121 main (int argc, char **argv)
123 int msgp = 0, anot = 0, inplace = 1, mime = 0;
124 int issue = 0, volume = 0, dashstuff = 0;
125 int nedit = 0, nwhat = 0, i, in;
126 int out, isdf = 0, msgnum;
127 char *cp, *cwd, *maildir, *dfolder = NULL;
128 char *dmsg = NULL, *digest = NULL, *ed = NULL;
129 char *file = NULL, *filter = NULL, *folder = NULL;
130 char *form = NULL, buf[BUFSIZ], value[10];
131 char **argp, **arguments, *msgs[MAXARGS];
139 setlocale(LC_ALL, "");
141 invo_name = r1bindex (argv[0], '/');
143 /* read user profile/context */
146 arguments = getarguments (invo_name, argc, argv, 1);
149 while ((cp = *argp++)) {
151 switch (smatch (++cp, switches)) {
153 ambigsw (cp, switches);
156 adios (NULL, "-%s unknown", cp);
159 snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]",
161 print_help (buf, switches, 1);
164 print_version(invo_name);
175 if (!(ed = *argp++) || *ed == '-')
176 adios (NULL, "missing argument to %s", argp[-2]);
184 if (!(whatnowproc = *argp++) || *whatnowproc == '-')
185 adios (NULL, "missing argument to %s", argp[-2]);
190 buildsw++; /* fall... */
198 adios (NULL, "only one file at a time!");
199 if (!(cp = *argp++) || *cp == '-')
200 adios (NULL, "missing argument to %s", argp[-2]);
201 file = path (cp, TFILE);
204 if (!(cp = *argp++) || *cp == '-')
205 adios (NULL, "missing argument to %s", argp[-2]);
206 filter = getcpy (etcpath (cp));
210 if (!(form = *argp++) || *form == '-')
211 adios (NULL, "missing argument to %s", argp[-2]);
215 filter = getcpy (etcpath (mhlforward));
237 if (!(digest = *argp++) || *digest == '-')
238 adios (NULL, "missing argument to %s", argp[-2]);
242 if (!(cp = *argp++) || *cp == '-')
243 adios (NULL, "missing argument to %s", argp[-2]);
244 if ((issue = atoi (cp)) < 1)
245 adios (NULL, "bad argument %s %s", argp[-2], cp);
248 if (!(cp = *argp++) || *cp == '-')
249 adios (NULL, "missing argument to %s", argp[-2]);
250 if ((volume = atoi (cp)) < 1)
251 adios (NULL, "bad argument %s %s", argp[-2], cp);
256 adios (NULL, "only one draft folder at a time!");
257 if (!(cp = *argp++) || *cp == '-')
258 adios (NULL, "missing argument to %s", argp[-2]);
259 dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp,
260 *cp != '@' ? TFOLDER : TSUBCWF);
264 adios (NULL, "only one draft message at a time!");
265 if (!(dmsg = *argp++) || *dmsg == '-')
266 adios (NULL, "missing argument to %s", argp[-2]);
274 dashstuff = 1; /* trinary logic */
277 dashstuff = -1; /* trinary logic */
281 if (*cp == '+' || *cp == '@') {
283 adios (NULL, "only one folder at a time!");
285 folder = pluspath (cp);
291 cwd = getcpy (pwd ());
293 if (!context_find ("path"))
294 free (path ("./", TFOLDER));
295 if (file && (msgp || folder))
296 adios (NULL, "can't mix files and folders/msgs");
301 strncpy (drft, buildsw ? m_maildir ("draft")
302 : m_draft (dfolder, NULL, NOUSE, &isdf), sizeof(drft));
304 /* Check if a draft already exists */
305 if (!buildsw && stat (drft, &st) != NOTOK) {
307 strncpy (drft, m_draft (dfolder, dmsg, NOUSE, &isdf), sizeof(drft));
309 /* Check if a draft already exists */
310 if (stat (drft, &st) != NOTOK) {
312 printf ("Draft \"%s\" exists (%ld bytes).", drft, (long) st.st_size);
313 for (i = LISTDSW; i != YESW;) {
314 if (!(argp = getans ("\nDisposition? ", isdf ? aqrnl : aqrl)))
316 switch (i = smatch (*argp, isdf ? aqrnl : aqrl)) {
325 showfile (++argp, drft);
328 if (refile (++argp, drft) == 0)
332 advise (NULL, "say what?");
342 anot = 0; /* don't want to annotate a file */
345 * Forwarding a message.
348 msgs[msgp++] = "cur";
350 folder = getfolder (1);
351 maildir = m_maildir (folder);
353 if (chdir (maildir) == NOTOK)
354 adios (maildir, "unable to change directory to");
356 /* read folder and create message structure */
357 if (!(mp = folder_read (folder)))
358 adios (NULL, "unable to read folder %s", folder);
360 /* check for empty folder */
362 adios (NULL, "no messages in %s", folder);
364 /* parse all the message ranges/sequences and set SELECTED */
365 for (msgnum = 0; msgnum < msgp; msgnum++)
366 if (!m_convert (mp, msgs[msgnum]))
368 seq_setprev (mp); /* set the previous sequence */
371 if (filter && access (filter, R_OK) == NOTOK)
372 adios (filter, "unable to read");
375 * Open form (component) file.
379 snprintf (buf, sizeof(buf), IFORMAT, digest);
381 && (cp = context_find (buf))
382 && ((issue = atoi (cp)) < 0))
387 snprintf (buf, sizeof(buf), VFORMAT, digest);
388 if ((cp = context_find (buf)) == NULL || (volume = atoi (cp)) <= 0)
392 in = build_form (form, digest, volume, issue);
394 in = open_form(&form, forwcomps);
396 if ((out = creat (drft, m_gmprot ())) == NOTOK)
397 adios (drft, "unable to create");
400 * copy the components into the draft
402 cpydata (in, out, form, drft);
406 /* just copy the file into the draft */
407 if ((in = open (file, O_RDONLY)) == NOTOK)
408 adios (file, "unable to open");
409 cpydata (in, out, file, drft);
414 * If filter file is defined, then format the
415 * messages into the draft using mhlproc.
418 mhl_draft (out, digest, volume, issue, drft, filter, dashstuff);
420 copy_mime_draft (out);
422 copy_draft (out, digest, drft, volume, issue, dashstuff);
426 snprintf (buf, sizeof(buf), IFORMAT, digest);
427 snprintf (value, sizeof(value), "%d", issue);
428 context_replace (buf, getcpy (value));
429 snprintf (buf, sizeof(buf), VFORMAT, digest);
430 snprintf (value, sizeof(value), "%d", volume);
431 context_replace (buf, getcpy (value));
434 context_replace (pfolder, folder); /* update current folder */
435 seq_setcur (mp, mp->lowsel); /* update current message */
436 seq_save (mp); /* synchronize sequences */
437 context_save (); /* save the context file */
442 what_now (ed, nedit, NOUSE, drft, NULL, 0, mp,
443 anot ? "Forwarded" : NULL, inplace, cwd);
450 * Filter the messages you are forwarding, into the
451 * draft calling the mhlproc, and reading its output
456 mhl_draft (int out, char *digest, int volume, int issue,
457 char *file, char *filter, int dashstuff)
460 int i, msgnum, pd[2];
465 if (pipe (pd) == NOTOK)
466 adios ("pipe", "unable to create");
468 vec[0] = r1bindex (mhlproc, '/');
470 for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
474 adios ("fork", "unable to");
482 vec[i++] = "-forwall";
487 vec[i++] = "-digest";
490 snprintf (buf1, sizeof(buf1), "%d", issue);
492 vec[i++] = "-volume";
493 snprintf (buf2, sizeof(buf2), "%d", volume);
498 * Are we dashstuffing (quoting) the lines that begin
499 * with `-'. We use the mhl default (don't add any flag)
500 * unless the user has specified a specific flag.
503 vec[i++] = "-dashstuffing";
504 else if (dashstuff < 0)
505 vec[i++] = "-nodashstuffing";
507 if (mp->numsel >= MAXARGS - i)
508 adios (NULL, "more than %d messages for %s exec",
509 MAXARGS - i, vec[0]);
512 * Now add the message names to filter. We can only
513 * handle about 995 messages (because vec is fixed size),
514 * but that should be plenty.
516 for (msgnum = mp->lowsel; msgnum <= mp->hghsel && i < sizeof(vec) - 1;
518 if (is_selected (mp, msgnum))
519 vec[i++] = getcpy (m_name (msgnum));
522 execvp (mhlproc, vec);
523 fprintf (stderr, "unable to exec ");
529 cpydata (pd[0], out, vec[0], file);
531 pidXwait(child_id, mhlproc);
538 * Copy the messages into the draft. The messages are
539 * not filtered through the mhlproc. Do dashstuffing if
544 copy_draft (int out, char *digest, char *file, int volume, int issue, int dashstuff)
546 int fd,i, msgcnt, msgnum;
548 register char *bp, *msgnam;
552 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
553 if (is_selected (mp, msgnum)) {
555 strncpy (buffer, msgnum == mp->lowsel ?
556 delim3 : delim4, sizeof(buffer));
558 /* Get buffer ready to go */
560 buflen = sizeof(buffer);
562 strncpy (bp, "\n-------", buflen);
567 if (msgnum == mp->lowsel) {
568 snprintf (bp, buflen, " Forwarded Message%s",
569 mp->numsel > 1 ? "s" : "");
571 snprintf (bp, buflen, " Message %d", msgcnt);
577 strncpy (bp, "\n\n", buflen);
579 write (out, buffer, strlen (buffer));
581 if ((fd = open (msgnam = m_name (msgnum), O_RDONLY)) == NOTOK) {
582 admonish (msgnam, "unable to read message");
587 * Copy the message. Add RFC934 quoting (dashstuffing)
588 * unless given the -nodashstuffing flag.
591 cpydgst (fd, out, msgnam, file);
593 cpydata (fd, out, msgnam, file);
601 strncpy (buffer, delim4, sizeof(buffer));
603 snprintf (buffer, sizeof(buffer), "\n------- End of Forwarded Message%s\n\n",
604 mp->numsel > 1 ? "s" : "");
606 write (out, buffer, strlen (buffer));
609 snprintf (buffer, sizeof(buffer), "End of %s Digest [Volume %d Issue %d]\n",
610 digest, volume, issue);
612 for (bp = buffer + i; i > 1; i--)
616 write (out, buffer, strlen (buffer));
622 * Create a mhbuild composition file for forwarding message.
626 copy_mime_draft (int out)
631 snprintf (buffer, sizeof(buffer), "#forw [forwarded message%s] +%s",
632 mp->numsel == 1 ? "" : "s", mp->foldpath);
633 write (out, buffer, strlen (buffer));
634 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
635 if (is_selected (mp, msgnum)) {
636 snprintf (buffer, sizeof(buffer), " %s", m_name (msgnum));
637 write (out, buffer, strlen (buffer));
639 write (out, "\n", 1);
644 build_form (char *form, char *digest, int volume, int issue)
649 char *line, tmpfil[BUFSIZ];
651 register struct comp *cptr;
656 /* Get new format string */
657 nfs = new_fs (form, NULL, NULL);
658 fmtsize = strlen (nfs) + 256;
660 /* Compile format string */
661 fmt_compile (nfs, &fmt);
663 FINDCOMP (cptr, "digest");
665 cptr->c_text = digest;
666 FINDCOMP (cptr, "date");
668 cptr->c_text = getcpy(dtimenow (0));
676 cp = m_mktemp2(NULL, invo_name, NULL, &tmp);
677 if (cp == NULL) adios("forw", "unable to create temporary file");
678 strncpy (tmpfil, cp, sizeof(tmpfil));
680 if ((in = dup (fileno (tmp))) == NOTOK)
681 adios ("dup", "unable to");
683 line = mh_xmalloc ((unsigned) fmtsize);
684 fmt_scan (fmt, line, fmtsize, dat);
688 adios (tmpfil, "error writing");
690 lseek (in, (off_t) 0, SEEK_SET);