summaryrefslogtreecommitdiffstats
path: root/src/imap/cmd-sort.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/imap/cmd-sort.c')
-rw-r--r--src/imap/cmd-sort.c142
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);
+}