]> diplodocus.org Git - nmh/blob - uip/rmf.c
Use va_copy() to get a copy of va_list, instead of using original.
[nmh] / uip / rmf.c
1 /* rmf.c -- remove a folder
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include <h/mh.h>
9 #include "h/done.h"
10 #include <h/utils.h>
11 #include "sbr/m_maildir.h"
12 #include "sbr/m_mktemp.h"
13
14 #define RMF_SWITCHES \
15 X("interactive", 0, INTRSW) \
16 X("nointeractive", 0, NINTRSW) \
17 X("version", 0, VERSIONSW) \
18 X("help", 0, HELPSW) \
19
20 #define X(sw, minchars, id) id,
21 DEFINE_SWITCH_ENUM(RMF);
22 #undef X
23
24 #define X(sw, minchars, id) { sw, minchars, id },
25 DEFINE_SWITCH_ARRAY(RMF, switches);
26 #undef X
27
28 /*
29 * static prototypes
30 */
31 static int rmf(char *);
32 static void rma (char *);
33
34
35 int
36 main (int argc, char **argv)
37 {
38 bool defolder = false;
39 int interactive = -1;
40 char *cp, *folder = NULL, newfolder[BUFSIZ];
41 char buf[BUFSIZ], **argp, **arguments;
42 char *fp;
43
44 if (nmh_init(argv[0], true, true)) { return 1; }
45
46 arguments = getarguments (invo_name, argc, argv, 1);
47 argp = arguments;
48
49 while ((cp = *argp++)) {
50 if (*cp == '-') {
51 switch (smatch (++cp, switches)) {
52 case AMBIGSW:
53 ambigsw (cp, switches);
54 done (1);
55 case UNKWNSW:
56 die("-%s unknown", cp);
57
58 case HELPSW:
59 snprintf (buf, sizeof(buf), "%s [+folder] [switches]",
60 invo_name);
61 print_help (buf, switches, 1);
62 done (0);
63 case VERSIONSW:
64 print_version(invo_name);
65 done (0);
66
67 case INTRSW:
68 interactive = 1;
69 continue;
70 case NINTRSW:
71 interactive = 0;
72 continue;
73 }
74 }
75 if (*cp == '+' || *cp == '@') {
76 if (folder)
77 die("only one folder at a time!");
78 folder = pluspath (cp);
79 } else {
80 die("usage: %s [+folder] [switches]", invo_name);
81 }
82 }
83
84 if (!context_find ("path"))
85 free (path ("./", TFOLDER));
86 if (!folder) {
87 folder = getfolder (1);
88 defolder = true;
89 }
90 fp = m_mailpath(folder);
91 if (!strcmp(fp, pwd()))
92 die("sorry, you can't remove the current working directory");
93 free(fp);
94
95 if (interactive == -1)
96 interactive = defolder;
97
98 if (strchr (folder, '/') && (*folder != '/') && (*folder != '.')) {
99 for (cp = stpcpy(newfolder, folder); cp > newfolder && *cp != '/'; cp--)
100 continue;
101 if (cp > newfolder)
102 *cp = '\0';
103 else
104 strncpy (newfolder, getfolder(0), sizeof(newfolder));
105 } else {
106 strncpy (newfolder, getfolder(0), sizeof(newfolder));
107 }
108
109 if (interactive) {
110 cp = concat ("Remove folder \"", folder, "\"? ", NULL);
111 if (!read_yes_or_no_if_tty (cp))
112 done (0);
113 free (cp);
114 }
115
116 if (rmf (folder) == OK) {
117 char *cfolder = context_find(pfolder);
118 if (cfolder && strcmp (cfolder, newfolder)) {
119 printf ("[+%s now current]\n", newfolder);
120 context_replace (pfolder, newfolder); /* update current folder */
121 }
122 }
123 context_save (); /* save the context file */
124 done (0);
125 return 1;
126 }
127
128 static int
129 rmf (char *folder)
130 {
131 int i;
132 bool others;
133 char *fp;
134 char *maildir;
135 char cur[BUFSIZ];
136 struct dirent *dp;
137 DIR *dd;
138
139 switch (i = chdir (maildir = m_maildir (folder))) {
140 case OK:
141 if (access (".", W_OK) != NOTOK && access ("..", W_OK) != NOTOK)
142 break;
143 /* FALLTHRU */
144
145 case NOTOK:
146 fp = m_mailpath(folder);
147 snprintf (cur, sizeof(cur), "atr-%s-%s", current, fp);
148 free(fp);
149 if (!context_del (cur)) {
150 printf ("[+%s de-referenced]\n", folder);
151 return OK;
152 }
153 inform("you have no profile entry for the %s folder +%s",
154 i == NOTOK ? "unreadable" : "read-only", folder);
155 return NOTOK;
156 }
157
158 if ((dd = opendir (".")) == NULL)
159 die("unable to read folder +%s", folder);
160 others = false;
161
162 /*
163 * Run the external delete hook program.
164 */
165
166 (void)ext_hook("del-hook", maildir, NULL);
167
168 while ((dp = readdir (dd))) {
169 switch (dp->d_name[0]) {
170 case '.':
171 if (strcmp (dp->d_name, ".") == 0
172 || strcmp (dp->d_name, "..") == 0)
173 continue;
174 break;
175
176 case ',':
177 break;
178
179 default:
180 if (m_atoi (dp->d_name))
181 break;
182 if (strcmp (dp->d_name, LINK) == 0
183 || has_prefix(dp->d_name, BACKUP_PREFIX))
184 break;
185
186 inform("file \"%s/%s\" not deleted, continuing...",
187 folder, dp->d_name);
188 others = true;
189 continue;
190 }
191 if (m_unlink (dp->d_name) == NOTOK) {
192 admonish (dp->d_name, "unable to unlink %s:", folder);
193 others = true;
194 }
195 }
196
197 closedir (dd);
198
199 /*
200 * Remove any relevant private sequences
201 * or attributes from context file.
202 */
203 rma (folder);
204
205 if (chdir ("..") < 0) {
206 advise ("..", "chdir");
207 }
208 if (!others && remdir (maildir))
209 return OK;
210
211 inform("folder +%s not removed", folder);
212 return NOTOK;
213 }
214
215
216 /*
217 * Remove all the (private) sequence information for
218 * this folder from the profile/context list.
219 */
220
221 static void
222 rma (char *folder)
223 {
224 int alen, j, plen;
225 char *cp;
226 struct node *np, *pp;
227
228 alen = LEN("atr-");
229 plen = strlen (cp = m_mailpath (folder)) + 1;
230
231 /*
232 * Search context list for keys that look like
233 * "atr-something-folderpath", and remove them.
234 */
235 for (np = m_defs, pp = NULL; np; np = np->n_next) {
236 if (ssequal ("atr-", np->n_name)
237 && (j = strlen (np->n_name) - plen) > alen
238 && *(np->n_name + j) == '-'
239 && strcmp (cp, np->n_name + j + 1) == 0) {
240 if (!np->n_context)
241 inform("bug: context_del(key=\"%s\"), continuing...",
242 np->n_name);
243 if (pp) {
244 pp->n_next = np->n_next;
245 np = pp;
246 } else {
247 m_defs = np->n_next;
248 }
249 ctxflags |= CTXMOD;
250 } else {
251 pp = np;
252 }
253 }
254
255 free(cp);
256 }