Commit b9ef5553 b9ef5553104e1125d305c828017394c40941b19a by Sergey Poznyakoff

* examples/lsf.c: Use mu_folder_enumerate + callback function, for

speed up.
* imap4d/imap4d.h (WCARD_NOMATCH,WCARD_MATCH)
(WCARD_RECURSE_MATCH): Remove.
* imap4d/list.c: Rewrite using mu_folder_enumerate.
* imap4d/lsub.c (imap4d_lsub): Fix call to util_wcard_match.
* imap4d/util.c (util_wcard_match): Return 0 for match, 1
otherwise.
* imap4d/testsuite/imap4d/list.exp: Fix two testcases to match
the new (stricter RFC-compliant) behavior.
* include/mailutils/folder.h (mu_folder_match_fp): New typedef.
(mu_folder_enumerate_fp): New typedef.
(mu_folder_enumerate): New function.
(mu_folder_set_match, mu_folder_get_match): New functions.

* libproto/imap/folder.c, libproto/include/imap0.h,
libproto/nntp/folder.c : Use new folder list framework.
* libproto/include/folder0.h (struct _mu_folder._list): Change
signature.
(_match): New member.
* libproto/mbox/folder.c (_path_is_scheme): Improve automatic
mailbox	format detection.
(folder_mbox_list): Do not use glob, recursively scan
subdirectories instead.
* mailbox/folder.c (mu_folder_match): New function.
(mu_folder_create_from_record): Set mu_folder_match as the default
matcher.
(mu_folder_set_match, mu_folder_get_match): New functions.
(mu_folder_enumerate): New function.
(mu_folder_list): Rewrite using mu_folder_enumerate.
1 parent 6d490ce1
2007-12-21 Sergey Poznyakoff <gray@gnu.org.ua>
* examples/lsf.c: Use mu_folder_enumerate + callback function, for
speed up.
* imap4d/imap4d.h (WCARD_NOMATCH,WCARD_MATCH)
(WCARD_RECURSE_MATCH): Remove.
* imap4d/list.c: Rewrite using mu_folder_enumerate.
* imap4d/lsub.c (imap4d_lsub): Fix call to util_wcard_match.
* imap4d/util.c (util_wcard_match): Return 0 for match, 1
otherwise.
* imap4d/testsuite/imap4d/list.exp: Fix two testcases to match
the new (stricter RFC-compliant) behavior.
* include/mailutils/folder.h (mu_folder_match_fp): New typedef.
(mu_folder_enumerate_fp): New typedef.
(mu_folder_enumerate): New function.
(mu_folder_set_match, mu_folder_get_match): New functions.
* libproto/imap/folder.c, libproto/include/imap0.h,
libproto/nntp/folder.c : Use new folder list framework.
* libproto/include/folder0.h (struct _mu_folder._list): Change
signature.
(_match): New member.
* libproto/mbox/folder.c (_path_is_scheme): Improve automatic
mailbox format detection.
(folder_mbox_list): Do not use glob, recursively scan
subdirectories instead.
* mailbox/folder.c (mu_folder_match): New function.
(mu_folder_create_from_record): Set mu_folder_match as the default
matcher.
(mu_folder_set_match, mu_folder_get_match): New functions.
(mu_folder_enumerate): New function.
(mu_folder_list): Rewrite using mu_folder_enumerate.
2007-12-19 Sergey Poznyakoff <gray@gnu.org.ua>
* NEWS: Update.
......
......@@ -25,10 +25,8 @@
#include <mailutils/mailutils.h>
static int
ls_printer (void *item, void *data)
enumfun (mu_folder_t folder, struct mu_list_response *resp, void *data)
{
struct mu_list_response *resp = item;
printf ("%c%c %c %4d %s\n",
(resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY) ? 'd' : '-',
(resp->type & MU_FOLDER_ATTRIBUTE_FILE) ? 'f' : '-',
......@@ -60,13 +58,14 @@ ls_folders (char *fname, char *ref, char *pattern, int level)
return 1;
}
status = mu_folder_list (folder, ref, pattern, level, &flist);
status = mu_folder_enumerate (folder, ref, pattern, 0, level, &flist,
enumfun, NULL);
switch (status)
{
case 0:
mu_list_count (flist, &count);
printf ("Number of folders: %lu\n", (unsigned long) count);
mu_list_do (flist, ls_printer, NULL);
mu_list_destroy (&flist);
break;
case MU_ERR_NOENT:
......@@ -105,7 +104,5 @@ main (int argc, char *argv[])
mu_register_all_mbox_formats ();
if (!ref)
ref = folder;
return ls_folders (folder, ref, pattern, level);
}
......
......@@ -148,11 +148,6 @@ struct imap4d_command
#define NS_SHARED 2
#define NS_MAX 3
/* Wildcard return codes */
#define WCARD_NOMATCH 0
#define WCARD_MATCH 1
#define WCARD_RECURSE_MATCH 2
/* IMAP4D capability names */
#define IMAP_CAPA_STARTTLS "STARTTLS"
#define IMAP_CAPA_LOGINDISABLED "LOGINDISABLED"
......
......@@ -60,12 +60,12 @@ imap4d_lsub (struct imap4d_command *command, char *arg)
char *buf = NULL;
size_t n = 0;
while (getline(&buf, &n, fp) > 0)
while (getline (&buf, &n, fp) > 0)
{
int len = strlen (buf);
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
if (util_wcard_match (buf, pattern, delim) != WCARD_NOMATCH)
if (util_wcard_match (buf, pattern, delim) == 0)
util_out (RESP_NONE, "LIST () \"%s\" %s", delim, buf);
}
fclose (fp);
......
......@@ -53,8 +53,6 @@ imap4d_test "LIST \"/\" \"*\""\
imap4d_test -sort "LIST \"$MU_DATA_DIR\" \"*\""\
"LIST (\\NoSelect) \"/\" $MU_DATA_DIR/etc"\
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/etc/mail.rc"\
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/etc/passwd"\
"LIST (\\NoSelect) \"/\" $MU_DATA_DIR/spool"\
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/bigto.mbox"\
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/relational.mbox" \
......@@ -77,13 +75,8 @@ imap4d_test "LIST \"$MU_DATA_DIR/folder\" \"one\""\
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/folder/one"\
"OK LIST Completed"
# Well, I doubt if this is quite OK with the RFC, but at least it does
# not contradict it. The first INBOX refers to the reserved word meaning
# "the primary mailbox for this user on this server", the second one is
# the actual filename.
imap4d_test -sort "LIST \"\" INBOX"\
"LIST (\\NoInferiors) NIL INBOX"\
"LIST (\\NoInferiors) \"/\" INBOX"\
"OK LIST Completed"
imap4d_stop
......
......@@ -1028,7 +1028,7 @@ util_localname ()
return localname;
}
/* Match STRING against the IMAP4 wildard pattern PATTERN */
/* Match STRING against the IMAP4 wildcard pattern PATTERN. */
int
util_wcard_match (const char *string, const char *pattern, const char *delim)
......@@ -1041,40 +1041,39 @@ util_wcard_match (const char *string, const char *pattern, const char *delim)
switch (c)
{
case '%':
/* Matches everything except '/' */
if (*p == '\0')
{
/* Matches everything except '/' */
for (; *n && *n != delim[0]; n++)
;
return (*n == delim[0]) ? WCARD_RECURSE_MATCH : WCARD_MATCH;
for (; *n; ++n)
if (*n == *delim)
return 1;
return 0;
}
else
for (; *n != '\0'; ++n)
if (util_wcard_match (n, p, delim) == WCARD_MATCH)
return WCARD_MATCH;
if (util_wcard_match (n, p, delim) == 0)
return 0;
break;
case '*':
if (*p == '\0')
return WCARD_RECURSE_MATCH;
for (; *n != '\0'; ++n)
{
int status = util_wcard_match (n, p, delim);
if (status == WCARD_MATCH || status == WCARD_RECURSE_MATCH)
return status;
}
return 0;
else
for (; *n != '\0'; ++n)
if (util_wcard_match (n, p, delim) == 0)
return 0;
break;
default:
if (c != *n)
return WCARD_NOMATCH;
return 1;
}
}
if (!c && !*n)
return WCARD_MATCH;
return 0;
return WCARD_NOMATCH;
return 1;
}
/* Return the uindvalidity of a mailbox.
......
......@@ -33,6 +33,10 @@ struct mu_list_response
char *name;
};
typedef int (*mu_folder_match_fp) (const char *, void *, int);
typedef int (*mu_folder_enumerate_fp) (mu_folder_t, struct mu_list_response *,
void *data);
/* Constructor/destructor and possible types. */
extern int mu_folder_create (mu_folder_t *, const char *);
extern int mu_folder_create_from_record (mu_folder_t *, const char *,
......@@ -47,8 +51,12 @@ extern int mu_folder_delete (mu_folder_t, const char *);
extern int mu_folder_rename (mu_folder_t, const char *, const char *);
extern int mu_folder_subscribe (mu_folder_t, const char *);
extern int mu_folder_unsubscribe (mu_folder_t, const char *);
extern int mu_folder_list (mu_folder_t, const char *, const char *,
extern int mu_folder_list (mu_folder_t, const char *, void *,
size_t, mu_list_t *);
extern int mu_folder_enumerate (mu_folder_t, const char *,
void *, int,
size_t, mu_list_t *,
mu_folder_enumerate_fp, void *);
extern int mu_folder_lsub (mu_folder_t, const char *, const char *,
mu_list_t *);
......@@ -56,6 +64,11 @@ extern int mu_folder_lsub (mu_folder_t, const char *, const char *,
extern int mu_folder_get_stream (mu_folder_t, mu_stream_t *);
extern int mu_folder_set_stream (mu_folder_t, mu_stream_t);
/* Match function */
extern int mu_folder_set_match (mu_folder_t folder, mu_folder_match_fp pmatch);
extern int mu_folder_get_match (mu_folder_t folder,
mu_folder_match_fp *pmatch);
/* Notifications. */
extern int mu_folder_get_observable (mu_folder_t, mu_observable_t *);
......
......@@ -111,6 +111,7 @@ typedef struct _mu_tcp_server *mu_tcp_server_t;
#define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001
#define MU_FOLDER_ATTRIBUTE_FILE 0x002
#define MU_FOLDER_ATTRIBUTE_ALL \
(MU_FOLDER_ATTRIBUTE_DIRECTORY|MU_FOLDER_ATTRIBUTE_FILE)
......
......@@ -111,9 +111,10 @@ static int folder_imap_open (mu_folder_t, int);
static int folder_imap_close (mu_folder_t);
static void folder_imap_destroy (mu_folder_t);
static int folder_imap_delete (mu_folder_t, const char *);
static int folder_imap_list (mu_folder_t, const char *, const char *,
static int folder_imap_list (mu_folder_t, const char *, void *,
size_t,
mu_list_t);
mu_list_t,
mu_folder_enumerate_fp efp, void *edp);
static int folder_imap_lsub (mu_folder_t, const char *, const char *,
mu_list_t);
static int folder_imap_rename (mu_folder_t, const char *,
......@@ -975,9 +976,10 @@ glob_to_imap (const char *pat, int recursive)
}
static int
folder_imap_list (mu_folder_t folder, const char *ref, const char *name,
folder_imap_list (mu_folder_t folder, const char *ref, void *name,
size_t max_level,
mu_list_t flist)
mu_list_t flist,
mu_folder_enumerate_fp efp, void *edp)
{
f_imap_t f_imap = folder->data;
int status = 0;
......@@ -992,6 +994,11 @@ folder_imap_list (mu_folder_t folder, const char *ref, const char *name,
if (name == NULL)
name = "";
f_imap->folder = folder;
f_imap->enum_fun = efp;
f_imap->enum_stop = 0;
f_imap->enum_data = edp;
switch (f_imap->state)
{
case IMAP_NO_STATE:
......@@ -1017,6 +1024,11 @@ folder_imap_list (mu_folder_t folder, const char *ref, const char *name,
break;
}
f_imap->folder = NULL;
f_imap->enum_fun = NULL;
f_imap->enum_stop = 0;
f_imap->enum_data = NULL;
list_copy (flist, f_imap->flist, strlen (ref),
imap_mailbox_name_match, name, max_level);
......@@ -1041,6 +1053,10 @@ folder_imap_lsub (mu_folder_t folder, const char *ref, const char *name,
if (name == NULL)
name = "";
f_imap->enum_fun = NULL;
f_imap->enum_stop = 0;
f_imap->enum_data = NULL;
switch (f_imap->state)
{
case IMAP_NO_STATE:
......@@ -1384,7 +1400,10 @@ imap_list (f_imap_t f_imap)
int status = 0;
int argc;
char **argv;
if (f_imap->enum_stop)
return 0;
buffer = malloc (len);
if (!buffer)
return ENOMEM;
......@@ -1400,7 +1419,6 @@ imap_list (f_imap_t f_imap)
mu_list_create (&f_imap->flist);
mu_list_set_destroy_item (f_imap->flist, mu_list_response_free);
}
mu_list_append (f_imap->flist, lr);
/* Glob untag. */
tok = strtok_r (buffer, " ", &sp);
......@@ -1475,6 +1493,12 @@ imap_list (f_imap_t f_imap)
}
mu_argcv_free (argc, argv);
free (buffer);
if (f_imap->enum_fun)
f_imap->enum_stop = f_imap->enum_fun (f_imap->folder, lr,
f_imap->enum_data);
mu_list_append (f_imap->flist, lr);
return status;
}
......
......@@ -33,6 +33,9 @@
extern "C" {
#endif
#define MU_FOLDER_LIST 0
#define MU_FOLDER_ENUM 1
struct _mu_folder
{
/* Data */
......@@ -55,11 +58,11 @@ struct _mu_folder
int (*_open) (mu_folder_t, int flag);
int (*_close) (mu_folder_t);
int (*_list) (mu_folder_t, const char *, const char *,
size_t,
mu_list_t);
int (*_list) (mu_folder_t, const char *, void *, int, size_t,
mu_list_t, mu_folder_enumerate_fp, void *);
int (*_lsub) (mu_folder_t, const char *, const char *,
mu_list_t);
mu_folder_match_fp _match;
int (*_delete) (mu_folder_t, const char *);
int (*_rename) (mu_folder_t, const char *, const char *);
int (*_subscribe) (mu_folder_t, const char *);
......
......@@ -161,7 +161,10 @@ struct _f_imap
/* Use for LIST and LSUB. */
mu_list_t flist;
mu_folder_enumerate_fp enum_fun;
void *enum_data;
int enum_stop;
int isopen;
/* Server channel buffer I/O */
......@@ -170,8 +173,8 @@ struct _f_imap
char *ptr;
char *nl;
mu_off_t offset; /* Dummy, this is used because of the stream buffering.
The mu_stream_t maintains and offset and the offset we use must
be in sync. */
The mu_stream_t maintains and offset and the offset we
use must be in sync. */
/* Login */
char *user;
......
......@@ -41,6 +41,7 @@
#include <mailutils/stream.h>
#include <mailutils/mutil.h>
#include <mailutils/errno.h>
#include <mailutils/debug.h>
/* We export url parsing and the initialisation of
the mailbox, via the register entry/record. */
......@@ -77,11 +78,32 @@ _path_is_scheme (mu_record_t record, const char *url, int flags)
struct stat st;
if (stat (path, &st) < 0)
return MU_FOLDER_ATTRIBUTE_ALL; /* mu_mailbox_open will complain */
{
if (errno == ENOENT)
rc |= MU_FOLDER_ATTRIBUTE_FILE;
return rc;
}
if ((flags & MU_FOLDER_ATTRIBUTE_FILE)
&& (S_ISREG (st.st_mode) || S_ISCHR (st.st_mode)))
rc |= MU_FOLDER_ATTRIBUTE_FILE;
if (S_ISREG (st.st_mode) || S_ISCHR (st.st_mode))
{
if (st.st_size == 0)
{
rc |= MU_FOLDER_ATTRIBUTE_FILE;
}
else if (flags & MU_FOLDER_ATTRIBUTE_FILE)
{
int fd = open (path, O_RDONLY);
if (fd != -1)
{
char buf[5];
if (read (fd, buf, 5) == 5)
if (memcmp (buf, "From ", 5) == 0)
rc |= MU_FOLDER_ATTRIBUTE_FILE;
close (fd);
}
}
}
if ((flags & MU_FOLDER_ATTRIBUTE_DIRECTORY)
&& S_ISDIR (st.st_mode))
rc |= MU_FOLDER_ATTRIBUTE_DIRECTORY;
......@@ -113,8 +135,9 @@ 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 *, const char *,
size_t, mu_list_t);
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 *,
......@@ -228,7 +251,8 @@ folder_mbox_delete (mu_folder_t folder, const char *filename)
}
static int
folder_mbox_rename (mu_folder_t folder, const char *oldpath, const char *newpath)
folder_mbox_rename (mu_folder_t folder, const char *oldpath,
const char *newpath)
{
fmbox_t fmbox = folder->data;
if (oldpath && newpath)
......@@ -266,8 +290,15 @@ struct inode_list /* Inode/dev number list used to cut off
struct search_data
{
mu_list_t result;
const char *pattern;
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
......@@ -279,126 +310,146 @@ inode_list_lookup (struct inode_list *list, struct stat *st)
return 0;
}
static int
list_helper (struct search_data *data,
const char *dirname, size_t level, struct inode_list *ilist)
list_helper (struct search_data *data, const char *dirname, size_t level,
struct inode_list *ilist)
{
int status;
glob_t gl;
char *pathname;
++level;
DIR *dirp;
struct dirent *dp;
int stop = 0;
if (data->max_level && level > data->max_level)
return 0;
pathname = get_pathname (dirname, data->pattern);
if (!pathname)
return ENOMEM;
memset(&gl, 0, sizeof(gl));
status = glob (pathname, 0, NULL, &gl);
free (pathname);
if (status == 0)
dirp = opendir (dirname);
if (dirp == NULL)
{
size_t i;
struct mu_list_response *resp;
MU_DEBUG2 (data->folder->debug, MU_DEBUG_ERROR,
"list_helper cannot open directory %s: %s",
dirname, mu_strerror (errno));
data->errcnt++;
return 1;
}
while ((dp = readdir (dirp)))
{
char const *ename = dp->d_name;
char *fname;
for (i = 0; i < gl.gl_pathc; i++)
if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0)
continue;
fname = get_pathname (dirname, ename);
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)
{
struct stat st;
resp = malloc (sizeof (*resp));
if (resp == NULL)
{
status = ENOMEM;
break;
}
else if ((resp->name = strdup (gl.gl_pathv[i])) == NULL)
if (stat (fname, &st) == 0)
{
free (resp);
status = ENOMEM;
break;
}
char *refname = fname;
int type = 0;
struct mu_list_response *resp;
resp = malloc (sizeof (*resp));
if (resp == NULL)
{
MU_DEBUG1 (data->folder->debug, MU_DEBUG_ERROR,
"list_helper: %s", mu_strerror (ENOMEM));
data->errcnt++;
free (fname);
continue;
}
resp->level = level;
resp->separator = '/';
resp->type = 0;
mu_list_append (data->result, resp);
mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL, NULL,
&type);
if (stat (gl.gl_pathv[i], &st) == 0)
{
resp->type = 0;
mu_registrar_lookup (gl.gl_pathv[i], MU_FOLDER_ATTRIBUTE_ALL,
NULL, &resp->type);
if ((resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
resp->name = fname;
resp->level = level;
resp->separator = '/';
resp->type = type;
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;
status = list_helper (data, gl.gl_pathv[i], level, &idata);
if (status)
break;
stop = list_helper (data, refname, level + 1, &idata);
}
}
}
globfree (&gl);
}
else
{
switch (status)
{
case GLOB_NOSPACE:
status = ENOMEM;
break;
case GLOB_ABORTED:
status = MU_ERR_READ;
break;
case GLOB_NOMATCH:
if (mu_list_is_empty (data->result))
status = MU_ERR_NOENT;
else
status = 0;
break;
case GLOB_NOSYS:
status = ENOSYS;
break;
default:
status = MU_ERR_FAILURE;
break;
{
MU_DEBUG2 (data->folder->debug, MU_DEBUG_ERROR,
"list_helper cannot stat %s: %s",
fname, mu_strerror (errno));
}
}
free (fname);
}
return status;
closedir (dirp);
return stop;
}
/* The listing is not recursive and we use glob() some expansion for us.
Unfortunately glob() does not expand the '~'. We also return
the full pathname so it can be use to create other folders. */
static int
folder_mbox_list (mu_folder_t folder, const char *dirname, const char *pattern,
folder_mbox_list (mu_folder_t folder, const char *ref,
void *pattern,
int flags,
size_t max_level,
mu_list_t flist)
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);
if (dirname == NULL || dirname[0] == '\0')
dirname = (const char *)fmbox->dirname;
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;
return list_helper (&sdata, dirname, 0, &iroot);
sdata.folder = folder;
sdata.errcnt = 0;
list_helper (&sdata, sdata.dirname, 0, &iroot);
free (sdata.dirname);
/* FIXME: error code */
return 0;
}
static int
......
......@@ -63,9 +63,10 @@ static int nntp_folder_open (mu_folder_t, int);
static int nntp_folder_close (mu_folder_t);
static void nntp_folder_destroy (mu_folder_t folder);
static int nntp_folder_list (mu_folder_t folder, const char *ref,
const char *name,
void *name,
size_t max,
mu_list_t flist);
mu_list_t flist,
mu_folder_enumerate_fp efp, void *edp);
int
_nntp_folder_init (mu_folder_t folder)
......@@ -185,8 +186,9 @@ nntp_folder_destroy (mu_folder_t folder)
static int
nntp_folder_list (mu_folder_t folder, const char *ref, const char *name,
size_t max_level, mu_list_t flist)
nntp_folder_list (mu_folder_t folder, const char *ref, void *pat,
size_t max_level, mu_list_t flist,
mu_folder_enumerate_fp efp, void *edp)
{
return ENOTSUP;
}
......
......@@ -24,6 +24,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <fnmatch.h>
#include <mailutils/auth.h>
#include <mailutils/debug.h>
......@@ -45,13 +46,19 @@ static int is_known_folder (mu_url_t, mu_folder_t *);
/* Static folder lock. */
static struct mu_monitor folder_lock = MU_MONITOR_INITIALIZER;
int
mu_folder_match (const char *name, void *pattern, int flags)
{
return fnmatch (pattern, name[0] == '/' ? name + 1 : name, flags);
}
/* A folder could be remote (IMAP), or local(a spool directory) like $HOME/Mail
etc .. We maintain a known list of folder to not generate multiple folder
of the same URL. Meaning when mu_folder_create () is call we'll check if we
already have a folder for that URL and return the same, if not we create a
new one. The downside, the scheme to detect the same URL is very weak, and
they maybe cases where you want a different folder for the same URL, there
is not easy way to do this. */
etc .. We maintain a list of known folders to avoid creating multiple
folders for the same URL. So, when mu_folder_create is called we check if
we already have a folder for that URL and return it, otherwise we create a
new one. Downsides: the scheme to detect the same URL is very weak, and
there could be cases where you'll want a different folder for the same URL,
there is not easy way to do this. */
int
mu_folder_create_from_record (mu_folder_t *pfolder, const char *name,
mu_record_t record)
......@@ -112,6 +119,8 @@ mu_folder_create_from_record (mu_folder_t *pfolder, const char *name,
status = f_init (folder);
if (status == 0)
{
if (!folder->_match)
folder->_match = mu_folder_match;
*pfolder = folder;
folder->ref++;
/* Put on the internal list of known folders. */
......@@ -280,6 +289,26 @@ mu_folder_get_observable (mu_folder_t folder, mu_observable_t *pobservable)
}
int
mu_folder_set_match (mu_folder_t folder, mu_folder_match_fp pmatch)
{
if (folder == NULL)
return EINVAL;
folder->_match = pmatch;
return 0;
}
int
mu_folder_get_match (mu_folder_t folder, mu_folder_match_fp *pmatch)
{
if (folder == NULL)
return EINVAL;
if (pmatch == NULL)
return MU_ERR_OUT_PTR_NULL;
*pmatch = folder->_match;
return 0;
}
int
mu_folder_has_debug (mu_folder_t folder)
{
if (folder == NULL)
......@@ -325,20 +354,41 @@ mu_list_response_free (void *data)
}
int
mu_folder_list (mu_folder_t folder, const char *dirname, const char *basename,
mu_folder_list (mu_folder_t folder, const char *dirname, void *pattern,
size_t max_level,
mu_list_t *pflist)
{
return mu_folder_enumerate (folder, dirname, pattern, 0, max_level,
pflist, NULL, NULL);
}
int
mu_folder_enumerate (mu_folder_t folder, const char *name,
void *pattern, int flags,
size_t max_level,
mu_list_t *pflist,
mu_folder_enumerate_fp enumfun, void *enumdata)
{
int status;
if (folder == NULL || folder->_list == NULL)
return EINVAL;
else
{
status = mu_list_create (pflist);
if (status)
return status;
mu_list_set_destroy_item (*pflist, mu_list_response_free);
status = folder->_list (folder, dirname, basename, max_level, *pflist);
mu_list_t list = NULL;
if (pflist)
{
status = mu_list_create (&list);
if (status)
return status;
*pflist = list;
mu_list_set_destroy_item (list, mu_list_response_free);
}
else if (!enumfun)
return EINVAL;
status = folder->_list (folder, name, pattern, flags, max_level,
list, enumfun, enumdata);
if (status)
mu_list_destroy (pflist);
}
......