dovecot-2.1: imap: Implemented THREAD=ORDEREDSUBJECT extension.
dovecot at dovecot.org
dovecot at dovecot.org
Wed Aug 15 13:43:22 EEST 2012
details: http://hg.dovecot.org/dovecot-2.1/rev/670f467ff5c5
changeset: 14670:670f467ff5c5
user: Timo Sirainen <tss at iki.fi>
date: Wed Aug 15 13:43:16 2012 +0300
description:
imap: Implemented THREAD=ORDEREDSUBJECT extension.
diffstat:
configure.in | 2 +-
src/imap/cmd-thread.c | 148 +++++++++++++++++++++++++++++++++++++++++-
src/lib-storage/mail-thread.c | 2 +
3 files changed, 150 insertions(+), 2 deletions(-)
diffs (196 lines):
diff -r 501f22bf92c3 -r 670f467ff5c5 configure.in
--- a/configure.in Wed Aug 15 12:37:34 2012 +0300
+++ b/configure.in Wed Aug 15 13:43:16 2012 +0300
@@ -2708,7 +2708,7 @@
dnl IDLE doesn't really belong to banner. It's there just to make Blackberries
dnl happy, because otherwise BIS server disables push email.
capability_banner="IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE"
-capability="$capability_banner SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS MULTIAPPEND UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE"
+capability="$capability_banner SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE"
AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", IMAP capabilities)
AC_DEFINE_UNQUOTED(CAPABILITY_BANNER_STRING, "$capability_banner", IMAP capabilities advertised in banner)
diff -r 501f22bf92c3 -r 670f467ff5c5 src/imap/cmd-thread.c
--- a/src/imap/cmd-thread.c Wed Aug 15 12:37:34 2012 +0300
+++ b/src/imap/cmd-thread.c Wed Aug 15 13:43:16 2012 +0300
@@ -3,6 +3,7 @@
#include "imap-common.h"
#include "str.h"
#include "ostream.h"
+#include "imap-base-subject.h"
#include "imap-commands.h"
#include "imap-search-args.h"
#include "mail-thread.h"
@@ -102,6 +103,148 @@
return ret;
}
+struct orderedsubject_thread {
+ time_t timestamp;
+ ARRAY_TYPE(uint32_t) msgs;
+};
+
+static int orderedsubject_thread_cmp(const struct orderedsubject_thread *t1,
+ const struct orderedsubject_thread *t2)
+{
+ const uint32_t *m1, *m2;
+
+ if (t1->timestamp < t2->timestamp)
+ return -1;
+ if (t1->timestamp > t2->timestamp)
+ return 1;
+
+ m1 = array_idx(&t1->msgs, 0);
+ m2 = array_idx(&t2->msgs, 0);
+ if (*m1 < *m2)
+ return -1;
+ if (*m1 > *m2)
+ return 1;
+ i_unreached();
+}
+
+static void
+imap_orderedsubject_thread_write(struct ostream *output, string_t *reply,
+ const struct orderedsubject_thread *thread)
+{
+ const uint32_t *msgs;
+ unsigned int i, count;
+
+ if (str_len(reply) > 128-10) {
+ o_stream_send(output, str_data(reply), str_len(reply));
+ str_truncate(reply, 0);
+ }
+
+ msgs = array_get(&thread->msgs, &count);
+ switch (count) {
+ case 1:
+ str_printfa(reply, "(%u)", msgs[0]);
+ break;
+ case 2:
+ str_printfa(reply, "(%u %u)", msgs[0], msgs[1]);
+ break;
+ default:
+ /* (1 (2)(3)) */
+ str_printfa(reply, "(%u ", msgs[0]);
+ for (i = 1; i < count; i++) {
+ if (str_len(reply) > 128-10) {
+ o_stream_send(output, str_data(reply),
+ str_len(reply));
+ str_truncate(reply, 0);
+ }
+ str_printfa(reply, "(%u)", msgs[i]);
+ }
+ str_append_c(reply, ')');
+ }
+}
+
+static int imap_thread_orderedsubject(struct client_command_context *cmd,
+ struct mail_search_args *search_args)
+{
+ static const enum mail_sort_type sort_program[] = {
+ MAIL_SORT_SUBJECT,
+ MAIL_SORT_DATE,
+ 0
+ };
+ struct mailbox_transaction_context *trans;
+ struct mail_search_context *search_ctx;
+ struct mail *mail;
+ string_t *prev_subject, *reply;
+ const char *subject, *base_subject;
+ pool_t pool;
+ ARRAY_DEFINE(threads, struct orderedsubject_thread);
+ const struct orderedsubject_thread *thread;
+ struct orderedsubject_thread *cur_thread = NULL;
+ uint32_t num;
+ int ret;
+
+ prev_subject = str_new(default_pool, 128);
+
+ /* first read all of the threads into memory */
+ pool = pool_alloconly_create("orderedsubject thread", 1024);
+ i_array_init(&threads, 128);
+ trans = mailbox_transaction_begin(cmd->client->mailbox, 0);
+ search_ctx = mailbox_search_init(trans, search_args, sort_program,
+ 0, NULL);
+ while (mailbox_search_next(search_ctx, &mail)) {
+ if (mail_get_first_header(mail, "Subject", &subject) <= 0)
+ subject = "";
+ T_BEGIN {
+ base_subject = imap_get_base_subject_cased(
+ pool_datastack_create(), subject, NULL);
+ if (strcmp(str_c(prev_subject), base_subject) != 0) {
+ /* thread changed */
+ cur_thread = NULL;
+ }
+ str_truncate(prev_subject, 0);
+ str_append(prev_subject, base_subject);
+ } T_END;
+
+ if (cur_thread == NULL) {
+ /* starting a new thread. get the first message's
+ date */
+ cur_thread = array_append_space(&threads);
+ if (mail_get_date(mail, &cur_thread->timestamp, NULL) == 0 &&
+ cur_thread->timestamp == 0) {
+ (void)mail_get_received_date(mail,
+ &cur_thread->timestamp);
+ }
+ p_array_init(&cur_thread->msgs, pool, 4);
+ }
+ num = cmd->uid ? mail->uid : mail->seq;
+ array_append(&cur_thread->msgs, &num, 1);
+ }
+ str_free(&prev_subject);
+ ret = mailbox_search_deinit(&search_ctx);
+ (void)mailbox_transaction_commit(&trans);
+ if (ret < 0) {
+ array_free(&threads);
+ pool_unref(&pool);
+ return -1;
+ }
+
+ /* sort the threads by their first message's timestamp */
+ array_sort(&threads, orderedsubject_thread_cmp);
+
+ /* write the threads to client */
+ reply = t_str_new(128);
+ str_append(reply, "* THREAD ");
+ array_foreach(&threads, thread) {
+ imap_orderedsubject_thread_write(cmd->client->output,
+ reply, thread);
+ }
+ str_append(reply, "\r\n");
+ o_stream_send(cmd->client->output, str_data(reply), str_len(reply));
+
+ array_free(&threads);
+ pool_unref(&pool);
+ return 0;
+}
+
bool cmd_thread(struct client_command_context *cmd)
{
struct client *client = cmd->client;
@@ -133,7 +276,10 @@
if (ret <= 0)
return ret < 0;
- ret = imap_thread(cmd, sargs, thread_type);
+ if (thread_type != MAIL_THREAD_ORDEREDSUBJECT)
+ ret = imap_thread(cmd, sargs, thread_type);
+ else
+ ret = imap_thread_orderedsubject(cmd, sargs);
mail_search_args_unref(&sargs);
if (ret < 0) {
client_send_storage_error(cmd,
diff -r 501f22bf92c3 -r 670f467ff5c5 src/lib-storage/mail-thread.c
--- a/src/lib-storage/mail-thread.c Wed Aug 15 12:37:34 2012 +0300
+++ b/src/lib-storage/mail-thread.c Wed Aug 15 13:43:16 2012 +0300
@@ -9,6 +9,8 @@
*type_r = MAIL_THREAD_REFERENCES;
else if (strcasecmp(str, "REFS") == 0)
*type_r = MAIL_THREAD_REFS;
+ else if (strcasecmp(str, "ORDEREDSUBJECT") == 0)
+ *type_r = MAIL_THREAD_ORDEREDSUBJECT;
else
return FALSE;
return TRUE;
More information about the dovecot-cvs
mailing list