diff options
Diffstat (limited to 'src/imap/cmd-sort.c')
-rw-r--r-- | src/imap/cmd-sort.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/imap/cmd-sort.c b/src/imap/cmd-sort.c new file mode 100644 index 0000000..6515a67 --- /dev/null +++ b/src/imap/cmd-sort.c @@ -0,0 +1,142 @@ +/* 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); +} |