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