/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "imap-common.h"
#include "buffer.h"
#include "imap-commands.h"
#include "imap-search-args.h"
#include "imap-search.h"
struct sort_name {
enum mail_sort_type type;
const char *name;
};
static struct sort_name sort_names[] = {
{ MAIL_SORT_ARRIVAL, "arrival" },
{ MAIL_SORT_CC, "cc" },
{ MAIL_SORT_DATE, "date" },
{ MAIL_SORT_FROM, "from" },
{ MAIL_SORT_SIZE, "size" },
{ MAIL_SORT_SUBJECT, "subject" },
{ MAIL_SORT_TO, "to" },
{ MAIL_SORT_RELEVANCY, "x-score" }, /* FIXME: obsolete */
{ MAIL_SORT_RELEVANCY, "relevancy" },
{ MAIL_SORT_DISPLAYFROM, "displayfrom" },
{ MAIL_SORT_DISPLAYTO, "displayto" },
{ MAIL_SORT_END, NULL }
};
static int
get_sort_program(struct client_command_context *cmd,
const struct imap_arg *args,
enum mail_sort_type program[MAX_SORT_PROGRAM_SIZE])
{
enum mail_sort_type mask = 0;
const char *arg;
unsigned int i, pos;
bool reverse, last_reverse;
if (IMAP_ARG_IS_EOL(args)) {
/* empty list */
client_send_command_error(cmd, "Empty sort program.");
return -1;
}
pos = 0; reverse = last_reverse = FALSE;
for (; imap_arg_get_astring(args, &arg); args++) {
last_reverse = strcasecmp(arg, "reverse") == 0;
if (last_reverse) {
reverse = !reverse;
continue;
}
for (i = 0; sort_names[i].type != MAIL_SORT_END; i++) {
if (strcasecmp(arg, sort_names[i].name) == 0)
break;
}
if (sort_names[i].type == MAIL_SORT_END) {
client_send_command_error(cmd, t_strconcat(
"Unknown sort argument: ", arg, NULL));
return -1;
}
if ((mask & sort_names[i].type) != 0)
continue;
mask |= sort_names[i].type;
/* @UNSAFE: mask check should prevent us from ever
overflowing */
i_assert(pos < MAX_SORT_PROGRAM_SIZE-1);
program[pos++] = sort_names[i].type |
(reverse ? MAIL_SORT_FLAG_REVERSE : 0);
reverse = FALSE;
}
if (last_reverse) {
client_send_command_error(cmd, "Sort list ends with REVERSE.");
return -1;
}
program[pos] = MAIL_SORT_END;
if (!IMAP_ARG_IS_EOL(args)) {
client_send_command_error(cmd,
"Invalid sort list argument.");
return -1;
}
return 0;
}
bool cmd_sort(struct client_command_context *cmd)
{
struct imap_search_context *ctx;
struct mail_search_args *sargs;
enum mail_sort_type sort_program[MAX_SORT_PROGRAM_SIZE];
const struct imap_arg *args, *list_args;
const char *charset;
int ret;
if (!client_read_args(cmd, 0, 0, &args))
return FALSE;
if (!client_verify_open_mailbox(cmd))
return TRUE;
ctx = p_new(cmd->pool, struct imap_search_context, 1);
ctx->cmd = cmd;
if ((ret = cmd_search_parse_return_if_found(ctx, &args)) <= 0) {
/* error / waiting for unambiguity */
return ret < 0;
}
/* sort program */
if (!imap_arg_get_list(args, &list_args)) {
client_send_command_error(cmd, "Invalid sort argument.");
imap_search_context_free(ctx);
return TRUE;
}
if (get_sort_program(cmd, list_args, sort_program) < 0) {
imap_search_context_free(ctx);
return TRUE;
}
args++;
/* charset */
if (!imap_arg_get_astring(args, &charset)) {
client_send_command_error(cmd, "Invalid charset argument.");
imap_search_context_free(ctx);
return TRUE;
}
args++;
ret = imap_search_args_build(cmd, args, charset, &sargs);
if (ret <= 0) {
imap_search_context_free(ctx);
return ret < 0;
}
return imap_search_start(ctx, sargs, sort_program);
}