Bring in all of the mh-e support that is actually used
[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 = mhbasename(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 = getcpy(expandfol(cp));
78                 } else {
79                         adios(NULL, "usage: %s [+folder] [switches]",
80                                         invo_name);
81                 }
82         }
83
84         if (!folder) {
85                 folder = getcurfol();
86                 defolder++;
87         }
88         if (strcmp(toabsdir(folder), pwd()) == 0)
89                 adios(NULL, "You can't remove the current working directory");
90
91         if (interactive == -1)
92                 interactive = defolder;
93
94         if (strchr(folder, '/') && (*folder != '/') && (*folder != '.')) {
95                 strcpy(newfolder, folder);
96                 cp = newfolder + strlen(newfolder);
97                 while (cp > newfolder && *cp != '/')
98                         cp--;
99                 if (cp > newfolder)
100                         *cp = '\0';
101                 else
102                         strncpy(newfolder, getdeffol(), sizeof(newfolder));
103         } else {
104                 strncpy(newfolder, getdeffol(), sizeof(newfolder));
105         }
106
107         if (interactive) {
108                 cp = concat("Remove folder \"", folder, "\"? ", NULL);
109                 if (!getanswer(cp))
110                         done(0);
111                 free(cp);
112         }
113
114         if (rmf(folder) == OK) {
115                 char *cfolder = context_find(curfolder);
116                 if (cfolder && strcmp(cfolder, newfolder)!=0) {
117                         printf("[+%s now current]\n", newfolder);
118                         /* update current folder */
119                         context_replace(curfolder, newfolder);
120                 }
121         }
122         context_save();  /* save the context file */
123         done(0);
124         return 1;
125 }
126
127 static int
128 rmf(char *folder)
129 {
130         int i, j, others;
131         register char *maildir;
132         char cur[BUFSIZ];
133         register struct dirent *dp;
134         register DIR *dd;
135
136         switch (i = chdir(maildir = toabsdir(folder))) {
137         case OK:
138                 if (access(".", W_OK) != NOTOK && access("..", W_OK) != NOTOK)
139                         break;  /* fall otherwise */
140
141         case NOTOK:
142                 snprintf(cur, sizeof(cur), "atr-%s-%s", seq_cur,
143                                 toabsdir(folder));
144                 if (!context_del(cur)) {
145                         printf("[+%s de-referenced]\n", folder);
146                         return OK;
147                 }
148                 advise(NULL, "you have no profile entry for the %s folder +%s",
149                                 i == NOTOK ? "unreadable" : "read-only",
150                                 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         ext_hook("del-hook", maildir, NULL);
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                         break;
174
175                 default:
176                         if (m_atoi(dp->d_name))
177                                 break;
178                         if (strcmp(dp->d_name, altmsglink) == 0 ||
179                                         strncmp(dp->d_name,
180                                         backup_prefix, j) == 0)
181                                 break;
182
183                         admonish(NULL, "file \"%s/%s\" not deleted",
184                                         folder, dp->d_name);
185                         others++;
186                         continue;
187                 }
188                 if (unlink(dp->d_name) == NOTOK) {
189                         admonish(dp->d_name, "unable to unlink %s:", folder);
190                         others++;
191                 }
192         }
193
194         closedir(dd);
195
196         /*
197         ** Remove any relevant private sequences
198         ** or attributes from context file.
199         */
200         rma(folder);
201
202         chdir("..");
203         if (others == 0) {
204                 context_save();  /* Is this needed? meillo 2011-10 */
205                 fflush(stdout);  /* Is this needed? meillo 2011-10 */
206                 if (rmdir(maildir) != -1) {
207                         return OK;
208                 }
209                 admonish(maildir, "unable to remove directory");
210         }
211
212         advise(NULL, "folder +%s not removed", folder);
213         return NOTOK;
214 }
215
216
217 /*
218 ** Remove all the (private) sequence information for
219 ** this folder from the profile/context list.
220 */
221
222 static void
223 rma(char *folder)
224 {
225         register int alen, j, plen;
226         register char *cp;
227         register struct node *np, *pp;
228
229         alen = strlen("atr-");
230         plen = strlen(cp = getcpy(toabsdir(folder))) + 1;
231
232         /*
233         ** Search context list for keys that look like
234         ** "atr-something-folderpath", and remove them.
235         */
236         for (np = m_defs, pp = NULL; np; np = np->n_next) {
237                 if (strncmp(np->n_name, "atr-", alen)==0 &&
238                                 (j = strlen(np->n_name) - plen) > alen &&
239                                 *(np->n_name + j) == '-' &&
240                                 strcmp(cp, np->n_name + j + 1) == 0) {
241                         if (!np->n_context)
242                                 admonish(NULL, "bug: context_del(key=\"%s\")",
243                                                 np->n_name);
244                         if (pp) {
245                                 pp->n_next = np->n_next;
246                                 np = pp;
247                         } else {
248                                 m_defs = np->n_next;
249                         }
250                         ctxflags |= CTXMOD;
251                 } else {
252                         pp = np;
253                 }
254         }
255         free(cp);
256 }