Update for post-1.5 release.
[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                 break;
173
174             default: 
175                 if (m_atoi (dp->d_name))
176                     break;
177                 if (strcmp (dp->d_name, LINK) == 0
178                         || strncmp (dp->d_name, BACKUP_PREFIX, j) == 0)
179                     break;
180
181                 admonish (NULL, "file \"%s/%s\" not deleted",
182                         folder, dp->d_name);
183                 others++;
184                 continue;
185         }
186         if (unlink (dp->d_name) == NOTOK) {
187             admonish (dp->d_name, "unable to unlink %s:", folder);
188             others++;
189         }
190     }
191
192     closedir (dd);
193
194     /*
195      * Remove any relevant private sequences
196      * or attributes from context file.
197      */
198     rma (folder);
199
200     chdir ("..");
201     if (others == 0 && remdir (maildir))
202         return OK;
203
204     advise (NULL, "folder +%s not removed", folder);
205     return NOTOK;
206 }
207
208
209 /*
210  * Remove all the (private) sequence information for
211  * this folder from the profile/context list.
212  */
213
214 static void
215 rma (char *folder)
216 {
217     register int alen, j, plen;
218     register char *cp;
219     register struct node *np, *pp;
220
221     alen = strlen ("atr-");
222     plen = strlen (cp = m_mailpath (folder)) + 1;
223
224     /*
225      * Search context list for keys that look like
226      * "atr-something-folderpath", and remove them.
227      */
228     for (np = m_defs, pp = NULL; np; np = np->n_next) {
229         if (ssequal ("atr-", np->n_name)
230                 && (j = strlen (np->n_name) - plen) > alen
231                 && *(np->n_name + j) == '-'
232                 && strcmp (cp, np->n_name + j + 1) == 0) {
233             if (!np->n_context)
234                 admonish (NULL, "bug: context_del(key=\"%s\")", np->n_name);
235             if (pp) {
236                 pp->n_next = np->n_next;
237                 np = pp;
238             } else {
239                 m_defs = np->n_next;
240             }
241             ctxflags |= CTXMOD;
242         } else {
243             pp = np;
244         }
245     }
246 }