Move #include from h/mh.h to source files
[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 #include <unistd.h>
11 #include <dirent.h>
12 #include <locale.h>
13
14 static struct swit switches[] = {
15 #define INTRSW  0
16         { "interactive", 0 },
17 #define NINTRSW  1
18         { "nointeractive", 2 },
19 #define VERSIONSW  2
20         { "Version", 0 },
21 #define HELPSW  3
22         { "help", 0 },
23         { NULL, 0 }
24 };
25
26 /*
27 ** static prototypes
28 */
29 static int rmf(char *);
30 static void rma(char *);
31
32
33 int
34 main(int argc, char **argv)
35 {
36         int defolder = 0, interactive = -1;
37         char *cp, *folder = NULL, newfolder[BUFSIZ];
38         char buf[BUFSIZ], **argp, **arguments;
39
40         setlocale(LC_ALL, "");
41         invo_name = mhbasename(argv[0]);
42
43         /* read user profile/context */
44         context_read();
45
46         arguments = getarguments(invo_name, argc, argv, 1);
47         argp = arguments;
48
49         while ((cp = *argp++)) {
50                 if (*cp == '-') {
51                         switch (smatch(++cp, switches)) {
52                         case AMBIGSW:
53                                 ambigsw(cp, switches);
54                                 exit(1);
55                         case UNKWNSW:
56                                 adios(NULL, "-%s unknown", cp);
57
58                         case HELPSW:
59                                 snprintf(buf, sizeof(buf), "%s [+folder] [switches]", invo_name);
60                                 print_help(buf, switches, 1);
61                                 exit(0);
62                         case VERSIONSW:
63                                 print_version(invo_name);
64                                 exit(0);
65
66                         case INTRSW:
67                                 interactive = 1;
68                                 continue;
69                         case NINTRSW:
70                                 interactive = 0;
71                                 continue;
72                         }
73                 }
74                 if (*cp == '+' || *cp == '@') {
75                         if (folder)
76                                 adios(NULL, "only one folder at a time!");
77                         else
78                                 folder = getcpy(expandfol(cp));
79                 } else {
80                         adios(NULL, "usage: %s [+folder] [switches]",
81                                         invo_name);
82                 }
83         }
84
85         if (!folder) {
86                 folder = getcurfol();
87                 defolder++;
88         }
89         if (strcmp(toabsdir(folder), pwd()) == 0)
90                 adios(NULL, "You can't remove the current working directory");
91
92         if (interactive == -1)
93                 interactive = defolder;
94
95         if (strchr(folder, '/') && (*folder != '/') && (*folder != '.')) {
96                 strcpy(newfolder, folder);
97                 cp = newfolder + strlen(newfolder);
98                 while (cp > newfolder && *cp != '/')
99                         cp--;
100                 if (cp > newfolder)
101                         *cp = '\0';
102                 else
103                         strncpy(newfolder, getdeffol(), sizeof(newfolder));
104         } else {
105                 strncpy(newfolder, getdeffol(), sizeof(newfolder));
106         }
107
108         if (interactive) {
109                 cp = concat("Remove folder \"", folder, "\"? ", NULL);
110                 if (!getanswer(cp))
111                         exit(0);
112                 free(cp);
113         }
114
115         if (rmf(folder) == OK) {
116                 char *cfolder = context_find(curfolder);
117                 if (cfolder && strcmp(cfolder, newfolder)!=0) {
118                         printf("[+%s now current]\n", newfolder);
119                         /* update current folder */
120                         context_replace(curfolder, newfolder);
121                 }
122         }
123         context_save();  /* save the context file */
124         return 0;
125 }
126
127 static int
128 rmf(char *folder)
129 {
130         int i, 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         while ((dp = readdir(dd))) {
165                 switch (dp->d_name[0]) {
166                 case '.':
167                         if (strcmp(dp->d_name, ".") == 0 ||
168                                         strcmp(dp->d_name, "..") == 0)
169                                 continue;  /* else fall */
170
171                 case ',':
172                         break;
173
174                 default:
175                         if (m_atoi(dp->d_name))
176                                 break;
177
178                         admonish(NULL, "file \"%s/%s\" not deleted",
179                                         folder, dp->d_name);
180                         others++;
181                         continue;
182                 }
183                 if (unlink(dp->d_name) == NOTOK) {
184                         admonish(dp->d_name, "unable to unlink %s:", folder);
185                         others++;
186                 }
187         }
188
189         closedir(dd);
190
191         /*
192         ** Remove any relevant private sequences
193         ** or attributes from context file.
194         */
195         rma(folder);
196
197         chdir("..");
198         if (others == 0) {
199                 context_save();  /* Is this needed? meillo 2011-10 */
200                 fflush(stdout);  /* Is this needed? meillo 2011-10 */
201                 if (rmdir(maildir) != -1) {
202                         return OK;
203                 }
204                 admonish(maildir, "unable to remove directory");
205         }
206
207         advise(NULL, "folder +%s not removed", folder);
208         return NOTOK;
209 }
210
211
212 /*
213 ** Remove all the (private) sequence information for
214 ** this folder from the profile/context list.
215 */
216
217 static void
218 rma(char *folder)
219 {
220         register int alen, j, plen;
221         register char *cp;
222         register struct node *np, *pp;
223
224         alen = strlen("atr-");
225         plen = strlen(cp = getcpy(toabsdir(folder))) + 1;
226
227         /*
228         ** Search context list for keys that look like
229         ** "atr-something-folderpath", and remove them.
230         */
231         for (np = m_defs, pp = NULL; np; np = np->n_next) {
232                 if (strncmp(np->n_name, "atr-", alen)==0 &&
233                                 (j = strlen(np->n_name) - plen) > alen &&
234                                 *(np->n_name + j) == '-' &&
235                                 strcmp(cp, np->n_name + j + 1) == 0) {
236                         if (!np->n_context)
237                                 admonish(NULL, "bug: context_del(key=\"%s\")",
238                                                 np->n_name);
239                         if (pp) {
240                                 pp->n_next = np->n_next;
241                                 np = pp;
242                         } else {
243                                 m_defs = np->n_next;
244                         }
245                         ctxflags |= CTXMOD;
246                 } else {
247                         pp = np;
248                 }
249         }
250         free(cp);
251 }