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