summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cloos <cloos@jhcloos.com>2010-10-16 19:05:51 -0400
committerJames Cloos <cloos@jhcloos.com>2010-10-16 20:03:31 -0400
commitc03d2eb5128671bf602338c0eb497a07e7823e96 (patch)
tree8067c0eb4389220d610763f824535115c24249e5
parent6907dcb959f8d3b88ffbf614ba591f0c2bfa6f70 (diff)
Do IMAP LIST/LSUB commands with a single query
Signed-off-by: James Cloos <cloos@jhcloos.com>
-rw-r--r--check_dbmail_db.c5
-rw-r--r--db.c92
-rw-r--r--db.h6
-rw-r--r--dbmail-user.c3
-rw-r--r--export.c3
-rw-r--r--imapcommands.c35
6 files changed, 94 insertions, 50 deletions
diff --git a/check_dbmail_db.c b/check_dbmail_db.c
index bad274dd..a2bdd818 100644
--- a/check_dbmail_db.c
+++ b/check_dbmail_db.c
@@ -846,16 +846,17 @@ END_TEST
*/
//int db_findmailbox_by_regex(u64_t owner_idnr, const char *pattern,
// u64_t ** children, unsigned *nchildren,
-// int only_subscribed);
+// int only_subscribed, &mb);
START_TEST(test_db_findmailbox_by_regex)
{
int result;
u64_t *children = NULL;
u64_t mailbox_id = 0;
unsigned nchildren = 0;
+ mailbox_t *mb;
result = db_createmailbox("INBOX/Trash", testidnr, &mailbox_id);
- result = db_findmailbox_by_regex(testidnr, "INBOX/Trash", &children, &nchildren, 0);
+ result = db_findmailbox_by_regex(testidnr, "INBOX/Trash", &children, &nchildren, 0, &mb);
}
END_TEST
diff --git a/db.c b/db.c
index 69a7664e..2c1aa049 100644
--- a/db.c
+++ b/db.c
@@ -2799,18 +2799,22 @@ static int db_findmailbox_owner(const char *name, u64_t owner_idnr,
}
static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char * pattern,
- u64_t ** mailboxes, unsigned int *nr_mailboxes)
+ u64_t ** mailboxes, unsigned int *nr_mailboxes, mailbox_t ** mb)
{
unsigned int i;
u64_t *tmp_mailboxes;
u64_t *all_mailboxes;
char** all_mailbox_names;
u64_t *all_mailbox_owners;
+ u64_t *all_mailbox_nosels;
+ u64_t *all_mailbox_noinfs;
+ u64_t *all_mailbox_children;
u64_t search_user_idnr = user_idnr;
unsigned n_rows;
char *matchname;
const char *spattern;
char *namespace, *username;
+ mailbox_t *tmp_mb;
char query[DEF_QUERYSIZE];
memset(query,0,DEF_QUERYSIZE);
@@ -2852,7 +2856,7 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char *
if (only_subscribed)
snprintf(query, DEF_QUERYSIZE,
- "SELECT distinct(mbx.name), mbx.mailbox_idnr, mbx.owner_idnr "
+ "SELECT distinct(mbx.name), mbx.mailbox_idnr, mbx.owner_idnr, mbx.no_select, mbx.no_inferiors, mbx.children "
"FROM %smailboxes mbx "
"LEFT JOIN %sacl acl ON mbx.mailbox_idnr = acl.mailbox_id "
"LEFT JOIN %susers usr ON acl.user_id = usr.user_idnr "
@@ -2868,7 +2872,7 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char *
DBMAIL_ACL_ANYONE_USER);
else
snprintf(query, DEF_QUERYSIZE,
- "SELECT distinct(mbx.name), mbx.mailbox_idnr, mbx.owner_idnr "
+ "SELECT distinct(mbx.name), mbx.mailbox_idnr, mbx.owner_idnr, mbx.no_select, mbx.no_inferiors, mbx.children "
"FROM %smailboxes mbx "
"LEFT JOIN %sacl acl ON mbx.mailbox_idnr = acl.mailbox_id "
"LEFT JOIN %susers usr ON acl.user_id = usr.user_idnr "
@@ -2896,20 +2900,32 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char *
all_mailboxes = g_new0(u64_t,n_rows);
all_mailbox_names = g_new0(char *,n_rows);
all_mailbox_owners = g_new0(u64_t,n_rows);
+ all_mailbox_nosels = g_new0(u64_t,n_rows);
+ all_mailbox_noinfs = g_new0(u64_t,n_rows);
+ all_mailbox_children = g_new0(u64_t,n_rows);
tmp_mailboxes = g_new0(u64_t,n_rows);
for (i = 0; i < n_rows; i++) {
all_mailbox_names[i] = g_strdup(db_get_result(i, 0));
all_mailboxes[i] = db_get_result_u64(i, 1);
all_mailbox_owners[i] = db_get_result_u64(i, 2);
+ all_mailbox_nosels[i] = db_get_result_u64(i, 3);
+ all_mailbox_noinfs[i] = db_get_result_u64(i, 4);
+ all_mailbox_children[i] = db_get_result_u64(i, 5);
}
db_free_result();
+ tmp_mb = g_new0(mailbox_t,n_rows);
+
for (i = 0; i < n_rows; i++) {
char *mailbox_name;
+ GString *fqname;
u64_t mailbox_idnr = all_mailboxes[i];
u64_t owner_idnr = all_mailbox_owners[i];
+ u64_t no_select = all_mailbox_nosels[i];
+ u64_t no_inferiors = all_mailbox_noinfs[i];
+ u64_t no_children = all_mailbox_children[i];
char *simple_mailbox_name = all_mailbox_names[i];
/* add possible namespace prefix to mailbox_name */
@@ -2918,7 +2934,23 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char *
if (mailbox_name) {
tmp_mailboxes[*nr_mailboxes] = mailbox_idnr;
(*nr_mailboxes)++;
+
+ fqname = g_string_new(mailbox_name);
+ fqname = g_string_truncate(fqname,IMAP_MAX_MAILBOX_NAMELEN);
+ tmp_mb[i].name = fqname->str;
+ g_string_free(fqname,FALSE);
}
+
+ /* owner_idnr */
+ tmp_mb[i].owner_idnr = owner_idnr;
+
+ /* no_select */
+ tmp_mb[i].no_select=no_select;
+ /* no_inferior */
+ tmp_mb[i].no_inferiors=no_inferiors;
+
+ /* no_children */
+ tmp_mb[i].no_children=no_children?0:1;
g_free(mailbox_name);
g_free(simple_mailbox_name);
@@ -2926,6 +2958,9 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char *
g_free(all_mailbox_names);
g_free(all_mailboxes);
g_free(all_mailbox_owners);
+ g_free(all_mailbox_nosels);
+ g_free(all_mailbox_noinfs);
+ g_free(all_mailbox_children);
if (*nr_mailboxes == 0) {
/* none exist, none matched */
@@ -2934,18 +2969,19 @@ static int mailboxes_by_regex(u64_t user_idnr, int only_subscribed, const char *
}
*mailboxes = tmp_mailboxes;
+ *mb = tmp_mb;
return DM_EGENERAL;
}
int db_findmailbox_by_regex(u64_t owner_idnr, const char *pattern,
u64_t ** children, unsigned *nchildren,
- int only_subscribed)
+ int only_subscribed, mailbox_t ** mb)
{
*children = NULL;
/* list normal mailboxes */
- if (mailboxes_by_regex(owner_idnr, only_subscribed, pattern, children, nchildren) < 0) {
+ if (mailboxes_by_regex(owner_idnr, only_subscribed, pattern, children, nchildren, mb) < 0) {
TRACE(TRACE_ERROR, "error listing mailboxes");
return DM_EQUERY;
}
@@ -4662,7 +4698,6 @@ int db_getmailbox_list_result(u64_t mailbox_idnr, u64_t user_idnr, mailbox_t * m
{
/* query mailbox for LIST results */
char *mbxname, *name;
- char *mailbox_like;
GString *fqname;
int i=0;
char query[DEF_QUERYSIZE];
@@ -4670,7 +4705,7 @@ int db_getmailbox_list_result(u64_t mailbox_idnr, u64_t user_idnr, mailbox_t * m
snprintf(query, DEF_QUERYSIZE,
- "SELECT owner_idnr, name, no_select, no_inferiors "
+ "SELECT owner_idnr, name, no_select, no_inferiors, children "
"FROM %smailboxes WHERE mailbox_idnr = %llu",
DBPFX, mailbox_idnr);
@@ -4699,26 +4734,9 @@ int db_getmailbox_list_result(u64_t mailbox_idnr, u64_t user_idnr, mailbox_t * m
mb->no_select=db_get_result_bool(0,i++);
/* no_inferior */
mb->no_inferiors=db_get_result_bool(0,i++);
- db_free_result();
/* no_children */
- mailbox_like = db_imap_utf7_like("name", name, "/%");
-
- memset(query,0,DEF_QUERYSIZE);
-
- snprintf(query, DEF_QUERYSIZE,
- "SELECT COUNT(*) AS nr_children "
- "FROM %smailboxes WHERE owner_idnr = %llu "
- "AND %s",
- DBPFX, mb->owner_idnr, mailbox_like);
-
- g_free(mailbox_like);
-
- if (db_query(query) == -1) {
- TRACE(TRACE_ERROR, "db error");
- return DM_EQUERY;
- }
- mb->no_children=db_get_result_u64(0,0)?0:1;
+ mb->no_children=db_get_result_u64(0,i++)?0:1;
g_free(name);
db_free_result();
@@ -5199,3 +5217,27 @@ int db_user_log_login(u64_t user_idnr)
return result;
}
+
+int db_getmailbox_list_by_regex(u64_t owner_idnr, const char *pattern,
+ u64_t ** children, unsigned *nchildren,
+ int only_subscribed, mailbox_t **mb)
+{
+ *children = NULL;
+
+ /* list normal mailboxes */
+ if (mailboxes_by_regex(owner_idnr, only_subscribed, pattern, children, nchildren, mb) < 0) {
+ TRACE(TRACE_ERROR, "error listing mailboxes");
+ return DM_EQUERY;
+ }
+
+ if (*nchildren == 0) {
+ TRACE(TRACE_INFO, "did not find any mailboxes that "
+ "match pattern. returning 0, nchildren = 0");
+ return DM_SUCCESS;
+ }
+
+
+ /* store matches */
+ TRACE(TRACE_INFO, "found [%d] mailboxes", *nchildren);
+ return DM_SUCCESS;
+}
diff --git a/db.h b/db.h
index bef7d4a3..3231f8a2 100644
--- a/db.h
+++ b/db.h
@@ -945,13 +945,14 @@ int db_findmailbox(const char *name, u64_t user_idnr,
* returns and needs to be free-d by caller
* \param nchildren number of mailboxes in children
* \param only_subscribed only search in subscribed mailboxes.
+ * \param mb pointer to a list of mailbox_t to be filled.
* \return
* - -1 on failure
* - 0 on success
*/
int db_findmailbox_by_regex(u64_t owner_idnr, const char *pattern,
u64_t ** children, unsigned *nchildren,
- int only_subscribed);
+ int only_subscribed, mailbox_t ** mb);
/**
* \brief get info on a mailbox. Info is filled in in the
* mailbox_t struct.
@@ -1334,4 +1335,7 @@ int db_count_replycache(timestring_t lasttokeep, u64_t *affected_rows);
/* get driver specific SQL snippets */
const char * db_get_sql(sql_fragment_t frag);
+int db_getmailbox_list_by_regex(u64_t owner_idnr, const char *pattern,
+ u64_t ** children, unsigned *nchildren,
+ int only_subscribed, mailbox_t **mb);
#endif
diff --git a/dbmail-user.c b/dbmail-user.c
index 5c7ef605..0e655cc6 100644
--- a/dbmail-user.c
+++ b/dbmail-user.c
@@ -698,10 +698,11 @@ int do_empty(u64_t useridnr)
u64_t owner_idnr;
unsigned nchildren, i;
char mailbox[IMAP_MAX_MAILBOX_NAMELEN];
+ mailbox_t *mb;
qprintf("You've requested to delete all mailboxes owned by user number [%llu]:\n", useridnr);
- db_findmailbox_by_regex(useridnr, "*", &children, &nchildren, 0);
+ db_findmailbox_by_regex(useridnr, "*", &children, &nchildren, 0, &mb);
for (i = 0; i < nchildren; i++) {
/* Given a list of mailbox id numbers, check if the
* user actually owns the mailbox (because that means
diff --git a/export.c b/export.c
index e01942f7..d4692588 100644
--- a/export.c
+++ b/export.c
@@ -169,6 +169,7 @@ static int do_export(char *user, char *base_mailbox, char *basedir, char *outfil
u64_t user_idnr = 0, owner_idnr = 0, mailbox_idnr = 0;
char *dumpfile = NULL, *mailbox = NULL, *search_mailbox = NULL, *dir = NULL;
u64_t *children;
+ mailbox_t *mb;
unsigned nchildren, i;
int result = 0;
@@ -198,7 +199,7 @@ static int do_export(char *user, char *base_mailbox, char *basedir, char *outfil
}
/* FIXME: What are the possible error conditions here? */
- db_findmailbox_by_regex(user_idnr, search_mailbox, &children, &nchildren, 0);
+ db_findmailbox_by_regex(user_idnr, search_mailbox, &children, &nchildren, 0, &mb);
/* Decision process for basedir vs. outfile:
* If we're dumping one mailbox for one user, it goes to
diff --git a/imapcommands.c b/imapcommands.c
index 96550c0d..3c288ddd 100644
--- a/imapcommands.c
+++ b/imapcommands.c
@@ -738,8 +738,8 @@ int _ic_list(struct ImapSession *self)
pattern = g_strdup_printf("%s%s", self->args[0], self->args[1]);
TRACE(TRACE_INFO, "search with pattern: [%s]",pattern);
-
- result = db_findmailbox_by_regex(ud->userid, pattern, &children, &nchildren, list_is_lsub);
+
+ result = db_getmailbox_list_by_regex(ud->userid, pattern, &children, &nchildren, list_is_lsub, &mb);
if (result == -1) {
dbmail_imap_session_printf(self, "* BYE internal dbase error\r\n");
g_free(children);
@@ -755,17 +755,13 @@ int _ic_list(struct ImapSession *self)
return 1;
}
- mb = g_new0(mailbox_t,1);
-
shown = g_tree_new_full((GCompareDataFunc)dm_strcmpdata,NULL,(GDestroyNotify)g_free,NULL);
for (i = 0; i < nchildren; i++) {
gboolean show = FALSE;
- if ((db_getmailbox_list_result(children[i], ud->userid, mb) != 0))
- continue;
/* Enforce match of mailbox to pattern. */
- if (! listex_match(pattern, mb->name, MAILBOX_SEPARATOR, 0)) {
+ if (! listex_match(pattern, mb[i].name, MAILBOX_SEPARATOR, 0)) {
if (g_str_has_suffix(pattern,"%")) {
/*
If the "%" wildcard is the last character of a mailbox name argument, matching levels
@@ -773,8 +769,8 @@ int _ic_list(struct ImapSession *self)
mailboxes, they are returned with the \Noselect mailbox name attribute
*/
- TRACE(TRACE_DEBUG, "mailbox [%s] doesn't match pattern [%s]", mb->name, pattern);
- char *m = NULL, **p = g_strsplit(mb->name,MAILBOX_SEPARATOR,0);
+ TRACE(TRACE_DEBUG, "mailbox [%s] doesn't match pattern [%s]", mb[i].name, pattern);
+ char *m = NULL, **p = g_strsplit(mb[i].name,MAILBOX_SEPARATOR,0);
int l = g_strv_length(p);
while (l-- > 1) {
if (p[l]) {
@@ -784,10 +780,10 @@ int _ic_list(struct ImapSession *self)
m = g_strjoinv(MAILBOX_SEPARATOR,p);
if (listex_match(pattern, m, MAILBOX_SEPARATOR, 0)) {
- g_free(mb->name);
- mb->name = m;
- mb->no_select = 1;
- mb->no_children = 0;
+ g_free(mb[i].name);
+ mb[i].name = m;
+ mb[i].no_select = 1;
+ mb[i].no_children = 0;
show = TRUE;
break;
}
@@ -799,15 +795,15 @@ int _ic_list(struct ImapSession *self)
show = TRUE;
}
- if (show && (! g_tree_lookup(shown, mb->name))) {
- char *s = g_strdup(mb->name);
+ if (show && (! g_tree_lookup(shown, mb[i].name))) {
+ char *s = g_strdup(mb[i].name);
g_tree_insert(shown, s, s);
plist = NULL;
- if (mb->no_select)
+ if (mb[i].no_select)
plist = g_list_append(plist, g_strdup("\\noselect"));
- if (mb->no_inferiors)
+ if (mb[i].no_inferiors)
plist = g_list_append(plist, g_strdup("\\noinferiors"));
- if (mb->no_children)
+ if (mb[i].no_children)
plist = g_list_append(plist, g_strdup("\\hasnochildren"));
else
plist = g_list_append(plist, g_strdup("\\haschildren"));
@@ -815,14 +811,13 @@ int _ic_list(struct ImapSession *self)
/* show */
pstring = dbmail_imap_plist_as_string(plist);
dbmail_imap_session_printf(self, "* %s %s \"%s\" \"%s\"\r\n", thisname,
- pstring, MAILBOX_SEPARATOR, mb->name);
+ pstring, MAILBOX_SEPARATOR, mb[i].name);
g_list_destroy(plist);
g_free(pstring);
}
}
-
if (children)
g_free(children);