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