cmd-sort.c revision d43bed2d458520fd01c28229ce2b178a4593a4a7
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen#include "common.h"
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen#include "buffer.h"
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen#include "commands.h"
e5b8b3a57993ab957d389e1c7253698bcd1e6cb1Timo Sirainen#include "imap-search-args.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "imap-search.h"
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstruct sort_name {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen enum mail_sort_type type;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen const char *name;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen};
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic struct sort_name sort_names[] = {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen { MAIL_SORT_ARRIVAL, "arrival" },
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen { MAIL_SORT_CC, "cc" },
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen { MAIL_SORT_DATE, "date" },
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen { MAIL_SORT_FROM, "from" },
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen { MAIL_SORT_SIZE, "size" },
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen { MAIL_SORT_SUBJECT, "subject" },
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen { MAIL_SORT_TO, "to" },
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen { MAIL_SORT_SEARCH_SCORE, "x-score" },
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen { MAIL_SORT_END, NULL }
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen};
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
a04cd96888653891272a512f7735121193af7b35Timo Sirainenstatic int
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainenget_sort_program(struct client_command_context *cmd,
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainen const struct imap_arg *args,
a04cd96888653891272a512f7735121193af7b35Timo Sirainen enum mail_sort_type program[MAX_SORT_PROGRAM_SIZE])
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen{
a04cd96888653891272a512f7735121193af7b35Timo Sirainen enum mail_sort_type mask = 0;
a04cd96888653891272a512f7735121193af7b35Timo Sirainen unsigned int i, pos;
828edf966ee46f65ec5d907f310cab270e7e1088Timo Sirainen bool reverse, last_reverse;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
63946971b08cfb1eec698c28569e1c4aa237852dTimo Sirainen if (args->type == IMAP_ARG_EOL) {
63946971b08cfb1eec698c28569e1c4aa237852dTimo Sirainen /* empyty list */
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen client_send_command_error(cmd, "Empty sort program.");
a04cd96888653891272a512f7735121193af7b35Timo Sirainen return -1;
63946971b08cfb1eec698c28569e1c4aa237852dTimo Sirainen }
63946971b08cfb1eec698c28569e1c4aa237852dTimo Sirainen
828edf966ee46f65ec5d907f310cab270e7e1088Timo Sirainen pos = 0; reverse = last_reverse = FALSE;
a04cd96888653891272a512f7735121193af7b35Timo Sirainen for (; args->type == IMAP_ARG_ATOM || args->type == IMAP_ARG_STRING;
a04cd96888653891272a512f7735121193af7b35Timo Sirainen args++) {
4525c4a8f8d1a6365e4469c0c8f46575400a9a67Timo Sirainen const char *arg = IMAP_ARG_STR(args);
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
828edf966ee46f65ec5d907f310cab270e7e1088Timo Sirainen last_reverse = strcasecmp(arg, "reverse") == 0;
828edf966ee46f65ec5d907f310cab270e7e1088Timo Sirainen if (last_reverse) {
a04cd96888653891272a512f7735121193af7b35Timo Sirainen reverse = !reverse;
a04cd96888653891272a512f7735121193af7b35Timo Sirainen continue;
a04cd96888653891272a512f7735121193af7b35Timo Sirainen }
a04cd96888653891272a512f7735121193af7b35Timo Sirainen
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen for (i = 0; sort_names[i].type != MAIL_SORT_END; i++) {
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen if (strcasecmp(arg, sort_names[i].name) == 0)
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen break;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen }
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen if (sort_names[i].type == MAIL_SORT_END) {
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen client_send_command_error(cmd, t_strconcat(
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen "Unknown sort argument: ", arg, NULL));
a04cd96888653891272a512f7735121193af7b35Timo Sirainen return -1;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen }
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
a04cd96888653891272a512f7735121193af7b35Timo Sirainen if ((mask & sort_names[i].type) != 0)
a04cd96888653891272a512f7735121193af7b35Timo Sirainen continue;
a04cd96888653891272a512f7735121193af7b35Timo Sirainen mask |= sort_names[i].type;
a04cd96888653891272a512f7735121193af7b35Timo Sirainen
a04cd96888653891272a512f7735121193af7b35Timo Sirainen /* @UNSAFE: mask check should prevent us from ever
a04cd96888653891272a512f7735121193af7b35Timo Sirainen overflowing */
a04cd96888653891272a512f7735121193af7b35Timo Sirainen i_assert(pos < MAX_SORT_PROGRAM_SIZE-1);
a04cd96888653891272a512f7735121193af7b35Timo Sirainen program[pos++] = sort_names[i].type |
a04cd96888653891272a512f7735121193af7b35Timo Sirainen (reverse ? MAIL_SORT_FLAG_REVERSE : 0);
a04cd96888653891272a512f7735121193af7b35Timo Sirainen reverse = FALSE;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen }
828edf966ee46f65ec5d907f310cab270e7e1088Timo Sirainen if (last_reverse) {
828edf966ee46f65ec5d907f310cab270e7e1088Timo Sirainen client_send_command_error(cmd, "Sort list ends with REVERSE.");
828edf966ee46f65ec5d907f310cab270e7e1088Timo Sirainen return -1;
828edf966ee46f65ec5d907f310cab270e7e1088Timo Sirainen }
a04cd96888653891272a512f7735121193af7b35Timo Sirainen program[pos++] = MAIL_SORT_END;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen if (args->type != IMAP_ARG_EOL) {
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen client_send_command_error(cmd,
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen "Invalid sort list argument.");
a04cd96888653891272a512f7735121193af7b35Timo Sirainen return -1;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen }
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
a04cd96888653891272a512f7735121193af7b35Timo Sirainen return 0;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen}
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool cmd_sort(struct client_command_context *cmd)
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct imap_search_context *ctx;
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen struct mail_search_args *sargs;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen enum mail_sort_type sort_program[MAX_SORT_PROGRAM_SIZE];
f1e9611e93dcb3b745c1904029084fa81644e1b3Timo Sirainen const struct imap_arg *args;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen int args_count;
97cfe59cd16ce624e58e8d9b6003d1e29d75b3d2Timo Sirainen const char *charset;
97cfe59cd16ce624e58e8d9b6003d1e29d75b3d2Timo Sirainen int ret;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen args_count = imap_parser_read_args(cmd->parser, 0, 0, &args);
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen if (args_count == -2)
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen cmd->client->input_lock = NULL;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen if (args_count < 3) {
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen client_send_command_error(cmd, args_count < 0 ? NULL :
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen "Missing or invalid arguments.");
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen return TRUE;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen }
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen if (!client_verify_open_mailbox(cmd))
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen return TRUE;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen /* sort program */
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen if (args->type != IMAP_ARG_LIST) {
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen client_send_command_error(cmd, "Invalid sort argument.");
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen return TRUE;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen }
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (get_sort_program(cmd, IMAP_ARG_LIST_ARGS(args), sort_program) < 0)
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen return TRUE;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen args++;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen /* charset */
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen if (args->type != IMAP_ARG_ATOM && args->type != IMAP_ARG_STRING) {
e60a349c641bb2f4723e4a395a25f55531682d2bTimo Sirainen client_send_command_error(cmd,
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen "Invalid charset argument.");
fd4632d0060b2e9eef513b544ccff1e26d1fc222Timo Sirainen return TRUE;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen }
4525c4a8f8d1a6365e4469c0c8f46575400a9a67Timo Sirainen charset = IMAP_ARG_STR(args);
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen args++;
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx = p_new(cmd->pool, struct imap_search_context, 1);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->cmd = cmd;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ret = cmd_search_parse_return_if_found(ctx, &args)) <= 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* error / waiting for unambiguity */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return ret < 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen ret = imap_search_args_build(cmd, args, charset, &sargs);
97cfe59cd16ce624e58e8d9b6003d1e29d75b3d2Timo Sirainen if (ret <= 0)
97cfe59cd16ce624e58e8d9b6003d1e29d75b3d2Timo Sirainen return ret < 0;
97cfe59cd16ce624e58e8d9b6003d1e29d75b3d2Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return imap_search_start(ctx, sargs, sort_program);
55a7410569737197afb302b07b488973324b0cc5Timo Sirainen}