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