* docs/MAIL.FILTERING: added note on removing procmail -f or
[mmh] / sbr / folder_delmsgs.c
1
2 /*
3  * folder_delmsgs.c -- "remove" SELECTED messages from a folder
4  *
5  * $Id$
6  *
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.
10  */
11
12 #include <h/mh.h>
13
14 /*
15  * 1) If we are using an external rmmproc, then exec it.
16  * 2) Else if unlink_msgs is non-zero, then unlink the
17  *    SELECTED messages.
18  * 3) Else rename SELECTED messages by prefixing name
19  *    with a standard prefix.
20  *
21  * If there is an error, return -1, else return 0.
22  */
23
24 int
25 folder_delmsgs (struct msgs *mp, int unlink_msgs, int nohook)
26 {
27     pid_t pid;
28     int msgnum, vecp, retval = 0;
29     char buf[100], *dp, **vec;
30     char        msgpath[BUFSIZ];
31
32     /*
33      * If "rmmproc" is defined, exec it to remove messages.
34      */
35     if (rmmproc) {
36         /* Unset the EXISTS flag for each message to be removed */
37         for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
38             if (is_selected (mp, msgnum))
39                 unset_exists (mp, msgnum);
40         }
41
42         /* Mark that the sequence information has changed */
43         mp->msgflags |= SEQMOD;
44
45         if (mp->numsel > MAXARGS - 2)
46             adios (NULL, "more than %d messages for %s exec", MAXARGS - 2,
47                    rmmproc);
48         vec = (char **) calloc ((size_t) (mp->numsel + 2), sizeof(*vec));
49         if (vec == NULL)
50             adios (NULL, "unable to allocate exec vector");
51         vecp = 1;
52         for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
53             if (is_selected (mp, msgnum) &&
54                 !(vec[vecp++] = strdup (m_name (msgnum))))
55                 adios (NULL, "strdup failed");
56         }
57         vec[vecp] = NULL;
58
59         fflush (stdout);
60         vec[0] = r1bindex (rmmproc, '/');
61
62         switch (pid = vfork()) {
63         case -1:
64             advise ("fork", "unable to");
65             return -1;
66
67         case 0:
68             execvp (rmmproc, vec);
69             fprintf (stderr, "unable to exec ");
70             perror (rmmproc);
71             _exit (-1);
72
73         default:
74             return (pidwait (pid, -1));
75         }
76     }
77
78     /*
79      * Either unlink or rename the SELECTED messages
80      */
81     for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
82         if (is_selected (mp, msgnum)) {
83             /* unselect message */
84             unset_selected (mp, msgnum);
85             mp->numsel--;
86
87             /*
88              *  Run the external hook on the message if one was specified in the context.
89              *  All we have is the message number; we have changed to the directory
90              *  containing the message.  So, we need to extract that directory to form
91              *  the complete path.  Note that the caller knows the directory, but has
92              *  no way of passing that to us.
93              */
94
95             if (!nohook) {
96                     (void)snprintf(msgpath, sizeof (msgpath), "%s/%d", mp->foldpath, msgnum);
97                     (void)ext_hook("del-hook", msgpath, (char *)0);
98                 }
99
100             dp = m_name (msgnum);
101
102             if (unlink_msgs) {
103                 /* just unlink the messages */
104                 if (unlink (dp) == -1) {
105                     admonish (dp, "unable to unlink");
106                     retval = -1;
107                     continue;
108                 }
109             } else {
110                 /* or rename messages with standard prefix */
111                 strncpy (buf, m_backup (dp), sizeof(buf));
112                 if (rename (dp, buf) == -1) {
113                     admonish (buf, "unable to rename %s to", dp);
114                     retval = -1;
115                     continue;
116                 }
117             }
118
119             /* If removal was successful, decrement message count */
120             unset_exists (mp, msgnum);
121             mp->nummsg--;
122         }
123     }
124
125     /* Sanity check */
126     if (mp->numsel != 0)
127         adios (NULL, "oops, mp->numsel should be 0");
128
129     /* Mark that the sequence information has changed */
130     mp->msgflags |= SEQMOD;
131
132     return retval;
133 }