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