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