1 /*
2 ** Copyright 2003-2004 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5
6 /* $Id: maildirkw.c,v 1.2 2004/05/08 02:24:22 mrsam Exp $ */
7
8 #if HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <errno.h>
15
16 #if HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19 #include <sys/stat.h>
20 #include "maildirkeywords.h"
21 #include "maildirwatch.h"
22
usage()23 static void usage()
24 {
25 printf("Usage: maildirkw [ options ] maildir [+/-]flag [+/-]flag...\n");
26 exit(1);
27 }
28
doit_locked(const char * maildir,const char * filename,int lockflag,int plusminus,char ** argv,int optind,int argc)29 static int doit_locked(const char *maildir,
30 const char *filename,
31 int lockflag, int plusminus,
32 char **argv,
33 int optind, int argc)
34 {
35 char *tmpname, *newname;
36
37 if (!plusminus)
38 {
39 struct libmail_kwHashtable kwh;
40 struct libmail_kwMessage *kwm;
41
42 struct libmail_kwGeneric g;
43 int rc;
44
45 libmail_kwgInit(&g);
46
47 /* Make sure courierimapkeywords directory exists */
48
49 libmail_kwEnabled=0;
50 rc=libmail_kwgReadMaildir(&g, maildir);
51 libmail_kwEnabled=1;
52 libmail_kwgDestroy(&g);
53
54 if (rc)
55 return -1;
56
57
58 libmail_kwhInit(&kwh);
59
60 if (!(kwm=libmail_kwmCreate()))
61 {
62 perror("libmail_kwmCreate");
63 return -1;
64 }
65
66 while (optind < argc)
67 if (libmail_kwmSetName(&kwh, kwm,
68 argv[optind++]) < 0)
69 {
70 libmail_kwmDestroy(kwm);
71 perror("libmail_kwmSetName");
72 return -1;
73 }
74
75 if (maildir_kwSave(maildir, filename, kwm,
76 &tmpname, &newname, 0) < 0)
77 {
78 perror(maildir);
79 libmail_kwmDestroy(kwm);
80 return -1;
81 }
82 libmail_kwmDestroy(kwm);
83
84 if (rename(tmpname, newname) < 0)
85 {
86 perror(newname);
87 free(tmpname);
88 free(newname);
89 return -1;
90 }
91 free(tmpname);
92 free(newname);
93 return 0;
94 }
95 else
96 {
97 struct libmail_kwGeneric g;
98 int rc;
99 struct libmail_kwGenericEntry *e;
100 struct libmail_kwMessage *kwm, *kwm_alloced;
101
102 libmail_kwgInit(&g);
103
104 rc=libmail_kwgReadMaildir(&g, maildir);
105
106 if (rc != 0)
107 return rc;
108
109 e=libmail_kwgFindByName(&g, filename);
110
111 kwm_alloced=NULL;
112
113 if (e && e->keywords)
114 kwm=e->keywords;
115 else
116 {
117 if ((kwm=kwm_alloced=libmail_kwmCreate()) == NULL)
118 {
119 perror("libmail_kwmCreate");
120 libmail_kwgDestroy(&g);
121 return -1;
122 }
123 }
124
125 while (optind < argc)
126 {
127 const char *f=argv[optind++];
128
129 if ( plusminus == '+')
130 {
131 if (libmail_kwmSetName(&g.kwHashTable,
132 kwm, f) < 0)
133 {
134 perror("libmail_kwmSetName");
135 if (kwm_alloced)
136 libmail_kwmDestroy(kwm_alloced
137 );
138 libmail_kwgDestroy(&g);
139 return -1;
140 }
141 } else
142 {
143 struct libmail_keywordEntry *kwe=
144 libmail_kweFind(&g.kwHashTable,
145 f, 0);
146
147 if (kwe)
148 libmail_kwmClear(kwm, kwe);
149 }
150 }
151
152 rc=maildir_kwSave(maildir, filename, kwm,
153 &tmpname, &newname, 1);
154
155 if (rc == 0)
156 {
157 if (link(tmpname, newname) == 0)
158 {
159 struct stat stat_buf;
160
161 if (stat(tmpname, &stat_buf) == 0 &&
162 stat_buf.st_nlink == 2)
163 unlink(tmpname);
164 else
165 rc=1; /* What's up? */
166 }
167 else
168 {
169 if (errno == EEXIST)
170 rc=1;
171 else
172 rc= -1;
173 unlink(tmpname);
174 }
175 }
176
177 if (kwm_alloced)
178 libmail_kwmDestroy(kwm_alloced);
179 libmail_kwgDestroy(&g);
180
181 return rc;
182 }
183 }
184
list_locked(const char * maildir)185 static int list_locked(const char *maildir)
186 {
187 struct libmail_kwGeneric g;
188 int rc;
189 size_t n;
190
191 libmail_kwgInit(&g);
192
193 rc=libmail_kwgReadMaildir(&g, maildir);
194
195 if (rc)
196 return rc;
197
198 for (n=0; n<g.nMessages; n++)
199 {
200 struct libmail_kwGenericEntry *e=
201 libmail_kwgFindByIndex(&g, n);
202 struct libmail_kwMessageEntry *k;
203
204 if (!e)
205 continue;
206
207 printf("%s", e->filename);
208
209 for (k=e->keywords ? e->keywords->firstEntry:NULL; k;
210 k=k->next)
211 printf(" %s", keywordName(k->libmail_keywordEntryPtr));
212 printf("\n");
213 }
214 return 0;
215 }
216
doit(const char * maildir,const char * filename,int lockflag,int plusminus,char ** argv,int optind,int argc)217 static int doit(const char *maildir, const char *filename, int lockflag,
218 int plusminus,
219 char **argv, int optind, int argc)
220 {
221 if (lockflag)
222 {
223 struct maildirwatch *w=maildirwatch_alloc(maildir);
224 int tryAnyway;
225 char *lockname;
226 int rc;
227
228 if (!w)
229 {
230 perror(maildir);
231 return -1;
232 }
233
234 lockname=maildir_lock(maildir, w, &tryAnyway);
235
236 if (!lockname)
237 {
238 perror(maildir);
239 if (!tryAnyway)
240 {
241 maildirwatch_free(w);
242 maildirwatch_cleanup();
243 return -1;
244 }
245 }
246
247 rc=doit_locked(maildir, filename, 1, plusminus,
248 argv, optind, argc);
249 if (lockname)
250 {
251 unlink(lockname);
252 free(lockname);
253 }
254 maildirwatch_free(w);
255 maildirwatch_cleanup();
256 return rc;
257 }
258
259 return doit_locked(maildir, filename, 0, plusminus,
260 argv, optind, argc);
261 }
262
dolist(const char * maildir,int lockflag)263 static int dolist(const char *maildir, int lockflag)
264 {
265 if (lockflag)
266 {
267 struct maildirwatch *w=maildirwatch_alloc(maildir);
268 int tryAnyway;
269 char *lockname;
270 int rc;
271
272 if (!w)
273 {
274 perror(maildir);
275 return -1;
276 }
277
278 lockname=maildir_lock(maildir, w, &tryAnyway);
279
280 if (!lockname)
281 {
282 perror(maildir);
283 if (!tryAnyway)
284 {
285 maildirwatch_free(w);
286 maildirwatch_cleanup();
287 return -1;
288 }
289 }
290
291 rc=list_locked(maildir);
292 if (lockname)
293 {
294 unlink(lockname);
295 free(lockname);
296 }
297 maildirwatch_free(w);
298 maildirwatch_cleanup();
299 return rc;
300 }
301
302 return list_locked(maildir);
303 }
304
main(int argc,char * argv[])305 int main(int argc, char *argv[])
306 {
307 int lockflag=0;
308 int optc;
309 const char *maildir;
310 const char *filename;
311 int list=0;
312 int plusminus=0;
313 int n;
314
315 libmail_kwCaseSensitive=0;
316
317 while ((optc=getopt(argc, argv, "arLlhc")) != -1)
318 switch (optc) {
319 case 'c':
320 libmail_kwCaseSensitive=1;
321 break;
322 case 'l':
323 lockflag=1;
324 break;
325 case 'L':
326 list=1;
327 break;
328 case 'a':
329 plusminus='+';
330 break;
331 case 'r':
332 plusminus='-';
333 break;
334 default:
335 usage();
336 }
337
338 if (optind >= argc)
339 usage();
340
341 maildir=argv[optind++];
342
343 if (list)
344 {
345 exit (dolist(maildir, lockflag));
346 }
347
348 if (optind >= argc)
349 usage();
350
351 filename=argv[optind++];
352
353 while ((n=doit(maildir, filename, lockflag, plusminus,
354 argv, optind, argc)) > 0)
355 ;
356
357 exit(-n);
358 return (0);
359 }
360