summaryrefslogtreecommitdiff
path: root/libproto/mbox/folder.c
diff options
context:
space:
mode:
Diffstat (limited to 'libproto/mbox/folder.c')
-rw-r--r--libproto/mbox/folder.c517
1 files changed, 13 insertions, 504 deletions
diff --git a/libproto/mbox/folder.c b/libproto/mbox/folder.c
index 2cc23bb64..9e2c3f1cb 100644
--- a/libproto/mbox/folder.c
+++ b/libproto/mbox/folder.c
@@ -49,19 +49,23 @@ static int
_mbox_is_scheme (mu_record_t record, mu_url_t url, int flags)
{
int rc = 0;
-
- if (mu_url_is_scheme (url, record->scheme))
- return MU_FOLDER_ATTRIBUTE_FILE & flags;
-
- if (mu_scheme_autodetect_p (url))
+ int scheme_matched = mu_url_is_scheme (url, record->scheme);
+ if (scheme_matched || mu_scheme_autodetect_p (url))
{
struct stat st;
const char *path;
mu_url_sget_path (url, &path);
if (stat (path, &st) < 0)
- return 0;
-
+ {
+ if (errno == ENOENT)
+ {
+ if (scheme_matched)
+ return MU_FOLDER_ATTRIBUTE_FILE & flags;
+ }
+ return 0;
+ }
+
if (S_ISREG (st.st_mode) || S_ISCHR (st.st_mode))
{
if (st.st_size == 0)
@@ -71,7 +75,7 @@ _mbox_is_scheme (mu_record_t record, mu_url_t url, int flags)
else if (flags & MU_FOLDER_ATTRIBUTE_FILE)
{
#if 0
- /* This effectively sieves out all non-mailbox files,
+ /* FIXME: This effectively sieves out all non-mailbox files,
but it makes mu_folder_enumerate crawl, which is
intolerable for imap4d LIST command. */
int fd = open (path, O_RDONLY);
@@ -106,7 +110,7 @@ static struct _mu_record _mbox_record =
mu_url_expand_path, /* URL init. */
_mailbox_mbox_init, /* Mailbox init. */
NULL, /* Mailer init. */
- _folder_mbox_init, /* Folder init. */
+ _mu_fsfolder_init, /* Folder init. */
NULL, /* No need for an back pointer. */
_mbox_is_scheme, /* _is_scheme method. */
NULL, /* _get_url method. */
@@ -116,499 +120,4 @@ static struct _mu_record _mbox_record =
};
mu_record_t mu_mbox_record = &_mbox_record;
-/* lsub/subscribe/unsubscribe are not needed. */
-static void folder_mbox_destroy (mu_folder_t);
-static int folder_mbox_open (mu_folder_t, int);
-static int folder_mbox_close (mu_folder_t);
-static int folder_mbox_delete (mu_folder_t, const char *);
-static int folder_mbox_rename (mu_folder_t , const char *, const char *);
-static int folder_mbox_list (mu_folder_t, const char *, void *, int,
- size_t, mu_list_t, mu_folder_enumerate_fp,
- void *);
-static int folder_mbox_subscribe (mu_folder_t, const char *);
-static int folder_mbox_unsubscribe (mu_folder_t, const char *);
-static int folder_mbox_lsub (mu_folder_t, const char *, const char *,
- mu_list_t);
-
-
-static char *get_pathname (const char *, const char *);
-
-static int folder_mbox_get_authority (mu_folder_t folder, mu_authority_t * pauth);
-
-struct _fmbox
-{
- char *dirname;
- char **subscribe;
- size_t sublen;
-};
-typedef struct _fmbox *fmbox_t;
-
-
-int
-_folder_mbox_init (mu_folder_t folder)
-{
- fmbox_t dfolder;
- int status = 0;
-
- /* We create an authority so the API is uniform across the mailbox
- types. */
- status = folder_mbox_get_authority (folder, NULL);
- if (status != 0)
- return status;
-
- dfolder = folder->data = calloc (1, sizeof (*dfolder));
- if (dfolder == NULL)
- return ENOMEM;
-
- status = mu_url_aget_path (folder->url, &dfolder->dirname);
- if (status == MU_ERR_NOENT)
- {
- dfolder->dirname = malloc (2);
- if (dfolder->dirname == NULL)
- status = ENOMEM;
- else
- {
- strcpy (dfolder->dirname, ".");
- status = 0;
- }
- }
-
- if (status)
- {
- free (dfolder);
- folder->data = NULL;
- return status;
- }
-
- folder->_destroy = folder_mbox_destroy;
-
- folder->_open = folder_mbox_open;
- folder->_close = folder_mbox_close;
-
- folder->_list = folder_mbox_list;
- folder->_lsub = folder_mbox_lsub;
- folder->_subscribe = folder_mbox_subscribe;
- folder->_unsubscribe = folder_mbox_unsubscribe;
- folder->_delete = folder_mbox_delete;
- folder->_rename = folder_mbox_rename;
- return 0;
-}
-
-void
-folder_mbox_destroy (mu_folder_t folder)
-{
- if (folder->data)
- {
- fmbox_t fmbox = folder->data;
- if (fmbox->dirname)
- free (fmbox->dirname);
- if (fmbox->subscribe)
- free (fmbox->subscribe);
- free (folder->data);
- folder->data = NULL;
- }
-}
-
-/* Noop. */
-static int
-folder_mbox_open (mu_folder_t folder, int flags MU_ARG_UNUSED)
-{
- fmbox_t fmbox = folder->data;
- if (flags & MU_STREAM_CREAT)
- {
- return (mkdir (fmbox->dirname, S_IRWXU) == 0) ? 0 : errno;
- }
- return 0;
-}
-
-/* Noop. */
-static int
-folder_mbox_close (mu_folder_t folder MU_ARG_UNUSED)
-{
- return 0;
-}
-
-static int
-folder_mbox_delete (mu_folder_t folder, const char *filename)
-{
- fmbox_t fmbox = folder->data;
- if (filename)
- {
- int status = 0;
- char *pathname = get_pathname (fmbox->dirname, filename);
- if (pathname)
- {
- if (remove (pathname) != 0)
- status = errno;
- free (pathname);
- }
- else
- status = ENOMEM;
- return status;
- }
- return EINVAL;
-}
-
-static int
-folder_mbox_rename (mu_folder_t folder, const char *oldpath,
- const char *newpath)
-{
- fmbox_t fmbox = folder->data;
- if (oldpath && newpath)
- {
- int status = 0;
- char *pathold = get_pathname (fmbox->dirname, oldpath);
- if (pathold)
- {
- char *pathnew = get_pathname (fmbox->dirname, newpath);
- if (pathnew)
- {
- if (rename (pathold, pathnew) != 0)
- status = errno;
- free (pathnew);
- }
- else
- status = ENOMEM;
- free (pathold);
- }
- else
- status = ENOMEM;
- return status;
- }
- return EINVAL;
-}
-
-struct inode_list /* Inode/dev number list used to cut off
- recursion */
-{
- struct inode_list *next;
- ino_t inode;
- dev_t dev;
-};
-
-struct search_data
-{
- mu_list_t result;
- mu_folder_enumerate_fp enumfun;
- void *enumdata;
- char *dirname;
- size_t dirlen;
- void *pattern;
- int flags;
- size_t max_level;
- size_t errcnt;
- mu_folder_t folder;
-};
-
-static int
-inode_list_lookup (struct inode_list *list, struct stat *st)
-{
- for (; list; list = list->next)
- if (list->inode == st->st_ino && list->dev == st->st_dev)
- return 1;
- return 0;
-}
-
-static int
-list_helper (struct search_data *data, mu_record_t record,
- const char *dirname, size_t level,
- struct inode_list *ilist)
-{
- DIR *dirp;
- struct dirent *dp;
- int stop = 0;
-
- if (data->max_level && level > data->max_level)
- return 0;
-
- dirp = opendir (dirname);
- if (dirp == NULL)
- {
- mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
- ("list_helper cannot open directory %s: %s",
- dirname, mu_strerror (errno)));
- data->errcnt++;
- return 1;
- }
-
- if (!record)
- {
- int type;
- mu_registrar_lookup (dirname, MU_FOLDER_ATTRIBUTE_ALL,
- &record, &type);
- }
-
- while ((dp = readdir (dirp)))
- {
- char const *ename = dp->d_name;
- char *fname;
- struct stat st;
-
- if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0)
- continue;
- fname = get_pathname (dirname, ename);
- if (lstat (fname, &st) == 0)
- {
- int f;
- if (S_ISDIR (st.st_mode))
- f = MU_FOLDER_ATTRIBUTE_DIRECTORY;
- else if (S_ISREG (st.st_mode))
- f = MU_FOLDER_ATTRIBUTE_FILE;
- else if (S_ISLNK (st.st_mode))
- f = MU_FOLDER_ATTRIBUTE_LINK;
- else
- f = 0;
- if (mu_record_list_p (record, ename, f))
- {
- if (data->folder->_match == NULL
- || data->folder->_match (fname + data->dirlen +
- ((data->dirlen > 1
- && data->dirname[data->dirlen-1] != '/') ?
- 1 : 0),
- data->pattern,
- data->flags) == 0)
- {
- char *refname = fname;
- int type = 0;
- struct mu_list_response *resp;
- mu_record_t rec = NULL;
-
- resp = malloc (sizeof (*resp));
- if (resp == NULL)
- {
- mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
- ("list_helper: %s", mu_strerror (ENOMEM)));
- data->errcnt++;
- free (fname);
- continue;
- }
-
- mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL,
- &rec, &type);
-
- resp->name = fname;
- resp->level = level;
- resp->separator = '/';
- resp->type = type;
- resp->format = rec;
-
- if (resp->type == 0)
- {
- free (resp->name);
- free (resp);
- continue;
- }
-
- if (data->enumfun)
- {
- if (data->enumfun (data->folder, resp, data->enumdata))
- {
- free (resp->name);
- free (resp);
- stop = 1;
- break;
- }
- }
-
- if (data->result)
- {
- fname = NULL;
- mu_list_append (data->result, resp);
- }
- else
- free (resp);
-
- if ((type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
- && !inode_list_lookup (ilist, &st))
- {
- struct inode_list idata;
-
- idata.inode = st.st_ino;
- idata.dev = st.st_dev;
- idata.next = ilist;
- stop = list_helper (data, rec, refname, level + 1,
- &idata);
- }
- }
- else if (S_ISDIR (st.st_mode))
- {
- struct inode_list idata;
-
- idata.inode = st.st_ino;
- idata.dev = st.st_dev;
- idata.next = ilist;
- stop = list_helper (data, NULL, fname, level + 1, &idata);
- }
- }
- }
- else
- {
- mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
- ("list_helper cannot stat %s: %s",
- fname, mu_strerror (errno)));
- }
- free (fname);
- }
- closedir (dirp);
- return stop;
-}
-
-static int
-folder_mbox_list (mu_folder_t folder, const char *ref,
- void *pattern,
- int flags,
- size_t max_level,
- mu_list_t flist,
- mu_folder_enumerate_fp enumfun, void *enumdata)
-{
- fmbox_t fmbox = folder->data;
- struct inode_list iroot;
- struct search_data sdata;
-
- memset (&iroot, 0, sizeof iroot);
- sdata.dirname = get_pathname (fmbox->dirname, ref);
- sdata.dirlen = strlen (sdata.dirname);
- sdata.result = flist;
- sdata.enumfun = enumfun;
- sdata.enumdata = enumdata;
- sdata.pattern = pattern;
- sdata.flags = flags;
- sdata.max_level = max_level;
- sdata.folder = folder;
- sdata.errcnt = 0;
- list_helper (&sdata, NULL, sdata.dirname, 0, &iroot);
- free (sdata.dirname);
- /* FIXME: error code */
- return 0;
-}
-
-static int
-folder_mbox_lsub (mu_folder_t folder, const char *ref MU_ARG_UNUSED,
- const char *name,
- mu_list_t flist)
-{
- fmbox_t fmbox = folder->data;
- int status;
-
- if (name == NULL || *name == '\0')
- name = "*";
-
- if (fmbox->sublen > 0)
- {
- size_t i;
-
- for (i = 0; i < fmbox->sublen; i++)
- {
- if (fmbox->subscribe[i]
- && fnmatch (name, fmbox->subscribe[i], 0) == 0)
- {
- struct mu_list_response *resp;
- resp = malloc (sizeof (*resp));
- if (resp == NULL)
- {
- status = ENOMEM;
- break;
- }
- else if ((resp->name = strdup (fmbox->subscribe[i])) == NULL)
- {
- free (resp);
- status = ENOMEM;
- break;
- }
- resp->type = MU_FOLDER_ATTRIBUTE_FILE;
- resp->level = 0;
- resp->separator = '/';
- }
- }
- }
- return status;
-}
-
-static int
-folder_mbox_subscribe (mu_folder_t folder, const char *name)
-{
- fmbox_t fmbox = folder->data;
- char **tmp;
- size_t i;
- for (i = 0; i < fmbox->sublen; i++)
- {
- if (fmbox->subscribe[i] && strcmp (fmbox->subscribe[i], name) == 0)
- return 0;
- }
- tmp = realloc (fmbox->subscribe, (fmbox->sublen + 1) * sizeof (*tmp));
- if (tmp == NULL)
- return ENOMEM;
- fmbox->subscribe = tmp;
- fmbox->subscribe[fmbox->sublen] = strdup (name);
- if (fmbox->subscribe[fmbox->sublen] == NULL)
- return ENOMEM;
- fmbox->sublen++;
- return 0;
-}
-
-static int
-folder_mbox_unsubscribe (mu_folder_t folder, const char *name)
-{
- fmbox_t fmbox = folder->data;
- size_t i;
- for (i = 0; i < fmbox->sublen; i++)
- {
- if (fmbox->subscribe[i] && strcmp (fmbox->subscribe[i], name) == 0)
- {
- free (fmbox->subscribe[i]);
- fmbox->subscribe[i] = NULL;
- return 0;
- }
- }
- return MU_ERR_NOENT;
-}
-
-static char *
-get_pathname (const char *dirname, const char *basename)
-{
- char *pathname = NULL;
-
- /* Skip eventual protocol designator.
- FIXME: Actually, any valid URL spec should be allowed as dirname ... */
- if (strncmp (dirname, MU_MBOX_SCHEME, MU_MBOX_SCHEME_LEN) == 0)
- dirname += MU_MBOX_SCHEME_LEN;
- else if (strncmp (dirname, MU_FILE_SCHEME, MU_FILE_SCHEME_LEN) == 0)
- dirname += MU_FILE_SCHEME_LEN;
-
- /* null basename gives dirname. */
- if (basename == NULL)
- pathname = (dirname) ? strdup (dirname) : strdup (".");
- /* Absolute. */
- else if (basename[0] == '/')
- pathname = strdup (basename);
- /* Relative. */
- else
- {
- size_t baselen = strlen (basename);
- size_t dirlen = strlen (dirname);
- while (dirlen > 0 && dirname[dirlen-1] == '/')
- dirlen--;
- pathname = calloc (dirlen + baselen + 2, sizeof (char));
- if (pathname)
- {
- memcpy (pathname, dirname, dirlen);
- pathname[dirlen] = '/';
- strcpy (pathname + dirlen + 1, basename);
- }
- }
- return pathname;
-}
-
-static int
-folder_mbox_get_authority (mu_folder_t folder, mu_authority_t *pauth)
-{
- int status = 0;
- if (folder->authority == NULL)
- {
- status = mu_authority_create_null (&folder->authority, folder);
- }
- if (!status && pauth)
- *pauth = folder->authority;
- return status;
-}

Return to:

Send suggestions and report system problems to the System administrator.