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