1 /*
2 ** Copyright 2000-2007 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5 
6 #if HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9 
10 #include <sys/types.h>
11 #if HAVE_DIRENT_H
12 #include <dirent.h>
13 #define NAMLEN(dirent) strlen((dirent)->d_name)
14 #else
15 #define dirent direct
16 #define NAMLEN(dirent) (dirent)->d_namlen
17 #if HAVE_SYS_NDIR_H
18 #include <sys/ndir.h>
19 #endif
20 #if HAVE_SYS_DIR_H
21 #include <sys/dir.h>
22 #endif
23 #if HAVE_NDIR_H
24 #include <ndir.h>
25 #endif
26 #endif
27 #include	<sys/types.h>
28 #include	<sys/stat.h>
29 #include	<string.h>
30 #include	<stdlib.h>
31 #include	<time.h>
32 #if	HAVE_UNISTD_H
33 #include	<unistd.h>
34 #endif
35 #include	<stdio.h>
36 #include	<ctype.h>
37 #include	<errno.h>
38 #include	<fcntl.h>
39 
40 #include	"maildirmisc.h"
41 #include	"maildircreate.h"
42 #include	"maildirsharedrc.h"
43 
44 static const char rcsid[]="$Id: maildirshared.c,v 1.23 2007/04/16 22:31:53 mrsam Exp $";
45 
46 /* Prerequisited for shared folder support */
47 
48 #if	HAVE_READLINK
49 #if	HAVE_SYMLINK
50 #if	HAVE_DBOBJ
51 
52 #define	YES_WE_CAN_DO_SHARED	1
53 
54 #endif
55 #endif
56 #endif
57 
58 #if	YES_WE_CAN_DO_SHARED
59 
60 #include	"dbobj.h"
61 
62 static void list_sharable(const char *, const char *,
63 	void (*)(const char *, void *),
64 	void *);
65 
66 extern FILE *maildir_shared_fopen(const char *, const char *);
67 extern void maildir_shared_fparse(char *, char **, char **);
68 
maildir_list_sharable(const char * maildir,void (* func)(const char *,void *),void * voidp)69 void maildir_list_sharable(const char *maildir,
70 	void (*func)(const char *, void *),
71 	void *voidp)
72 {
73 char	buf[BUFSIZ];
74 FILE	*fp;
75 char	*p;
76 int	pass;
77 
78 	if (!maildir)	maildir=".";
79 
80 	for (pass=0; pass<2; pass++)
81 	{
82 		fp=pass ? maildir_shared_fopen(maildir, "r")
83 			: fopen (MAILDIRSHAREDRC, "r");
84 
85 		if (!fp)	continue;
86 
87 		while ((p=fgets(buf, sizeof(buf), fp)) != 0)
88 		{
89 		char	*name, *dir;
90 
91 			maildir_shared_fparse(p, &name, &dir);
92 			if (name)
93 				list_sharable(name, dir, func, voidp);
94 		}
95 		fclose(fp);
96 	}
97 }
98 
list_sharable(const char * pfix,const char * path,void (* func)(const char *,void *),void * voidp)99 static void list_sharable(const char *pfix, const char *path,
100 	void (*func)(const char *, void *),
101 	void *voidp)
102 {
103 DIR	*dirp;
104 struct	dirent *de;
105 struct	stat	stat_buf;
106 
107 	dirp=opendir(path);
108 	while (dirp && (de=readdir(dirp)) != 0)
109 	{
110 	char	*z;
111 
112 		if (de->d_name[0] != '.')	continue;
113 		if (strcmp(de->d_name, ".") == 0 ||
114 			strcmp(de->d_name, "..") == 0)	continue;
115 
116 		z=malloc(strlen(path)+strlen(de->d_name)+12);
117 		if (!z)	continue;
118 
119 		strcat(strcat(strcat(strcpy(z, path),
120 			"/"), de->d_name), "/cur/.");
121 
122 		if (stat(z, &stat_buf))
123 		{
124 			free(z);
125 			continue;
126 		}
127 		free(z);
128 		z=malloc(strlen(pfix)+strlen(de->d_name)+1);
129 		if (!z)	continue;
130 		strcat(strcpy(z, pfix), de->d_name);
131 		(*func)(z, voidp);
132 		free(z);
133 	}
134 	if (dirp)	closedir(dirp);
135 }
136 
maildir_shared_subscribe(const char * maildir,const char * folder)137 int maildir_shared_subscribe(const char *maildir, const char *folder)
138 {
139 char	linebuf[BUFSIZ];
140 FILE	*fp;
141 char	*p;
142 char	*name=strchr(folder, '.');
143 char	*s, *n, *dir;
144 char	*buf, *link;
145 unsigned l;
146 int	pass;
147 
148 	if (!name)
149 	{
150 		errno=EINVAL;
151 		return (-1);
152 	}
153 
154 	if (!maildir)	maildir=".";
155 	p=maildir_shareddir(maildir, folder);	/* valid folder name? */
156 	if (!p)
157 	{
158 		errno=EINVAL;
159 		return (-1);
160 	}
161 	free(p);
162 
163 	p=0;
164 
165 	for (pass=0; pass<2; pass++)
166 	{
167 		fp=pass ? maildir_shared_fopen(maildir, "r")
168 			: fopen (MAILDIRSHAREDRC, "r");
169 
170 		if (!fp)	continue;
171 
172 		while ((p=fgets(linebuf, sizeof(linebuf), fp)) != 0)
173 		{
174 			maildir_shared_fparse(p, &n, &dir);
175 
176 			if (!n)	continue;
177 
178 			if (strlen(n) == name - folder &&
179 				memcmp(n, folder, name-folder) == 0)	break;
180 		}
181 		fclose(fp);
182 
183 		if (p)	break;
184 	}
185 
186 	if (p)
187 	{
188 		/*
189 		** We will create:
190 		**
191 		**  maildir/shared-folders/ (name-folder) /(name)
192 		**
193 		**  there we'll have subdirs cur/new/tmp  and shared link
194 		*/
195 
196 		l=sizeof("/" SHAREDSUBDIR "//shared") +
197 			strlen(maildir) + strlen(folder);
198 		buf=malloc(l);
199 		if (!buf)	return (-1);
200 		strcat(strcpy(buf, maildir), "/" SHAREDSUBDIR);
201 		mkdir(buf, 0700);
202 		strcat(buf, "/");
203 		strncat(buf, folder, name-folder);
204 		mkdir(buf, 0700);
205 		strcat(buf, "/");
206 		strcat(buf, name+1);
207 		if ( mkdir(buf, 0700))	return (-1);
208 		s=buf+strlen(buf);
209 		*s++='/';
210 		strcpy(s, "tmp");
211 		if ( mkdir(buf, 0700))
212 		{
213 			s[-1]=0;
214 			rmdir(buf);
215 			free(buf);
216 			return (-1);
217 		}
218 		strcpy(s, "cur");
219 		if ( mkdir(buf, 0700))
220 		{
221 			strcpy(s, "tmp");
222 			rmdir(buf);
223 			s[-1]=0;
224 			rmdir(buf);
225 			free(buf);
226 			return (-1);
227 		}
228 		strcpy(s, "new");
229 		if ( mkdir(buf, 0700))
230 		{
231 			strcpy(s, "cur");
232 			rmdir(buf);
233 			strcpy(s, "tmp");
234 			rmdir(buf);
235 			s[-1]=0;
236 			rmdir(buf);
237 			free(buf);
238 			return (-1);
239 		}
240 
241 		strcpy(s, "shared");
242 		if ((link=malloc(strlen(dir)+strlen(name)+2)) == 0 ||
243 			symlink( strcat(strcat(strcpy(link, dir), "/"), name),
244 				buf))
245 		{
246 			if (link)	free(link);
247 			strcpy(s, "new");
248 			rmdir(buf);
249 			strcpy(s, "cur");
250 			rmdir(buf);
251 			strcpy(s, "tmp");
252 			rmdir(buf);
253 			s[-1]=0;
254 			rmdir(buf);
255 			free(buf);
256 			return (-1);
257 		}
258 		free(link);
259 		free(buf);
260 		return (0);
261 	}
262 	errno=ENOENT;
263 	return (-1);
264 }
265 
maildir_list_shared(const char * maildir,void (* func)(const char *,void *),void * voidp)266 void maildir_list_shared(const char *maildir,
267 	void (*func)(const char *, void *),
268 	void *voidp)
269 {
270 char	*sh;
271 DIR	*dirp;
272 struct	dirent *de;
273 
274 	if (!maildir)	maildir=".";
275 	sh=malloc(strlen(maildir)+sizeof("/" SHAREDSUBDIR));
276 	if (!sh)	return;
277 
278 	strcat(strcpy(sh, maildir), "/" SHAREDSUBDIR);
279 
280 	dirp=opendir(sh);
281 	while (dirp && (de=readdir(dirp)) != 0)
282 	{
283 	DIR	*dirp2;
284 	struct	dirent *de2;
285 	char	*z;
286 
287 		if (de->d_name[0] == '.')	continue;
288 
289 		z=malloc(strlen(sh)+strlen(de->d_name)+2);
290 		if (!z)	continue;
291 		strcat(strcat(strcpy(z, sh), "/"), de->d_name);
292 		dirp2=opendir(z);
293 		free(z);
294 
295 		while (dirp2 && (de2=readdir(dirp2)) != 0)
296 		{
297 		char	*s;
298 
299 			if (de2->d_name[0] == '.')	continue;
300 			s=malloc(strlen(de->d_name)+strlen(de2->d_name)+2);
301 			if (!s)	continue;
302 			strcat(strcat(strcpy(s, de->d_name), "."), de2->d_name);
303 			(*func)(s, voidp);
304 			free(s);
305 		}
306 		if (dirp2)	closedir(dirp2);
307 	}
308 	free(sh);
309 	if (dirp)	closedir(dirp);
310 }
311 
maildir_shared_unsubscribe(const char * maildir,const char * folder)312 int maildir_shared_unsubscribe(const char *maildir, const char *folder)
313 {
314 char	*s;
315 
316 	s=maildir_shareddir(maildir, folder);
317 	if (!s)	return (-1);
318 
319 	if (maildir_del(s))
320 	{
321 		free(s);
322 		return (-1);
323 	}
324 	*strrchr(s, '/')=0;	/* Try to remove the whole folder dir */
325 	rmdir(s);
326 	free(s);
327 	return (0);
328 }
329 
330 /*                    LET'S SYNC IT                  */
331 
332 static void do_maildir_shared_sync(const char *, const char *);
333 
maildir_shared_sync(const char * dir)334 void maildir_shared_sync(const char *dir)
335 {
336 char	*shareddir;
337 char	*buf;
338 
339 	shareddir=malloc(strlen(dir)+sizeof("/shared"));
340 	if (!shareddir)
341 	{
342 		perror("malloc");
343 		return;
344 	}
345 	strcat(strcpy(shareddir, dir),"/shared");
346 
347 	buf=maildir_getlink(shareddir);
348 	free(shareddir);
349 	if (buf)
350 	{
351 		do_maildir_shared_sync(dir, buf);
352 		free(buf);
353 	}
354 }
355 
356 /* Step 1 - safely create a temporary database */
357 
create_db(struct dbobj * obj,const char * dir,char ** dbname)358 static int create_db(struct dbobj *obj,
359 	const char *dir,
360 	char **dbname)
361 {
362 	struct maildir_tmpcreate_info createInfo;
363 
364 	maildir_tmpcreate_init(&createInfo);
365 
366 	createInfo.maildir=dir;
367 	createInfo.uniq="sync";
368 	createInfo.doordie=1;
369 
370 	{
371 		int	fd;
372 
373 		fd=maildir_tmpcreate_fd(&createInfo);
374 
375 		if (fd < 0)
376 		{
377 			perror(dir);
378 			return -1;
379 		}
380 		close(fd);
381 
382 		dbobj_init(obj);
383 		if (dbobj_open(obj, createInfo.tmpname, "N") < 0)
384 		{
385 			perror(createInfo.tmpname);
386 			unlink(createInfo.tmpname);
387 			maildir_tmpcreate_free(&createInfo);
388 			return (-1);
389 		}
390 	}
391 
392 	*dbname=createInfo.tmpname;
393 	createInfo.tmpname=NULL;
394 	maildir_tmpcreate_free(&createInfo);
395 	return (0);
396 }
397 
398 /*
399 ** Populate the DB by building the db with the messages in the sharable
400 ** folder's cur.  The key is the stripped message filename, the value is
401 ** the complete message filename.
402 */
403 
build_db(const char * shared,struct dbobj * obj)404 static int build_db(const char *shared, struct dbobj *obj)
405 {
406 char	*dummy=malloc(strlen(shared)+sizeof("/cur"));
407 DIR	*dirp;
408 struct	dirent *de;
409 
410 	if (!dummy)
411 	{
412 		perror("malloc");
413 		return (-1);
414 	}
415 
416 	strcat(strcpy(dummy, shared), "/cur");
417 
418 	dirp=opendir(dummy);
419 	while (dirp && (de=readdir(dirp)) != 0)
420 	{
421 	char	*a, *b;
422 	char	*c;
423 
424 		if (de->d_name[0] == '.')
425 			continue;
426 		if ((a=malloc(strlen(de->d_name)+1)) == 0)
427 		{
428 			perror("malloc");
429 			closedir(dirp);
430 			free(dummy);
431 			return (-1);
432 		}
433 		if ((b=malloc(strlen(de->d_name)+1)) == 0)
434 		{
435 			perror("malloc");
436 			closedir(dirp);
437 			free(dummy);
438 			free(a);
439 			return (-1);
440 		}
441 		strcpy(a, de->d_name);
442 		strcpy(b, de->d_name);
443 		c=strrchr(a, MDIRSEP[0]);
444 		if (c)	*c=0;
445 
446 		if (dbobj_store(obj, a, strlen(a), b, strlen(b), "R"))
447 		{
448 			perror("dbobj_store");
449 			free(a);
450 			free(b);
451 			closedir(dirp);
452 			free(dummy);
453 			return (-1);
454 		}
455 		free(a);
456 		free(b);
457 	}
458 	if (dirp)	closedir(dirp);
459 	free(dummy);
460 	return (0);
461 }
462 
463 static int update_link(const char *,
464 	const char *, const char *,
465 	const char *,
466 	const char *,
467 	size_t);
468 
469 /*
470 **	Now, read our synced cur directory, and make sure that the soft
471 **	links are up to date.  Remove messages that have been deleted from
472 **	the sharable maildir, and make sure that the remaining links are
473 **	valid.
474 */
475 
update_cur(const char * cur,const char * shared,struct dbobj * obj)476 static int update_cur(const char *cur, const char *shared, struct dbobj *obj)
477 {
478 DIR	*dirp;
479 struct	dirent *de;
480 char	*p;
481 
482 	dirp=opendir(cur);
483 	while (dirp && (de=readdir(dirp)) != 0)
484 	{
485 	char	*cur_base;
486 
487 	char	*cur_name_ptr;
488 	size_t	cur_name_len;
489 
490 	char	*linked_name_buf;
491 	size_t	linked_name_len;
492 	int	n;
493 
494 		if (de->d_name[0] == '.')	continue;
495 
496 		/*
497 		** Strip the maildir flags, and look up the message in the
498 		** db.
499 		*/
500 
501 		cur_base=malloc(strlen(de->d_name)+1);
502 		if (!cur_base)
503 		{
504 			perror("malloc");
505 			closedir(dirp);
506 			return (-1);
507 		}
508 		strcpy(cur_base, de->d_name);
509 		p=strrchr(cur_base, MDIRSEP[0]);
510 		if (p)	*p=0;
511 
512 		cur_name_ptr=dbobj_fetch(obj, cur_base, strlen(cur_base),
513 			&cur_name_len, "");
514 
515 		/* If it's there, delete the db entry. */
516 
517 		if (cur_name_ptr)
518 			dbobj_delete(obj, cur_base, strlen(cur_base));
519 
520 		/*
521 		** We'll either delete this soft link, or check its
522 		** contents, so we better build its complete pathname in
523 		** any case.
524 		*/
525 
526 		free(cur_base);
527 		cur_base=malloc(strlen(de->d_name)+strlen(cur)+2);
528 		if (!cur_base)
529 		{
530 			perror("malloc");
531 			if (cur_name_ptr)	free(cur_name_ptr);
532 			closedir(dirp);
533 			return (-1);
534 		}
535 		strcat(strcat(strcpy(cur_base, cur), "/"), de->d_name);
536 
537 		if (!cur_name_ptr)	/* Removed from sharable dir */
538 		{
539 			unlink(cur_base);
540 			free(cur_base);
541 			continue;
542 		}
543 
544 		linked_name_len=strlen(shared)+strlen(de->d_name)+100;
545 			/* should be enough */
546 
547 		if ((linked_name_buf=malloc(linked_name_len)) == 0)
548 		{
549 			perror("malloc");
550 			free(cur_base);
551 			free(cur_name_ptr);
552 			closedir(dirp);
553 			return (-1);
554 		}
555 
556 		if ((n=readlink(cur_base, linked_name_buf, linked_name_len))< 0)
557 		{
558 			/* This is stupid, let's just unlink this nonsense */
559 
560 			n=0;
561 		}
562 
563 		if (n == 0 || n >= linked_name_len ||
564 			(linked_name_buf[n]=0,
565 			update_link(cur,
566 				cur_base, linked_name_buf, shared, cur_name_ptr,
567 				cur_name_len)))
568 		{
569 			unlink(cur_base);
570 			free(linked_name_buf);
571 			free(cur_base);
572 			free(cur_name_ptr);
573 			closedir(dirp);
574 			return (-1);
575 		}
576 		free(cur_base);
577 		free(linked_name_buf);
578 		free(cur_name_ptr);
579 	}
580 	if (dirp)	closedir(dirp);
581 	return (0);
582 }
583 
584 /* Update the link pointer */
585 
update_link(const char * curdir,const char * linkname,const char * linkvalue,const char * shareddir,const char * msgfilename,size_t msgfilenamelen)586 static int update_link(const char *curdir,
587 	const char *linkname, const char *linkvalue,
588 	const char *shareddir,
589 	const char *msgfilename,
590 	size_t msgfilenamelen)
591 {
592 	char	*p=malloc(strlen(shareddir)+sizeof("/cur/")+msgfilenamelen);
593 	char	*q;
594 	int	fd;
595 	struct maildir_tmpcreate_info createInfo;
596 
597 	if (!p)
598 	{
599 		perror("malloc");
600 		return (-1);
601 	}
602 
603 	strcat(strcpy(p, shareddir), "/cur/");
604 	q=p+strlen(p);
605 	memcpy(q, msgfilename, msgfilenamelen);
606 	q[msgfilenamelen]=0;
607 
608 	if (linkvalue && strcmp(p, linkvalue) == 0)
609 	{
610 		/* the link is good */
611 
612 		free(p);
613 		return (0);
614 	}
615 
616 	/* Ok, we want this to be an atomic operation. */
617 
618 	maildir_tmpcreate_init(&createInfo);
619 	createInfo.maildir=curdir;
620 	createInfo.uniq="relink";
621 	createInfo.doordie=1;
622 
623 	if ((fd=maildir_tmpcreate_fd(&createInfo)) < 0)
624 		return -1;
625 
626 	close(fd);
627 	unlink(createInfo.tmpname);
628 
629 	if (symlink(p, createInfo.tmpname) < 0 ||
630 	    rename(createInfo.tmpname, linkname) < 0)
631 	{
632 		perror(createInfo.tmpname);
633 		maildir_tmpcreate_free(&createInfo);
634 		return (-1);
635 	}
636 
637 	maildir_tmpcreate_free(&createInfo);
638 	return (0);
639 }
640 
641 /* and now, anything that's left in the temporary db must be new messages */
642 
newmsgs(const char * cur,const char * shared,struct dbobj * obj)643 static int newmsgs(const char *cur, const char *shared, struct dbobj *obj)
644 {
645 	char	*key, *val;
646 	size_t	keylen, vallen;
647 	int fd;
648 	struct maildir_tmpcreate_info createInfo;
649 
650 	maildir_tmpcreate_init(&createInfo);
651 	createInfo.maildir=cur;
652 	createInfo.uniq="newlink";
653 	createInfo.doordie=1;
654 
655 	if ((fd=maildir_tmpcreate_fd(&createInfo)) < 0)
656 		return -1;
657 	close(fd);
658 
659 	unlink(createInfo.tmpname);
660 
661 	for (key=dbobj_firstkey(obj, &keylen, &val, &vallen); key;
662 		key=dbobj_nextkey(obj, &keylen, &val, &vallen))
663 	{
664 	char	*slink=malloc(strlen(shared)+sizeof("/cur/")+vallen);
665 	char	*q;
666 
667 		if (!slink)
668 		{
669 			free(val);
670 			maildir_tmpcreate_free(&createInfo);
671 			return (-1);
672 		}
673 
674 		strcat(strcpy(slink, shared), "/cur/");
675 		q=slink+strlen(slink);
676 		memcpy(q, val, vallen);
677 		q[vallen]=0;
678 		free(val);
679 
680 		if (symlink(slink, createInfo.tmpname))
681 		{
682 			perror(createInfo.tmpname);
683 
684 			free(slink);
685 			maildir_tmpcreate_free(&createInfo);
686 			return (-1);
687 		}
688 
689 		free(slink);
690 		slink=malloc(strlen(cur)+sizeof("/new/" MDIRSEP "2,")+keylen);
691 		if (!slink)
692 		{
693 			perror("malloc");
694 			maildir_tmpcreate_free(&createInfo);
695 			return (-1);
696 		}
697 
698 		strcat(strcpy(slink, cur), "/new/");
699 		q=slink+strlen(slink);
700 		memcpy(q, key, keylen);
701 		strcpy(q+keylen, MDIRSEP "2,");
702 
703 		if (rename(createInfo.tmpname, slink))
704 		{
705 			free(slink);
706 			maildir_tmpcreate_free(&createInfo);
707 			return (-1);
708 		}
709 		free(slink);
710 	}
711 	maildir_tmpcreate_free(&createInfo);
712 	return (0);
713 }
714 
do_maildir_shared_sync(const char * dir,const char * shared)715 static void do_maildir_shared_sync(const char *dir, const char *shared)
716 {
717 struct	dbobj obj;
718 char	*dbname;
719 char	*cur;
720 char	*shared_update_name;
721 
722 struct	stat	stat1, stat2;
723 int	fd;
724 
725 	maildir_purgetmp(dir);	/* clean up after myself */
726 	maildir_getnew(dir, 0, NULL, NULL);
727 
728 	maildir_purgetmp(shared);
729 	maildir_getnew(shared, 0, NULL, NULL);
730 
731 	/* Figure out if we REALLY need to sync something */
732 
733 	shared_update_name=malloc(strlen(dir)+sizeof("/shared-timestamp"));
734 	if (!shared_update_name)	return;
735 	strcat(strcpy(shared_update_name, dir), "/shared-timestamp");
736 	cur=malloc(strlen(shared)+sizeof("/new"));
737 	if (!cur)
738 	{
739 		free(shared_update_name);
740 		return;
741 	}
742 
743 	if (stat(shared_update_name, &stat1) == 0)
744 	{
745 		if ( stat( strcat(strcpy(cur, shared), "/new"), &stat2) == 0 &&
746 			stat2.st_mtime < stat1.st_mtime &&
747 			stat( strcat(strcpy(cur, shared), "/cur"), &stat2)
748 			== 0 && stat2.st_mtime < stat1.st_mtime)
749 		{
750 			free(shared_update_name);
751 			free(cur);
752 			return;
753 		}
754 	}
755 	if ((fd=maildir_safeopen(shared_update_name, O_RDWR|O_CREAT, 0600))>= 0)
756 	{
757 		if (write(fd, "", 1) < 0)
758 			perror("write");
759 		close(fd);
760 	}
761 
762 	free(cur);
763 	free(shared_update_name);
764 
765 	if (create_db(&obj, dir, &dbname))	return;
766 
767 	if (build_db(shared, &obj))
768 	{
769 		dbobj_close(&obj);
770 		unlink(dbname);
771 		free(dbname);
772 		return;
773 	}
774 
775 	if ((cur=malloc(strlen(dir)+sizeof("/cur"))) == 0)
776 	{
777 		perror("malloc");
778 		dbobj_close(&obj);
779 		unlink(dbname);
780 		free(dbname);
781 		return;
782 	}
783 	strcat(strcpy(cur, dir), "/cur");
784 	if (update_cur(cur, shared, &obj) == 0)
785 	{
786 		strcat(strcpy(cur, dir), "/new");
787 		if (update_cur(cur, shared, &obj) == 0)
788 		{
789 			*strrchr(cur, '/')=0;	/* Chop off the /new */
790 			newmsgs(cur, shared, &obj);
791 		}
792 	}
793 
794 	free(cur);
795 	dbobj_close(&obj);
796 	unlink(dbname);
797 	free(dbname);
798 }
799 
maildir_sharedisro(const char * maildir)800 int maildir_sharedisro(const char *maildir)
801 {
802 char	*p=malloc(strlen(maildir)+sizeof("/shared/cur"));
803 
804 	if (!p)
805 	{
806 		perror("malloc");
807 		return (-1);
808 	}
809 	strcat(strcpy(p, maildir), "/shared/cur");
810 
811 	if (access(p, W_OK) == 0)
812 	{
813 		free(p);
814 		return (0);
815 	}
816 	free(p);
817 	return (1);
818 }
819 
maildir_unlinksharedmsg(const char * filename)820 int maildir_unlinksharedmsg(const char *filename)
821 {
822 char	*buf=maildir_getlink(filename);
823 
824 	if (buf)
825 	{
826 		struct stat stat_buf;
827 		int rc=unlink(buf);
828 
829 		/*
830 		** If we FAILED to unlink the real message in the real
831 		** sharable folder, but the message still exists, it means
832 		** that we do not have the permission to do so, so do not
833 		** purge this folder.  Instead, remove the T flag from
834 		** this message.
835 		*/
836 
837 		if (rc && stat(buf, &stat_buf) == 0)
838 		{
839 			char *cpy=strdup(filename);
840 
841 			if (cpy)
842 			{
843 				char *p=strrchr(cpy, MDIRSEP[0]);
844 
845 				if (p && strchr(p, '/') == 0 &&
846 				    strncmp(p, MDIRSEP "2,", 3) == 0 &&
847 				    (p=strchr(p, 'T')) != 0)
848 				{
849 					while ((*p=p[1]) != 0)
850 						++p;
851 					rename(filename, cpy);
852 				}
853 				free(cpy);
854 			}
855 
856 			free(buf);
857 			return (0);
858 		}
859 		free(buf);
860 	}
861 	unlink(filename);
862 	return (0);
863 }
864 
865 
866 #else
867 
868 /* We cannot implement sharing */
869 
maildir_list_sharable(const char * maildir,void (* func)(const char *,void *),void * voidp)870 void maildir_list_sharable(const char *maildir,
871 	void (*func)(const char *, void *),
872 	void *voidp)
873 {
874 }
875 
maildir_shared_subscribe(const char * maildir,const char * folder)876 int maildir_shared_subscribe(const char *maildir, const char *folder)
877 {
878 	errno=EINVAL;
879 	return (-1);
880 }
881 
maildir_list_shared(const char * maildir,void (* func)(const char *,void *),void * voidp)882 void maildir_list_shared(const char *maildir,
883 	void (*func)(const char *, void *),
884 	void *voidp)
885 {
886 }
887 
maildir_shared_unsubscribe(const char * maildir,const char * folder)888 int maildir_shared_unsubscribe(const char *maildir, const char *folder)
889 {
890 	errno=EINVAL;
891 	return (-1);
892 }
893 
894 #if 0
895 char *maildir_shareddir(const char *maildir, const char *sharedname)
896 {
897 	errno=EINVAL;
898 	return (0);
899 }
900 #endif
901 
maildir_shared_sync(const char * maildir)902 void maildir_shared_sync(const char *maildir)
903 {
904 }
905 
maildir_sharedisro(const char * maildir)906 int maildir_sharedisro(const char *maildir)
907 {
908 	return (-1);
909 }
910 
maildir_unlinksharedmsg(const char * filename)911 int maildir_unlinksharedmsg(const char *filename)
912 {
913 	return (-1);
914 }
915 #endif
916