a49ba4cf8d24801562821dc89fad1e98a9e4485d
[mmh] / uip / rmf.c
1
2 /*
3  * rmf.c -- remove a folder
4  *
5  * This code is Copyright (c) 2002, by the authors of nmh.  See the
6  * COPYRIGHT file in the root directory of the nmh distribution for
7  * complete copyright information.
8  */
9
10 #include <h/mh.h>
11
12 static struct swit switches[] = {
13 #define INTRSW            0
14     { "interactive", 0 },
15 #define NINTRSW           1
16     { "nointeractive", 0 },
17 #define VERSIONSW         2
18     { "version", 0 },
19 #define HELPSW            3
20     { "help", 0 },
21     { NULL, 0 }
22 };
23
24 /*
25  * static prototypes
26  */
27 static int rmf(char *);
28 static void rma (char *);
29
30
31 int
32 main (int argc, char **argv)
33 {
34     int defolder = 0, interactive = -1;
35     char *cp, *folder = NULL, newfolder[BUFSIZ];
36     char buf[BUFSIZ], **argp, **arguments;
37
38 #ifdef LOCALE
39     setlocale(LC_ALL, "");
40 #endif
41     invo_name = r1bindex (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                     done (1);
55                 case UNKWNSW: 
56                     adios (NULL, "-%s unknown", cp);
57
58                 case HELPSW: 
59                     snprintf (buf, sizeof(buf), "%s [+folder] [switches]",
60                         invo_name);
61                     print_help (buf, switches, 1);
62                     done (1);
63                 case VERSIONSW:
64                     print_version(invo_name);
65                     done (1);
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 (NULL, "only one folder at a time!");
78             else
79                 folder = pluspath (cp);
80         } else {
81             adios (NULL, "usage: %s [+folder] [switches]", invo_name);
82         }
83     }
84
85     if (!context_find ("path"))
86         free (path ("./", TFOLDER));
87     if (!folder) {
88         folder = getfolder (1);
89         defolder++;
90     }
91     if (strcmp (m_mailpath (folder), pwd ()) == 0)
92         adios (NULL, "sorry, you can't remove the current working directory");
93
94     if (interactive == -1)
95         interactive = defolder;
96
97     if (strchr (folder, '/') && (*folder != '/') && (*folder != '.')) {
98         for (cp = copy (folder, newfolder); cp > newfolder && *cp != '/'; cp--)
99             continue;
100         if (cp > newfolder)
101             *cp = '\0';
102         else
103             strncpy (newfolder, getfolder(0), sizeof(newfolder));
104     } else {
105         strncpy (newfolder, getfolder(0), sizeof(newfolder));
106     }
107
108     if (interactive) {
109         cp = concat ("Remove folder \"", folder, "\"? ", NULL);
110         if (!getanswer (cp))
111             done (0);
112         free (cp);
113     }
114
115     if (rmf (folder) == OK) {
116         char *cfolder = context_find(pfolder);
117         if (cfolder && strcmp (cfolder, newfolder)) {
118             printf ("[+%s now current]\n", newfolder);
119             context_replace (pfolder, newfolder);       /* update current folder */
120         }
121     }
122     context_save ();    /* save the context file */
123     done (0);
124     return 1;
125 }
126
127 static int
128 rmf (char *folder)
129 {
130     int i, j, others;
131     register char *maildir;
132     char cur[BUFSIZ];
133     register struct dirent *dp;
134     register DIR *dd;
135
136     switch (i = chdir (maildir = m_maildir (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",
143                         current, m_mailpath (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", folder);
150             return NOTOK;
151     }
152
153     if ((dd = opendir (".")) == NULL)
154         adios (NULL, "unable to read folder +%s", folder);
155     others = 0;
156
157     /*
158      *  Run the external delete hook program.
159      */
160
161     (void)ext_hook("del-hook", maildir, (char *)0);
162
163     j = strlen(BACKUP_PREFIX);
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 #ifdef MHE
173             case '+': 
174 #endif /* MHE */
175 #ifdef UCI
176             case '_': 
177             case '#': 
178 #endif /* UCI */
179                 break;
180
181             default: 
182                 if (m_atoi (dp->d_name))
183                     break;
184                 if (strcmp (dp->d_name, LINK) == 0
185                         || strncmp (dp->d_name, BACKUP_PREFIX, j) == 0)
186                     break;
187
188                 admonish (NULL, "file \"%s/%s\" not deleted",
189                         folder, dp->d_name);
190                 others++;
191                 continue;
192         }
193         if (unlink (dp->d_name) == NOTOK) {
194             admonish (dp->d_name, "unable to unlink %s:", folder);
195             others++;
196         }
197     }
198
199     closedir (dd);
200
201     /*
202      * Remove any relevant private sequences
203      * or attributes from context file.
204      */
205     rma (folder);
206
207     chdir ("..");
208     if (others == 0 && remdir (maildir))
209         return OK;
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     register int alen, j, plen;
225     register char *cp;
226     register struct node *np, *pp;
227
228     alen = strlen ("atr-");
229     plen = strlen (cp = m_mailpath (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 (ssequal ("atr-", np->n_name)
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\")", np->n_name);
242             if (pp) {
243                 pp->n_next = np->n_next;
244                 np = pp;
245             } else {
246                 m_defs = np->n_next;
247             }
248             ctxflags |= CTXMOD;
249         } else {
250             pp = np;
251         }
252     }
253 }