From c03d2eb5128671bf602338c0eb497a07e7823e96 Mon Sep 17 00:00:00 2001 From: James Cloos Date: Sat, 16 Oct 2010 19:05:51 -0400 Subject: Do IMAP LIST/LSUB commands with a single query Signed-off-by: James Cloos --- check_dbmail_db.c | 5 +-- db.c | 92 ++++++++++++++++++++++++++++++++++++++++--------------- db.h | 6 +++- dbmail-user.c | 3 +- export.c | 3 +- imapcommands.c | 35 +++++++++------------ 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); -- cgit v1.2.3