Commit 05a15a28 05a15a280d82ecaf428a4055d8c6c4ded1f58f32 by Sergey Poznyakoff

Rewritten for new mu_folder_list,mu_folder_lsub semantics.

1 parent 76f6155e
......@@ -338,52 +338,62 @@ file_generator (const char *text, int state, char *path, size_t pathlen,
char repl,
int flags)
{
static struct mu_folder_list list;
static int i;
static mu_list_t list;
static mu_iterator_t itr;
if (!state)
{
char *wcard;
mu_folder_t folder;
size_t count;
wcard = xmalloc (strlen (text) + 2);
strcat (strcpy (wcard, text), "*");
mu_folder_create (&folder, path);
mu_folder_list (folder, path, wcard, &list);
mu_folder_list (folder, path, wcard, 1, &list);
free (wcard);
mu_folder_destroy (&folder);
if (list.num == 0)
return NULL;
else if (list.num == 1)
if (mu_list_count (list, &count) || count == 0)
{
mu_list_destroy (&list);
return NULL;
}
else if (count == 1)
ml_set_completion_append_character (0);
i = 0;
if (mu_list_get_iterator (list, &itr))
{
mu_list_destroy (&list);
return NULL;
}
mu_iterator_first (itr);
}
while (i < list.num)
while (!mu_iterator_is_done (itr))
{
if (list.element[i]->type & flags)
struct mu_list_response *resp;
mu_iterator_current (itr, (void**)&resp);
mu_iterator_next (itr);
if (resp->type & flags)
{
char *ret;
if (repl)
{
int len = strlen (list.element[i]->name + pathlen);
int len = strlen (resp->name + pathlen);
ret = xmalloc (len + 2);
ret[0] = repl;
memcpy (ret + 1, list.element[i]->name + pathlen, len);
memcpy (ret + 1, resp->name + pathlen, len);
ret[len+1] = 0;
}
else
ret = xstrdup (list.element[i]->name);
i++;
ret = xstrdup (resp->name);
return ret;
}
i++;
}
mu_folder_list_destroy (&list);
mu_iterator_destroy (&itr);
mu_list_destroy (&list);
return NULL;
}
......
......@@ -307,22 +307,52 @@ mu_folder_get_debug (mu_folder_t folder, mu_debug_t *pdebug)
return 0;
}
void
mu_list_response_free (void *data)
{
struct mu_list_response *f = data;
free (f->name);
free (f);
}
int
mu_folder_list (mu_folder_t folder, const char *dirname, const char *basename,
struct mu_folder_list *pflist)
size_t max_level,
mu_list_t *pflist)
{
int status;
if (folder == NULL || folder->_list == NULL)
return EINVAL;
return folder->_list (folder, dirname, basename, pflist);
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);
if (status)
mu_list_destroy (pflist);
}
return status;
}
int
mu_folder_lsub (mu_folder_t folder, const char *dirname, const char *basename,
struct mu_folder_list *pflist)
mu_list_t *pflist)
{
int status;
if (folder == NULL || folder->_lsub == NULL)
return ENOSYS;
return folder->_lsub (folder, dirname, basename, pflist);
else
{
status = mu_list_create (pflist);
if (status)
return status;
mu_list_set_destroy_item (*pflist, mu_list_response_free);
status = folder->_lsub (folder, dirname, basename, *pflist);
}
return status;
}
int
......@@ -342,28 +372,6 @@ mu_folder_unsubscribe (mu_folder_t folder, const char *name)
}
int
mu_folder_list_destroy (struct mu_folder_list *pflist)
{
size_t i;
if (pflist == NULL)
return 0;
for (i = 0 ; i < pflist->num; i++)
{
if (pflist->element[i])
{
if (pflist->element[i]->name)
free (pflist->element[i]->name);
free (pflist->element[i]);
}
}
if (i > 0)
free (pflist->element);
pflist->element = NULL;
pflist->num = 0;
return 0;
}
int
mu_folder_delete (mu_folder_t folder, const char *name)
{
if (folder == NULL || folder->_delete == NULL)
......
......@@ -252,8 +252,9 @@ mailbox_imap_open (mu_mailbox_t mailbox, int flags)
m_imap_t m_imap = mailbox->data;
f_imap_t f_imap = m_imap->f_imap;
mu_folder_t folder = f_imap->folder;
struct mu_folder_list folders = { 0, 0 };
mu_list_t folders = NULL;
size_t count;
/* m_imap must have been created during mailbox initialization. */
assert (mailbox->data);
assert (m_imap->name);
......@@ -274,7 +275,7 @@ mailbox_imap_open (mu_mailbox_t mailbox, int flags)
m_imap->state = IMAP_LIST;
case IMAP_LIST:
status = mu_folder_list (folder, NULL, m_imap->name, &folders);
status = mu_folder_list (folder, NULL, m_imap->name, 0, &folders);
if (status != 0)
{
if (status != EAGAIN && status != EINPROGRESS && status != EINTR)
......@@ -283,7 +284,9 @@ mailbox_imap_open (mu_mailbox_t mailbox, int flags)
return status;
}
m_imap->state = IMAP_NO_STATE;
if (folders.num)
status = mu_list_count (folders, &count);
mu_list_destroy (&folders);
if (status || count)
return 0;
if ((flags & MU_STREAM_CREAT) == 0)
......
......@@ -56,9 +56,10 @@ struct _mu_folder
int (*_open) (mu_folder_t, int flag);
int (*_close) (mu_folder_t);
int (*_list) (mu_folder_t, const char *, const char *,
struct mu_folder_list *);
size_t,
mu_list_t);
int (*_lsub) (mu_folder_t, const char *, const char *,
struct mu_folder_list *);
mu_list_t);
int (*_delete) (mu_folder_t, const char *);
int (*_rename) (mu_folder_t, const char *, const char *);
int (*_subscribe) (mu_folder_t, const char *);
......
......@@ -131,7 +131,6 @@ struct literal_string
size_t total;
msg_imap_t msg_imap;
enum imap_state type;
struct mu_folder_list flist;
size_t nleft; /* nleft to read in the literal. */
};
......@@ -160,7 +159,7 @@ struct _f_imap
} string;
/* Use for LIST and LSUB. */
struct mu_folder_list flist;
mu_list_t flist;
int isopen;
......
......@@ -113,11 +113,12 @@ 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 *,
struct mu_folder_list *);
size_t,
mu_list_t);
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 *,
struct mu_folder_list *);
mu_list_t);
static char *get_pathname (const char *, const char *);
......@@ -257,65 +258,103 @@ folder_mbox_rename (mu_folder_t folder, const char *oldpath, const char *newpath
return EINVAL;
}
/* The listing is not recursif 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. */
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;
const char *pattern;
size_t max_level;
};
static int
folder_mbox_list (mu_folder_t folder, const char *dirname, const char *pattern,
struct mu_folder_list *pflist)
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,
const char *dirname, size_t level, struct inode_list *ilist)
{
fmbox_t fmbox = folder->data;
char *pathname = NULL;
int status;
size_t num = 0;
glob_t gl;
char *pathname;
if (dirname == NULL || dirname[0] == '\0')
dirname = (const char *)fmbox->dirname;
++level;
if (data->max_level && level > data->max_level)
return 0;
pathname = get_pathname (dirname, data->pattern);
if (!pathname)
return ENOMEM;
pathname = get_pathname (dirname, pattern);
if (pathname)
{
memset(&gl, 0, sizeof(gl));
status = glob (pathname, 0, NULL, &gl);
free (pathname);
num = gl.gl_pathc;
}
else
status = ENOMEM;
memset(&gl, 0, sizeof(gl));
status = glob (pathname, 0, NULL, &gl);
free (pathname);
/* Build the folder list from glob. */
if (status == 0)
{
if (pflist)
size_t i;
struct mu_list_response *resp;
for (i = 0; i < gl.gl_pathc; i++)
{
struct mu_list_response **plist;
plist = calloc (num, sizeof (*plist));
if (plist)
struct stat st;
resp = malloc (sizeof (*resp));
if (resp == NULL)
{
status = ENOMEM;
break;
}
else if ((resp->name = strdup (gl.gl_pathv[i])) == NULL)
{
free (resp);
status = ENOMEM;
break;
}
resp->level = level;
resp->separator = '/';
resp->type = 0;
mu_list_append (data->result, resp);
if (stat (gl.gl_pathv[i], &st) == 0)
{
size_t i;
struct stat stbuf;
for (i = 0; i < num; i++)
mu_record_t record;
resp->type = mu_registrar_lookup (gl.gl_pathv[i],
&record,
MU_FOLDER_ATTRIBUTE_ALL);
if ((resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
&& !inode_list_lookup (ilist, &st))
{
plist[i] = calloc (1, sizeof (**plist));
if (plist[i] == NULL
|| (plist[i]->name = strdup (gl.gl_pathv[i])) == NULL)
{
num = i;
break;
}
if (stat (gl.gl_pathv[i], &stbuf) == 0)
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)
{
mu_record_t record;
plist[i]->type = mu_registrar_lookup (gl.gl_pathv[i],
&record,
MU_FOLDER_ATTRIBUTE_ALL);
if (status == MU_ERR_NOENT
&& !mu_list_is_empty (data->result))
status = 0;
else
break;
}
plist[i]->separator = '/';
}
}
pflist->element = plist;
pflist->num = num;
}
globfree (&gl);
}
......@@ -347,42 +386,68 @@ folder_mbox_list (mu_folder_t folder, const char *dirname, const char *pattern,
return status;
}
/* The listing is not recursif 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_lsub (mu_folder_t folder, const char *ref ARG_UNUSED, const char *name,
struct mu_folder_list *pflist)
folder_mbox_list (mu_folder_t folder, const char *dirname, const char *pattern,
size_t max_level,
mu_list_t flist)
{
fmbox_t fmbox = folder->data;
size_t j = 0;
struct inode_list iroot;
struct search_data sdata;
memset (&iroot, 0, sizeof iroot);
if (dirname == NULL || dirname[0] == '\0')
dirname = (const char *)fmbox->dirname;
if (pflist == NULL)
return MU_ERR_OUT_NULL;
sdata.result = flist;
sdata.pattern = pattern;
sdata.max_level = max_level;
return list_helper (&sdata, dirname, 0, &iroot);
}
static int
folder_mbox_lsub (mu_folder_t folder, const char *ref 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)
{
struct mu_list_response **plist;
{
size_t i;
plist = calloc (fmbox->sublen, sizeof (*plist));
for (i = 0; i < fmbox->sublen; i++)
{
if (fmbox->subscribe[i]
&& fnmatch (name, fmbox->subscribe[i], 0) == 0)
{
plist[i] = calloc (1, sizeof (**plist));
if (plist[i] == NULL
|| (plist[i]->name = strdup (fmbox->subscribe[i])) == NULL)
break;
plist[i]->type = MU_FOLDER_ATTRIBUTE_FILE;
plist[i]->separator = '/';
j++;
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 = '/';
}
}
pflist->element = plist;
}
pflist->num = j;
return 0;
return status;
}
static int
......@@ -449,7 +514,7 @@ get_pathname (const char *dirname, const char *basename)
size_t dirlen = strlen (dirname);
while (dirlen > 0 && dirname[dirlen-1] == '/')
dirlen--;
pathname = calloc (dirname + baselen + 2, sizeof (char));
pathname = calloc (dirlen + baselen + 2, sizeof (char));
if (pathname)
{
memcpy (pathname, dirname, dirlen);
......
......@@ -62,7 +62,10 @@ mu_record_t mu_nntp_record = &_nntp_record;
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, struct mu_folder_list *pflist);
static int nntp_folder_list (mu_folder_t folder, const char *ref,
const char *name,
size_t max,
mu_list_t flist);
int
_nntp_folder_init (mu_folder_t folder)
......@@ -187,7 +190,8 @@ nntp_folder_destroy (mu_folder_t folder)
static int
nntp_folder_list (mu_folder_t folder, const char *ref, const char *name, struct mu_folder_list *pflist)
nntp_folder_list (mu_folder_t folder, const char *ref, const char *name,
size_t max_level, mu_list_t flist)
{
return ENOTSUP;
}
......