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