* uip/sendsbr.c: replaced st_mtim with st_mtime, that's what
[mmh] / uip / rmf.c
1
2 /*
3  * rmf.c -- remove a folder
4  *
5  * $Id$
6  *
7  * This code is Copyright (c) 2002, by the authors of nmh.  See the
8  * COPYRIGHT file in the root directory of the nmh distribution for
9  * complete copyright information.
10  */
11
12 #include <h/mh.h>
13
14 static struct swit switches[] = {
15 #define INTRSW            0
16     { "interactive", 0 },
17 #define NINTRSW           1
18     { "nointeractive", 0 },
19 #define VERSIONSW         2
20     { "version", 0 },
21 #define HELPSW            3
22     { "help", 0 },
23     { NULL, 0 }
24 };
25
26 /*
27  * static prototypes
28  */
29 static int rmf(char *);
30 static void rma (char *);
31
32
33 int
34 main (int argc, char **argv)
35 {
36     int defolder = 0, interactive = -1;
37     char *cp, *folder = NULL, newfolder[BUFSIZ];
38     char buf[BUFSIZ], **argp, **arguments;
39
40 #ifdef LOCALE
41     setlocale(LC_ALL, "");
42 #endif
43     invo_name = r1bindex (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                     done (1);
57                 case UNKWNSW: 
58                     adios (NULL, "-%s unknown", cp);
59
60                 case HELPSW: 
61                     snprintf (buf, sizeof(buf), "%s [+folder] [switches]",
62                         invo_name);
63                     print_help (buf, switches, 1);
64                     done (1);
65                 case VERSIONSW:
66                     print_version(invo_name);
67                     done (1);
68
69                 case INTRSW: 
70                     interactive = 1;
71                     continue;
72                 case NINTRSW: 
73                     interactive = 0;
74                     continue;
75             }
76         }
77         if (*cp == '+' || *cp == '@') {
78             if (folder)
79                 adios (NULL, "only one folder at a time!");
80             else
81                 folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
82         } else {
83             adios (NULL, "usage: %s [+folder] [switches]", invo_name);
84         }
85     }
86
87     if (!context_find ("path"))
88         free (path ("./", TFOLDER));
89     if (!folder) {
90         folder = getfolder (1);
91         defolder++;
92     }
93     if (strcmp (m_mailpath (folder), pwd ()) == 0)
94         adios (NULL, "sorry, you can't remove the current working directory");
95
96     if (interactive == -1)
97         interactive = defolder;
98
99     if (strchr (folder, '/') && (*folder != '/') && (*folder != '.')) {
100         for (cp = copy (folder, newfolder); cp > newfolder && *cp != '/'; cp--)
101             continue;
102         if (cp > newfolder)
103             *cp = '\0';
104         else
105             strncpy (newfolder, getfolder(0), sizeof(newfolder));
106     } else {
107         strncpy (newfolder, getfolder(0), sizeof(newfolder));
108     }
109
110     if (interactive) {
111         cp = concat ("Remove folder \"", folder, "\"? ", NULL);
112         if (!getanswer (cp))
113             done (0);
114         free (cp);
115     }
116
117     if (rmf (folder) == OK) {
118         char *cfolder = context_find(pfolder);
119         if (cfolder && strcmp (cfolder, newfolder)) {
120             printf ("[+%s now current]\n", newfolder);
121             context_replace (pfolder, newfolder);       /* update current folder */
122         }
123     }
124     context_save ();    /* save the context file */
125     return done (0);
126 }
127
128 static int
129 rmf (char *folder)
130 {
131     int i, j, others;
132     register char *maildir;
133     char cur[BUFSIZ];
134     register struct dirent *dp;
135     register DIR *dd;
136
137     switch (i = chdir (maildir = m_maildir (folder))) {
138         case OK: 
139             if (access (".", W_OK) != NOTOK && access ("..", W_OK) != NOTOK)
140                 break;          /* fall otherwise */
141
142         case NOTOK: 
143             snprintf (cur, sizeof(cur), "atr-%s-%s",
144                         current, m_mailpath (folder));
145             if (!context_del (cur)) {
146                 printf ("[+%s de-referenced]\n", folder);
147                 return OK;
148             }
149             advise (NULL, "you have no profile entry for the %s folder +%s",
150                     i == NOTOK ? "unreadable" : "read-only", folder);
151             return NOTOK;
152     }
153
154     if ((dd = opendir (".")) == NULL)
155         adios (NULL, "unable to read folder +%s", folder);
156     others = 0;
157
158     /*
159      *  Run the external delete hook program.
160      */
161
162     (void)ext_hook("del-hook", maildir, (char *)0);
163
164     j = strlen(BACKUP_PREFIX);
165     while ((dp = readdir (dd))) {
166         switch (dp->d_name[0]) {
167             case '.': 
168                 if (strcmp (dp->d_name, ".") == 0
169                         || strcmp (dp->d_name, "..") == 0)
170                     continue;   /* else fall */
171
172             case ',': 
173 #ifdef MHE
174             case '+': 
175 #endif /* MHE */
176 #ifdef UCI
177             case '_': 
178             case '#': 
179 #endif /* UCI */
180                 break;
181
182             default: 
183                 if (m_atoi (dp->d_name))
184                     break;
185                 if (strcmp (dp->d_name, LINK) == 0
186                         || strncmp (dp->d_name, BACKUP_PREFIX, j) == 0)
187                     break;
188
189                 admonish (NULL, "file \"%s/%s\" not deleted",
190                         folder, dp->d_name);
191                 others++;
192                 continue;
193         }
194         if (unlink (dp->d_name) == NOTOK) {
195             admonish (dp->d_name, "unable to unlink %s:", folder);
196             others++;
197         }
198     }
199
200     closedir (dd);
201
202     /*
203      * Remove any relevant private sequences
204      * or attributes from context file.
205      */
206     rma (folder);
207
208     chdir ("..");
209     if (others == 0 && remdir (maildir))
210         return OK;
211
212     advise (NULL, "folder +%s not removed", folder);
213     return NOTOK;
214 }
215
216
217 /*
218  * Remove all the (private) sequence information for
219  * this folder from the profile/context list.
220  */
221
222 static void
223 rma (char *folder)
224 {
225     register int alen, j, plen;
226     register char *cp;
227     register struct node *np, *pp;
228
229     alen = strlen ("atr-");
230     plen = strlen (cp = m_mailpath (folder)) + 1;
231
232     /*
233      * Search context list for keys that look like
234      * "atr-something-folderpath", and remove them.
235      */
236     for (np = m_defs, pp = NULL; np; np = np->n_next) {
237         if (ssequal ("atr-", np->n_name)
238                 && (j = strlen (np->n_name) - plen) > alen
239                 && *(np->n_name + j) == '-'
240                 && strcmp (cp, np->n_name + j + 1) == 0) {
241             if (!np->n_context)
242                 admonish (NULL, "bug: context_del(key=\"%s\")", 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 }