cmd-thread.c revision 2f25f180578a4c280c9f5fda1cb9f22410084a1e
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen#include "common.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "str.h"
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen#include "ostream.h"
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen#include "commands.h"
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen#include "imap-search-args.h"
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen#include "mail-thread.h"
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainenstatic int imap_thread_write(struct mail_thread_iterate_context *iter,
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen string_t *str, bool root)
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen{
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen const struct mail_thread_child_node *node;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen struct mail_thread_iterate_context *child_iter;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen unsigned int count;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen int ret = 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen count = mail_thread_iterate_count(iter);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (count == 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen if (count == 1 && !root) {
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen /* only one child - special case to avoid extra paranthesis */
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen node = mail_thread_iterate_next(iter, &child_iter);
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen str_printfa(str, "%u", node->uid);
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen if (child_iter != NULL) {
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen str_append_c(str, ' ');
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen T_BEGIN {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen ret = imap_thread_write(child_iter, str, FALSE);
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen } T_END;
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen if (mail_thread_iterate_deinit(&child_iter) < 0)
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen return -1;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen }
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen return ret;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen }
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen while ((node = mail_thread_iterate_next(iter, &child_iter)) != NULL) {
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen if (child_iter == NULL) {
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen /* no children */
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen str_printfa(str, "(%u)", node->uid);
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen } else {
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen /* node with children */
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen str_append_c(str, '(');
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (node->uid != 0)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen str_printfa(str, "%u ", node->uid);
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen T_BEGIN {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen ret = imap_thread_write(child_iter, str, FALSE);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen } T_END;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (mail_thread_iterate_deinit(&child_iter) < 0 ||
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen ret < 0)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return -1;
d67c6dc68cdb90b53434a25ead1590650e4d84e7Timo Sirainen str_append_c(str, ')');
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen }
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen return 0;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen}
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenstatic int
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainenimap_thread_write_reply(struct mail_thread_context *ctx, string_t *str,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen enum mail_thread_type thread_type, bool write_seqs)
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen{
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen struct mail_thread_iterate_context *iter;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int ret;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen iter = mail_thread_iterate_init(ctx, thread_type, write_seqs);
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen str_append(str, "* THREAD ");
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen T_BEGIN {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen ret = imap_thread_write(iter, str, TRUE);
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen } T_END;
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen if (mail_thread_iterate_deinit(&iter) < 0)
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen ret = -1;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen str_append(str, "\r\n");
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen return ret;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen}
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainenstatic int imap_thread(struct client_command_context *cmd,
41e09cca158ab614961e03deac60f12a58235cd3Timo Sirainen struct mail_search_args *search_args,
41e09cca158ab614961e03deac60f12a58235cd3Timo Sirainen enum mail_thread_type thread_type)
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen{
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen struct mail_thread_context *ctx;
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen string_t *str;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen int ret;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen i_assert(thread_type == MAIL_THREAD_REFERENCES ||
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen thread_type == MAIL_THREAD_REFERENCES2);
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen str = str_new(default_pool, 1024);
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen ret = mail_thread_init(cmd->client->mailbox,
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen search_args, &ctx);
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if (ret == 0) {
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen ret = imap_thread_write_reply(ctx, str, thread_type,
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen !cmd->uid);
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen mail_thread_deinit(&ctx);
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen }
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen if (ret == 0) {
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen (void)o_stream_send(cmd->client->output,
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen str_data(str), str_len(str));
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen }
6f90ce01176bd920609d9d12e6419b9ba27c1359Timo Sirainen str_free(&str);
6f90ce01176bd920609d9d12e6419b9ba27c1359Timo Sirainen return ret;
6f90ce01176bd920609d9d12e6419b9ba27c1359Timo Sirainen}
6f90ce01176bd920609d9d12e6419b9ba27c1359Timo Sirainen
a23197a5232f34121b1d32b73f2279c5d2f4491cTimo Sirainenbool cmd_thread(struct client_command_context *cmd)
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen{
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen struct client *client = cmd->client;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen enum mail_thread_type thread_type;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen struct mail_search_args *sargs;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct imap_arg *args;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen const char *charset, *str;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen int ret;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen if (!client_read_args(cmd, 0, 0, &args))
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen return FALSE;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen if (!client_verify_open_mailbox(cmd))
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen return TRUE;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (args->type != IMAP_ARG_ATOM && args->type != IMAP_ARG_STRING) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen client_send_command_error(cmd,
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen "Invalid thread algorithm argument.");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return TRUE;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen }
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen str = IMAP_ARG_STR(args);
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen if (!mail_thread_type_parse(str, &thread_type)) {
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen client_send_command_error(cmd, "Unknown thread algorithm.");
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen return TRUE;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen }
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen args++;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* charset */
9b5a8e766112d24c12499aca85da5ddf24baad25Timo Sirainen if (args->type != IMAP_ARG_ATOM && args->type != IMAP_ARG_STRING) {
9b5a8e766112d24c12499aca85da5ddf24baad25Timo Sirainen client_send_command_error(cmd, "Invalid charset argument.");
9b5a8e766112d24c12499aca85da5ddf24baad25Timo Sirainen return TRUE;
9b5a8e766112d24c12499aca85da5ddf24baad25Timo Sirainen }
9b5a8e766112d24c12499aca85da5ddf24baad25Timo Sirainen charset = IMAP_ARG_STR(args);
9b5a8e766112d24c12499aca85da5ddf24baad25Timo Sirainen args++;
9b5a8e766112d24c12499aca85da5ddf24baad25Timo Sirainen
9b5a8e766112d24c12499aca85da5ddf24baad25Timo Sirainen ret = imap_search_args_build(cmd, args, charset, &sargs);
9b5a8e766112d24c12499aca85da5ddf24baad25Timo Sirainen if (ret <= 0)
9b5a8e766112d24c12499aca85da5ddf24baad25Timo Sirainen return ret < 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = imap_thread(cmd, sargs, thread_type);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_search_args_unref(&sargs);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret < 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen client_send_storage_error(cmd,
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen mailbox_get_storage(client->mailbox));
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen return TRUE;
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen }
137c1851d63c6575ebab35d261380423c4cf2b47Timo Sirainen
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen return cmd_sync(cmd, MAILBOX_SYNC_FLAG_FAST |
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen (cmd->uid ? 0 : MAILBOX_SYNC_FLAG_NO_EXPUNGES),
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen 0, "OK Thread completed.");
d48a2f3288eba53dd10d9d8029ec583d78a977e0Timo Sirainen}
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen