1 /*
2 ** rmf.c -- remove a folder
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh. See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <h/utils.h>
11 #include <unistd.h>
12 #include <dirent.h>
13 #include <locale.h>
14 #include <sysexits.h>
15
16 static struct swit switches[] = {
17 #define INTRSW 0
18 { "interactive", 0 },
19 #define NINTRSW 1
20 { "nointeractive", 2 },
21 #define VERSIONSW 2
22 { "Version", 0 },
23 #define HELPSW 3
24 { "help", 0 },
25 { NULL, 0 }
26 };
27
28 char *version=VERSION;
29
30 /*
31 ** static prototypes
32 */
33 static int rmf(char *);
34 static void rma(char *);
35
36
37 int
main(int argc,char ** argv)38 main(int argc, char **argv)
39 {
40 int defolder = 0, interactive = -1;
41 char *cp, *folder = NULL, newfolder[BUFSIZ];
42 char buf[BUFSIZ], **argp, **arguments;
43
44 setlocale(LC_ALL, "");
45 invo_name = mhbasename(argv[0]);
46
47 /* read user profile/context */
48 context_read();
49
50 arguments = getarguments(invo_name, argc, argv, 1);
51 argp = arguments;
52
53 while ((cp = *argp++)) {
54 if (*cp == '-') {
55 switch (smatch(++cp, switches)) {
56 case AMBIGSW:
57 ambigsw(cp, switches);
58 exit(EX_USAGE);
59 case UNKWNSW:
60 adios(EX_USAGE, NULL, "-%s unknown", cp);
61
62 case HELPSW:
63 snprintf(buf, sizeof(buf), "%s [+folder] [switches]", invo_name);
64 print_help(buf, switches, 1);
65 exit(argc == 2 ? EX_OK : EX_USAGE);
66 case VERSIONSW:
67 print_version(invo_name);
68 exit(argc == 2 ? EX_OK : EX_USAGE);
69
70 case INTRSW:
71 interactive = 1;
72 continue;
73 case NINTRSW:
74 interactive = 0;
75 continue;
76 }
77 }
78 if (*cp == '+' || *cp == '@') {
79 if (folder)
80 adios(EX_USAGE, NULL, "only one folder at a time!");
81 else
82 folder = mh_xstrdup(expandfol(cp));
83 } else {
84 adios(EX_USAGE, NULL, "usage: %s [+folder] [switches]",
85 invo_name);
86 }
87 }
88
89 if (!folder) {
90 folder = getcurfol();
91 defolder++;
92 }
93 if (strcmp(toabsdir(folder), pwd()) == 0)
94 adios(EX_USAGE, NULL, "You can't remove the current working directory");
95
96 if (interactive == -1)
97 interactive = defolder;
98
99 if (strchr(folder, '/') && (*folder != '/') && (*folder != '.')) {
100 strcpy(newfolder, folder);
101 cp = newfolder + strlen(newfolder);
102 while (cp > newfolder && *cp != '/')
103 cp--;
104 if (cp > newfolder)
105 *cp = '\0';
106 else
107 strncpy(newfolder, getdeffol(), sizeof(newfolder));
108 } else {
109 strncpy(newfolder, getdeffol(), sizeof(newfolder));
110 }
111
112 if (interactive) {
113 cp = concat("Remove folder \"", folder, "\"? ", NULL);
114 if (!getanswer(cp))
115 exit(EX_OK);
116 mh_free0(&cp);
117 }
118
119 if (rmf(folder) == OK) {
120 char *cfolder = context_find(curfolder);
121 if (cfolder && strcmp(cfolder, newfolder)!=0) {
122 printf("[+%s now current]\n", newfolder);
123 /* update current folder */
124 context_replace(curfolder, newfolder);
125 }
126 }
127 context_save(); /* save the context file */
128 return 0;
129 }
130
131 static int
rmf(char * folder)132 rmf(char *folder)
133 {
134 int i, others;
135 char *maildir;
136 char cur[BUFSIZ];
137 struct dirent *dp;
138 DIR *dd;
139
140 switch (i = chdir(maildir = toabsdir(folder))) {
141 case OK:
142 if (access(".", W_OK) != NOTOK && access("..", W_OK) != NOTOK)
143 break; /* fall otherwise */
144
145 case NOTOK:
146 snprintf(cur, sizeof(cur), "atr-%s-%s", seq_cur,
147 toabsdir(folder));
148 if (!context_del(cur)) {
149 printf("[+%s de-referenced]\n", folder);
150 return OK;
151 }
152 advise(NULL, "you have no profile entry for the %s folder +%s",
153 i == NOTOK ? "unreadable" : "read-only",
154 folder);
155 return NOTOK;
156 }
157
158 if ((dd = opendir(".")) == NULL)
159 adios(EX_IOERR, NULL, "unable to read folder +%s", folder);
160 others = 0;
161
162 /*
163 ** Run the external delete hook program.
164 */
165
166 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; /* else fall */
174
175 case ',':
176 break;
177
178 default:
179 if (m_atoi(dp->d_name))
180 break;
181
182 admonish(NULL, "file \"%s/%s\" not deleted",
183 folder, dp->d_name);
184 others++;
185 continue;
186 }
187 if (unlink(dp->d_name) == NOTOK) {
188 admonish(dp->d_name, "unable to unlink %s:", folder);
189 others++;
190 }
191 }
192
193 closedir(dd);
194
195 /*
196 ** Remove any relevant private sequences
197 ** or attributes from context file.
198 */
199 rma(folder);
200
201 chdir("..");
202 if (others == 0) {
203 context_save(); /* Is this needed? meillo 2011-10 */
204 fflush(stdout); /* Is this needed? meillo 2011-10 */
205 if (rmdir(maildir) != -1) {
206 return OK;
207 }
208 admonish(maildir, "unable to remove directory");
209 }
210
211 advise(NULL, "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
rma(char * folder)222 rma(char *folder)
223 {
224 int alen, j, plen;
225 char *cp;
226 struct node *np, *pp;
227
228 alen = strlen("atr-");
229 plen = strlen(cp = mh_xstrdup(toabsdir(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 (strncmp(np->n_name, "atr-", alen)==0 &&
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 admonish(NULL, "bug: context_del(key=\"%s\")",
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 mh_free0(&cp);
255 }
256