redesign version string
[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 <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
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
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
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 }