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