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