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