cmd-sort.c revision 828edf966ee46f65ec5d907f310cab270e7e1088
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "common.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "buffer.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "commands.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "imap-search.h"
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen#include "imap-sort.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstruct sort_name {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen enum mail_sort_type type;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const char *name;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen};
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic struct sort_name sort_names[] = {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen { MAIL_SORT_ARRIVAL, "arrival" },
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen { MAIL_SORT_CC, "cc" },
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen { MAIL_SORT_DATE, "date" },
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen { MAIL_SORT_FROM, "from" },
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen { MAIL_SORT_SIZE, "size" },
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen { MAIL_SORT_SUBJECT, "subject" },
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen { MAIL_SORT_TO, "to" },
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen { MAIL_SORT_END, NULL }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen};
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic int
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainenget_sort_program(struct client_command_context *cmd,
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen const struct imap_arg *args,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen enum mail_sort_type program[MAX_SORT_PROGRAM_SIZE])
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen enum mail_sort_type mask = 0;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen unsigned int i, pos;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen bool reverse, last_reverse;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (args->type == IMAP_ARG_EOL) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* empyty list */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_send_command_error(cmd, "Empty sort program.");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen pos = 0; reverse = last_reverse = FALSE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen for (; args->type == IMAP_ARG_ATOM || args->type == IMAP_ARG_STRING;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen args++) {
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen const char *arg = IMAP_ARG_STR(args);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen last_reverse = strcasecmp(arg, "reverse") == 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (last_reverse) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen reverse = !reverse;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen continue;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen for (i = 0; sort_names[i].type != MAIL_SORT_END; i++) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (strcasecmp(arg, sort_names[i].name) == 0)
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen break;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (sort_names[i].type == MAIL_SORT_END) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_send_command_error(cmd, t_strconcat(
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen "Unknown sort argument: ", arg, NULL));
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen return -1;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen }
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if ((mask & sort_names[i].type) != 0)
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen continue;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mask |= sort_names[i].type;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen /* @UNSAFE: mask check should prevent us from ever
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen overflowing */
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen i_assert(pos < MAX_SORT_PROGRAM_SIZE-1);
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen program[pos++] = sort_names[i].type |
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen (reverse ? MAIL_SORT_FLAG_REVERSE : 0);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen reverse = FALSE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (last_reverse) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_send_command_error(cmd, "Sort list ends with REVERSE.");
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen return -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen program[pos++] = MAIL_SORT_END;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (args->type != IMAP_ARG_EOL) {
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen client_send_command_error(cmd,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "Invalid sort list argument.");
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen return -1;
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen }
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen return 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenbool cmd_sort(struct client_command_context *cmd)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct client *client = cmd->client;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct mail_search_args *sargs;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen enum mail_sort_type sorting[MAX_SORT_PROGRAM_SIZE];
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const struct imap_arg *args;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen int args_count;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const char *charset;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen int ret;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen args_count = imap_parser_read_args(cmd->parser, 0, 0, &args);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (args_count == -2)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return FALSE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client->input_lock = NULL;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (args_count < 3) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_send_command_error(cmd, args_count < 0 ? NULL :
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "Missing or invalid arguments.");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return TRUE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (!client_verify_open_mailbox(cmd))
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return TRUE;
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen /* sort program */
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen if (args->type != IMAP_ARG_LIST) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen client_send_command_error(cmd, "Invalid sort argument.");
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return TRUE;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (get_sort_program(cmd, IMAP_ARG_LIST_ARGS(args), sorting) < 0)
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return TRUE;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen args++;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen /* charset */
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen if (args->type != IMAP_ARG_ATOM && args->type != IMAP_ARG_STRING) {
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen client_send_command_error(cmd,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen "Invalid charset argument.");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return TRUE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen charset = IMAP_ARG_STR(args);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen args++;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen ret = imap_search_args_build(cmd, args, charset, &sargs);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (ret <= 0)
a5e89374cb2fb2cad575fee6c3b33a9487ab9b3aTimo Sirainen return ret < 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ret = imap_sort(cmd, sargs, sorting);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_search_args_unref(&sargs);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (ret < 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_send_storage_error(cmd,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mailbox_get_storage(client->mailbox));
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return TRUE;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return cmd_sync(cmd, MAILBOX_SYNC_FLAG_FAST |
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen (cmd->uid ? 0 : MAILBOX_SYNC_FLAG_NO_EXPUNGES),
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen 0, "OK Sort completed.");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen