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