summaryrefslogtreecommitdiffstats
path: root/maildir/maildirshared.c
diff options
context:
space:
mode:
authorSam Varshavchik2013-08-19 16:39:41 -0400
committerSam Varshavchik2013-08-25 14:43:51 -0400
commit9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch)
tree7a81a04cb51efb078ee350859a64be2ebc6b8813 /maildir/maildirshared.c
parenta9520698b770168d1f33d6301463bb70a19655ec (diff)
downloadcourier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2
Initial checkin
Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'maildir/maildirshared.c')
-rw-r--r--maildir/maildirshared.c914
1 files changed, 914 insertions, 0 deletions
diff --git a/maildir/maildirshared.c b/maildir/maildirshared.c
new file mode 100644
index 0000000..7123ce6
--- /dev/null
+++ b/maildir/maildirshared.c
@@ -0,0 +1,914 @@
+/*
+** Copyright 2000-2007 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+#define dirent direct
+#define NAMLEN(dirent) (dirent)->d_namlen
+#if HAVE_SYS_NDIR_H
+#include <sys/ndir.h>
+#endif
+#if HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif
+#if HAVE_NDIR_H
+#include <ndir.h>
+#endif
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "maildirmisc.h"
+#include "maildircreate.h"
+#include "maildirsharedrc.h"
+
+
+/* Prerequisited for shared folder support */
+
+#if HAVE_READLINK
+#if HAVE_SYMLINK
+#if HAVE_DBOBJ
+
+#define YES_WE_CAN_DO_SHARED 1
+
+#endif
+#endif
+#endif
+
+#if YES_WE_CAN_DO_SHARED
+
+#include "dbobj.h"
+
+static void list_sharable(const char *, const char *,
+ void (*)(const char *, void *),
+ void *);
+
+extern FILE *maildir_shared_fopen(const char *, const char *);
+extern void maildir_shared_fparse(char *, char **, char **);
+
+void maildir_list_sharable(const char *maildir,
+ void (*func)(const char *, void *),
+ void *voidp)
+{
+char buf[BUFSIZ];
+FILE *fp;
+char *p;
+int pass;
+
+ if (!maildir) maildir=".";
+
+ for (pass=0; pass<2; pass++)
+ {
+ fp=pass ? maildir_shared_fopen(maildir, "r")
+ : fopen (MAILDIRSHAREDRC, "r");
+
+ if (!fp) continue;
+
+ while ((p=fgets(buf, sizeof(buf), fp)) != 0)
+ {
+ char *name, *dir;
+
+ maildir_shared_fparse(p, &name, &dir);
+ if (name)
+ list_sharable(name, dir, func, voidp);
+ }
+ fclose(fp);
+ }
+}
+
+static void list_sharable(const char *pfix, const char *path,
+ void (*func)(const char *, void *),
+ void *voidp)
+{
+DIR *dirp;
+struct dirent *de;
+struct stat stat_buf;
+
+ dirp=opendir(path);
+ while (dirp && (de=readdir(dirp)) != 0)
+ {
+ char *z;
+
+ if (de->d_name[0] != '.') continue;
+ if (strcmp(de->d_name, ".") == 0 ||
+ strcmp(de->d_name, "..") == 0) continue;
+
+ z=malloc(strlen(path)+strlen(de->d_name)+12);
+ if (!z) continue;
+
+ strcat(strcat(strcat(strcpy(z, path),
+ "/"), de->d_name), "/cur/.");
+
+ if (stat(z, &stat_buf))
+ {
+ free(z);
+ continue;
+ }
+ free(z);
+ z=malloc(strlen(pfix)+strlen(de->d_name)+1);
+ if (!z) continue;
+ strcat(strcpy(z, pfix), de->d_name);
+ (*func)(z, voidp);
+ free(z);
+ }
+ if (dirp) closedir(dirp);
+}
+
+int maildir_shared_subscribe(const char *maildir, const char *folder)
+{
+char linebuf[BUFSIZ];
+FILE *fp;
+char *p;
+char *name=strchr(folder, '.');
+char *s, *n, *dir;
+char *buf, *link;
+unsigned l;
+int pass;
+
+ if (!name)
+ {
+ errno=EINVAL;
+ return (-1);
+ }
+
+ if (!maildir) maildir=".";
+ p=maildir_shareddir(maildir, folder); /* valid folder name? */
+ if (!p)
+ {
+ errno=EINVAL;
+ return (-1);
+ }
+ free(p);
+
+ p=0;
+
+ for (pass=0; pass<2; pass++)
+ {
+ fp=pass ? maildir_shared_fopen(maildir, "r")
+ : fopen (MAILDIRSHAREDRC, "r");
+
+ if (!fp) continue;
+
+ while ((p=fgets(linebuf, sizeof(linebuf), fp)) != 0)
+ {
+ maildir_shared_fparse(p, &n, &dir);
+
+ if (!n) continue;
+
+ if (strlen(n) == name - folder &&
+ memcmp(n, folder, name-folder) == 0) break;
+ }
+ fclose(fp);
+
+ if (p) break;
+ }
+
+ if (p)
+ {
+ /*
+ ** We will create:
+ **
+ ** maildir/shared-folders/ (name-folder) /(name)
+ **
+ ** there we'll have subdirs cur/new/tmp and shared link
+ */
+
+ l=sizeof("/" SHAREDSUBDIR "//shared") +
+ strlen(maildir) + strlen(folder);
+ buf=malloc(l);
+ if (!buf) return (-1);
+ strcat(strcpy(buf, maildir), "/" SHAREDSUBDIR);
+ mkdir(buf, 0700);
+ strcat(buf, "/");
+ strncat(buf, folder, name-folder);
+ mkdir(buf, 0700);
+ strcat(buf, "/");
+ strcat(buf, name+1);
+ if ( mkdir(buf, 0700)) return (-1);
+ s=buf+strlen(buf);
+ *s++='/';
+ strcpy(s, "tmp");
+ if ( mkdir(buf, 0700))
+ {
+ s[-1]=0;
+ rmdir(buf);
+ free(buf);
+ return (-1);
+ }
+ strcpy(s, "cur");
+ if ( mkdir(buf, 0700))
+ {
+ strcpy(s, "tmp");
+ rmdir(buf);
+ s[-1]=0;
+ rmdir(buf);
+ free(buf);
+ return (-1);
+ }
+ strcpy(s, "new");
+ if ( mkdir(buf, 0700))
+ {
+ strcpy(s, "cur");
+ rmdir(buf);
+ strcpy(s, "tmp");
+ rmdir(buf);
+ s[-1]=0;
+ rmdir(buf);
+ free(buf);
+ return (-1);
+ }
+
+ strcpy(s, "shared");
+ if ((link=malloc(strlen(dir)+strlen(name)+2)) == 0 ||
+ symlink( strcat(strcat(strcpy(link, dir), "/"), name),
+ buf))
+ {
+ if (link) free(link);
+ strcpy(s, "new");
+ rmdir(buf);
+ strcpy(s, "cur");
+ rmdir(buf);
+ strcpy(s, "tmp");
+ rmdir(buf);
+ s[-1]=0;
+ rmdir(buf);
+ free(buf);
+ return (-1);
+ }
+ free(link);
+ free(buf);
+ return (0);
+ }
+ errno=ENOENT;
+ return (-1);
+}
+
+void maildir_list_shared(const char *maildir,
+ void (*func)(const char *, void *),
+ void *voidp)
+{
+char *sh;
+DIR *dirp;
+struct dirent *de;
+
+ if (!maildir) maildir=".";
+ sh=malloc(strlen(maildir)+sizeof("/" SHAREDSUBDIR));
+ if (!sh) return;
+
+ strcat(strcpy(sh, maildir), "/" SHAREDSUBDIR);
+
+ dirp=opendir(sh);
+ while (dirp && (de=readdir(dirp)) != 0)
+ {
+ DIR *dirp2;
+ struct dirent *de2;
+ char *z;
+
+ if (de->d_name[0] == '.') continue;
+
+ z=malloc(strlen(sh)+strlen(de->d_name)+2);
+ if (!z) continue;
+ strcat(strcat(strcpy(z, sh), "/"), de->d_name);
+ dirp2=opendir(z);
+ free(z);
+
+ while (dirp2 && (de2=readdir(dirp2)) != 0)
+ {
+ char *s;
+
+ if (de2->d_name[0] == '.') continue;
+ s=malloc(strlen(de->d_name)+strlen(de2->d_name)+2);
+ if (!s) continue;
+ strcat(strcat(strcpy(s, de->d_name), "."), de2->d_name);
+ (*func)(s, voidp);
+ free(s);
+ }
+ if (dirp2) closedir(dirp2);
+ }
+ free(sh);
+ if (dirp) closedir(dirp);
+}
+
+int maildir_shared_unsubscribe(const char *maildir, const char *folder)
+{
+char *s;
+
+ s=maildir_shareddir(maildir, folder);
+ if (!s) return (-1);
+
+ if (maildir_del(s))
+ {
+ free(s);
+ return (-1);
+ }
+ *strrchr(s, '/')=0; /* Try to remove the whole folder dir */
+ rmdir(s);
+ free(s);
+ return (0);
+}
+
+/* LET'S SYNC IT */
+
+static void do_maildir_shared_sync(const char *, const char *);
+
+void maildir_shared_sync(const char *dir)
+{
+char *shareddir;
+char *buf;
+
+ shareddir=malloc(strlen(dir)+sizeof("/shared"));
+ if (!shareddir)
+ {
+ perror("malloc");
+ return;
+ }
+ strcat(strcpy(shareddir, dir),"/shared");
+
+ buf=maildir_getlink(shareddir);
+ free(shareddir);
+ if (buf)
+ {
+ do_maildir_shared_sync(dir, buf);
+ free(buf);
+ }
+}
+
+/* Step 1 - safely create a temporary database */
+
+static int create_db(struct dbobj *obj,
+ const char *dir,
+ char **dbname)
+{
+ struct maildir_tmpcreate_info createInfo;
+
+ maildir_tmpcreate_init(&createInfo);
+
+ createInfo.maildir=dir;
+ createInfo.uniq="sync";
+ createInfo.doordie=1;
+
+ {
+ int fd;
+
+ fd=maildir_tmpcreate_fd(&createInfo);
+
+ if (fd < 0)
+ {
+ perror(dir);
+ return -1;
+ }
+ close(fd);
+
+ dbobj_init(obj);
+ if (dbobj_open(obj, createInfo.tmpname, "N") < 0)
+ {
+ perror(createInfo.tmpname);
+ unlink(createInfo.tmpname);
+ maildir_tmpcreate_free(&createInfo);
+ return (-1);
+ }
+ }
+
+ *dbname=createInfo.tmpname;
+ createInfo.tmpname=NULL;
+ maildir_tmpcreate_free(&createInfo);
+ return (0);
+}
+
+/*
+** Populate the DB by building the db with the messages in the sharable
+** folder's cur. The key is the stripped message filename, the value is
+** the complete message filename.
+*/
+
+static int build_db(const char *shared, struct dbobj *obj)
+{
+char *dummy=malloc(strlen(shared)+sizeof("/cur"));
+DIR *dirp;
+struct dirent *de;
+
+ if (!dummy)
+ {
+ perror("malloc");
+ return (-1);
+ }
+
+ strcat(strcpy(dummy, shared), "/cur");
+
+ dirp=opendir(dummy);
+ while (dirp && (de=readdir(dirp)) != 0)
+ {
+ char *a, *b;
+ char *c;
+
+ if (de->d_name[0] == '.')
+ continue;
+ if ((a=malloc(strlen(de->d_name)+1)) == 0)
+ {
+ perror("malloc");
+ closedir(dirp);
+ free(dummy);
+ return (-1);
+ }
+ if ((b=malloc(strlen(de->d_name)+1)) == 0)
+ {
+ perror("malloc");
+ closedir(dirp);
+ free(dummy);
+ free(a);
+ return (-1);
+ }
+ strcpy(a, de->d_name);
+ strcpy(b, de->d_name);
+ c=strrchr(a, MDIRSEP[0]);
+ if (c) *c=0;
+
+ if (dbobj_store(obj, a, strlen(a), b, strlen(b), "R"))
+ {
+ perror("dbobj_store");
+ free(a);
+ free(b);
+ closedir(dirp);
+ free(dummy);
+ return (-1);
+ }
+ free(a);
+ free(b);
+ }
+ if (dirp) closedir(dirp);
+ free(dummy);
+ return (0);
+}
+
+static int update_link(const char *,
+ const char *, const char *,
+ const char *,
+ const char *,
+ size_t);
+
+/*
+** Now, read our synced cur directory, and make sure that the soft
+** links are up to date. Remove messages that have been deleted from
+** the sharable maildir, and make sure that the remaining links are
+** valid.
+*/
+
+static int update_cur(const char *cur, const char *shared, struct dbobj *obj)
+{
+DIR *dirp;
+struct dirent *de;
+char *p;
+
+ dirp=opendir(cur);
+ while (dirp && (de=readdir(dirp)) != 0)
+ {
+ char *cur_base;
+
+ char *cur_name_ptr;
+ size_t cur_name_len;
+
+ char *linked_name_buf;
+ size_t linked_name_len;
+ int n;
+
+ if (de->d_name[0] == '.') continue;
+
+ /*
+ ** Strip the maildir flags, and look up the message in the
+ ** db.
+ */
+
+ cur_base=malloc(strlen(de->d_name)+1);
+ if (!cur_base)
+ {
+ perror("malloc");
+ closedir(dirp);
+ return (-1);
+ }
+ strcpy(cur_base, de->d_name);
+ p=strrchr(cur_base, MDIRSEP[0]);
+ if (p) *p=0;
+
+ cur_name_ptr=dbobj_fetch(obj, cur_base, strlen(cur_base),
+ &cur_name_len, "");
+
+ /* If it's there, delete the db entry. */
+
+ if (cur_name_ptr)
+ dbobj_delete(obj, cur_base, strlen(cur_base));
+
+ /*
+ ** We'll either delete this soft link, or check its
+ ** contents, so we better build its complete pathname in
+ ** any case.
+ */
+
+ free(cur_base);
+ cur_base=malloc(strlen(de->d_name)+strlen(cur)+2);
+ if (!cur_base)
+ {
+ perror("malloc");
+ if (cur_name_ptr) free(cur_name_ptr);
+ closedir(dirp);
+ return (-1);
+ }
+ strcat(strcat(strcpy(cur_base, cur), "/"), de->d_name);
+
+ if (!cur_name_ptr) /* Removed from sharable dir */
+ {
+ unlink(cur_base);
+ free(cur_base);
+ continue;
+ }
+
+ linked_name_len=strlen(shared)+strlen(de->d_name)+100;
+ /* should be enough */
+
+ if ((linked_name_buf=malloc(linked_name_len)) == 0)
+ {
+ perror("malloc");
+ free(cur_base);
+ free(cur_name_ptr);
+ closedir(dirp);
+ return (-1);
+ }
+
+ if ((n=readlink(cur_base, linked_name_buf, linked_name_len))< 0)
+ {
+ /* This is stupid, let's just unlink this nonsense */
+
+ n=0;
+ }
+
+ if (n == 0 || n >= linked_name_len ||
+ (linked_name_buf[n]=0,
+ update_link(cur,
+ cur_base, linked_name_buf, shared, cur_name_ptr,
+ cur_name_len)))
+ {
+ unlink(cur_base);
+ free(linked_name_buf);
+ free(cur_base);
+ free(cur_name_ptr);
+ closedir(dirp);
+ return (-1);
+ }
+ free(cur_base);
+ free(linked_name_buf);
+ free(cur_name_ptr);
+ }
+ if (dirp) closedir(dirp);
+ return (0);
+}
+
+/* Update the link pointer */
+
+static int update_link(const char *curdir,
+ const char *linkname, const char *linkvalue,
+ const char *shareddir,
+ const char *msgfilename,
+ size_t msgfilenamelen)
+{
+ char *p=malloc(strlen(shareddir)+sizeof("/cur/")+msgfilenamelen);
+ char *q;
+ int fd;
+ struct maildir_tmpcreate_info createInfo;
+
+ if (!p)
+ {
+ perror("malloc");
+ return (-1);
+ }
+
+ strcat(strcpy(p, shareddir), "/cur/");
+ q=p+strlen(p);
+ memcpy(q, msgfilename, msgfilenamelen);
+ q[msgfilenamelen]=0;
+
+ if (linkvalue && strcmp(p, linkvalue) == 0)
+ {
+ /* the link is good */
+
+ free(p);
+ return (0);
+ }
+
+ /* Ok, we want this to be an atomic operation. */
+
+ maildir_tmpcreate_init(&createInfo);
+ createInfo.maildir=curdir;
+ createInfo.uniq="relink";
+ createInfo.doordie=1;
+
+ if ((fd=maildir_tmpcreate_fd(&createInfo)) < 0)
+ return -1;
+
+ close(fd);
+ unlink(createInfo.tmpname);
+
+ if (symlink(p, createInfo.tmpname) < 0 ||
+ rename(createInfo.tmpname, linkname) < 0)
+ {
+ perror(createInfo.tmpname);
+ maildir_tmpcreate_free(&createInfo);
+ return (-1);
+ }
+
+ maildir_tmpcreate_free(&createInfo);
+ return (0);
+}
+
+/* and now, anything that's left in the temporary db must be new messages */
+
+static int newmsgs(const char *cur, const char *shared, struct dbobj *obj)
+{
+ char *key, *val;
+ size_t keylen, vallen;
+ int fd;
+ struct maildir_tmpcreate_info createInfo;
+
+ maildir_tmpcreate_init(&createInfo);
+ createInfo.maildir=cur;
+ createInfo.uniq="newlink";
+ createInfo.doordie=1;
+
+ if ((fd=maildir_tmpcreate_fd(&createInfo)) < 0)
+ return -1;
+ close(fd);
+
+ unlink(createInfo.tmpname);
+
+ for (key=dbobj_firstkey(obj, &keylen, &val, &vallen); key;
+ key=dbobj_nextkey(obj, &keylen, &val, &vallen))
+ {
+ char *slink=malloc(strlen(shared)+sizeof("/cur/")+vallen);
+ char *q;
+
+ if (!slink)
+ {
+ free(val);
+ maildir_tmpcreate_free(&createInfo);
+ return (-1);
+ }
+
+ strcat(strcpy(slink, shared), "/cur/");
+ q=slink+strlen(slink);
+ memcpy(q, val, vallen);
+ q[vallen]=0;
+ free(val);
+
+ if (symlink(slink, createInfo.tmpname))
+ {
+ perror(createInfo.tmpname);
+
+ free(slink);
+ maildir_tmpcreate_free(&createInfo);
+ return (-1);
+ }
+
+ free(slink);
+ slink=malloc(strlen(cur)+sizeof("/new/" MDIRSEP "2,")+keylen);
+ if (!slink)
+ {
+ perror("malloc");
+ maildir_tmpcreate_free(&createInfo);
+ return (-1);
+ }
+
+ strcat(strcpy(slink, cur), "/new/");
+ q=slink+strlen(slink);
+ memcpy(q, key, keylen);
+ strcpy(q+keylen, MDIRSEP "2,");
+
+ if (rename(createInfo.tmpname, slink))
+ {
+ free(slink);
+ maildir_tmpcreate_free(&createInfo);
+ return (-1);
+ }
+ free(slink);
+ }
+ maildir_tmpcreate_free(&createInfo);
+ return (0);
+}
+
+static void do_maildir_shared_sync(const char *dir, const char *shared)
+{
+struct dbobj obj;
+char *dbname;
+char *cur;
+char *shared_update_name;
+
+struct stat stat1, stat2;
+int fd;
+
+ maildir_purgetmp(dir); /* clean up after myself */
+ maildir_getnew(dir, 0, NULL, NULL);
+
+ maildir_purgetmp(shared);
+ maildir_getnew(shared, 0, NULL, NULL);
+
+ /* Figure out if we REALLY need to sync something */
+
+ shared_update_name=malloc(strlen(dir)+sizeof("/shared-timestamp"));
+ if (!shared_update_name) return;
+ strcat(strcpy(shared_update_name, dir), "/shared-timestamp");
+ cur=malloc(strlen(shared)+sizeof("/new"));
+ if (!cur)
+ {
+ free(shared_update_name);
+ return;
+ }
+
+ if (stat(shared_update_name, &stat1) == 0)
+ {
+ if ( stat( strcat(strcpy(cur, shared), "/new"), &stat2) == 0 &&
+ stat2.st_mtime < stat1.st_mtime &&
+ stat( strcat(strcpy(cur, shared), "/cur"), &stat2)
+ == 0 && stat2.st_mtime < stat1.st_mtime)
+ {
+ free(shared_update_name);
+ free(cur);
+ return;
+ }
+ }
+ if ((fd=maildir_safeopen(shared_update_name, O_RDWR|O_CREAT, 0600))>= 0)
+ {
+ if (write(fd, "", 1) < 0)
+ perror("write");
+ close(fd);
+ }
+
+ free(cur);
+ free(shared_update_name);
+
+ if (create_db(&obj, dir, &dbname)) return;
+
+ if (build_db(shared, &obj))
+ {
+ dbobj_close(&obj);
+ unlink(dbname);
+ free(dbname);
+ return;
+ }
+
+ if ((cur=malloc(strlen(dir)+sizeof("/cur"))) == 0)
+ {
+ perror("malloc");
+ dbobj_close(&obj);
+ unlink(dbname);
+ free(dbname);
+ return;
+ }
+ strcat(strcpy(cur, dir), "/cur");
+ if (update_cur(cur, shared, &obj) == 0)
+ {
+ strcat(strcpy(cur, dir), "/new");
+ if (update_cur(cur, shared, &obj) == 0)
+ {
+ *strrchr(cur, '/')=0; /* Chop off the /new */
+ newmsgs(cur, shared, &obj);
+ }
+ }
+
+ free(cur);
+ dbobj_close(&obj);
+ unlink(dbname);
+ free(dbname);
+}
+
+int maildir_sharedisro(const char *maildir)
+{
+char *p=malloc(strlen(maildir)+sizeof("/shared/cur"));
+
+ if (!p)
+ {
+ perror("malloc");
+ return (-1);
+ }
+ strcat(strcpy(p, maildir), "/shared/cur");
+
+ if (access(p, W_OK) == 0)
+ {
+ free(p);
+ return (0);
+ }
+ free(p);
+ return (1);
+}
+
+int maildir_unlinksharedmsg(const char *filename)
+{
+char *buf=maildir_getlink(filename);
+
+ if (buf)
+ {
+ struct stat stat_buf;
+ int rc=unlink(buf);
+
+ /*
+ ** If we FAILED to unlink the real message in the real
+ ** sharable folder, but the message still exists, it means
+ ** that we do not have the permission to do so, so do not
+ ** purge this folder. Instead, remove the T flag from
+ ** this message.
+ */
+
+ if (rc && stat(buf, &stat_buf) == 0)
+ {
+ char *cpy=strdup(filename);
+
+ if (cpy)
+ {
+ char *p=strrchr(cpy, MDIRSEP[0]);
+
+ if (p && strchr(p, '/') == 0 &&
+ strncmp(p, MDIRSEP "2,", 3) == 0 &&
+ (p=strchr(p, 'T')) != 0)
+ {
+ while ((*p=p[1]) != 0)
+ ++p;
+ rename(filename, cpy);
+ }
+ free(cpy);
+ }
+
+ free(buf);
+ return (0);
+ }
+ free(buf);
+ }
+ unlink(filename);
+ return (0);
+}
+
+
+#else
+
+/* We cannot implement sharing */
+
+void maildir_list_sharable(const char *maildir,
+ void (*func)(const char *, void *),
+ void *voidp)
+{
+}
+
+int maildir_shared_subscribe(const char *maildir, const char *folder)
+{
+ errno=EINVAL;
+ return (-1);
+}
+
+void maildir_list_shared(const char *maildir,
+ void (*func)(const char *, void *),
+ void *voidp)
+{
+}
+
+int maildir_shared_unsubscribe(const char *maildir, const char *folder)
+{
+ errno=EINVAL;
+ return (-1);
+}
+
+#if 0
+char *maildir_shareddir(const char *maildir, const char *sharedname)
+{
+ errno=EINVAL;
+ return (0);
+}
+#endif
+
+void maildir_shared_sync(const char *maildir)
+{
+}
+
+int maildir_sharedisro(const char *maildir)
+{
+ return (-1);
+}
+
+int maildir_unlinksharedmsg(const char *filename)
+{
+ return (-1);
+}
+#endif