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