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