cmd-sort.c revision 2f25f180578a4c280c9f5fda1cb9f22410084a1e
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include "common.h"
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include "buffer.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "commands.h"
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen#include "imap-search-args.h"
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen#include "imap-search.h"
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstruct sort_name {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen enum mail_sort_type type;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen const char *name;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen};
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstatic struct sort_name sort_names[] = {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen { MAIL_SORT_ARRIVAL, "arrival" },
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen { MAIL_SORT_CC, "cc" },
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen { MAIL_SORT_DATE, "date" },
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen { MAIL_SORT_FROM, "from" },
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen { MAIL_SORT_SIZE, "size" },
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen { MAIL_SORT_SUBJECT, "subject" },
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen { MAIL_SORT_TO, "to" },
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen { MAIL_SORT_SEARCH_SCORE, "x-score" },
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen { MAIL_SORT_END, NULL }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen};
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenstatic int
bd63b5b860658b01b1f46f26d406e1e4a9dc019aTimo Sirainenget_sort_program(struct client_command_context *cmd,
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen const struct imap_arg *args,
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen enum mail_sort_type program[MAX_SORT_PROGRAM_SIZE])
70ac869db925653b57f721cd045c467612fd5ee9Timo Sirainen{
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen enum mail_sort_type mask = 0;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen unsigned int i, pos;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen bool reverse, last_reverse;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (args->type == IMAP_ARG_EOL) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen /* empyty list */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen client_send_command_error(cmd, "Empty sort program.");
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return -1;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen pos = 0; reverse = last_reverse = FALSE;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen for (; args->type == IMAP_ARG_ATOM || args->type == IMAP_ARG_STRING;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen args++) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen const char *arg = IMAP_ARG_STR(args);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen last_reverse = strcasecmp(arg, "reverse") == 0;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (last_reverse) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen reverse = !reverse;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen continue;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen for (i = 0; sort_names[i].type != MAIL_SORT_END; i++) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (strcasecmp(arg, sort_names[i].name) == 0)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen break;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (sort_names[i].type == MAIL_SORT_END) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen client_send_command_error(cmd, t_strconcat(
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen "Unknown sort argument: ", arg, NULL));
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return -1;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if ((mask & sort_names[i].type) != 0)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen continue;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen mask |= sort_names[i].type;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen /* @UNSAFE: mask check should prevent us from ever
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen overflowing */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen i_assert(pos < MAX_SORT_PROGRAM_SIZE-1);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen program[pos++] = sort_names[i].type |
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen (reverse ? MAIL_SORT_FLAG_REVERSE : 0);
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen reverse = FALSE;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (last_reverse) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen client_send_command_error(cmd, "Sort list ends with REVERSE.");
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return -1;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen program[pos++] = MAIL_SORT_END;
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (args->type != IMAP_ARG_EOL) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen client_send_command_error(cmd,
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen "Invalid sort list argument.");
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return -1;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen }
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return 0;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen}
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainenbool cmd_sort(struct client_command_context *cmd)
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen{
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen struct imap_search_context *ctx;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen struct mail_search_args *sargs;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen enum mail_sort_type sort_program[MAX_SORT_PROGRAM_SIZE];
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen const struct imap_arg *args;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen const char *charset;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen int ret;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (!client_read_args(cmd, 0, 0, &args))
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen return FALSE;
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (!client_verify_open_mailbox(cmd))
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen return TRUE;
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen /* sort program */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (args->type != IMAP_ARG_LIST) {
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen client_send_command_error(cmd, "Invalid sort argument.");
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen return TRUE;
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen }
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen if (get_sort_program(cmd, IMAP_ARG_LIST_ARGS(args), sort_program) < 0)
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen return TRUE;
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen args++;
250a06cde50c4004ac1cc72279b75a229a7f90f5Timo Sirainen
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen /* charset */
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen if (args->type != IMAP_ARG_ATOM && args->type != IMAP_ARG_STRING) {
1c633f71ec2060e5bfa500a97f34cd881a958ecdTimo Sirainen client_send_command_error(cmd,
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen "Invalid charset argument.");
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen return TRUE;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen }
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen charset = IMAP_ARG_STR(args);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen args++;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen ctx = p_new(cmd->pool, struct imap_search_context, 1);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen ctx->cmd = cmd;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen if ((ret = cmd_search_parse_return_if_found(ctx, &args)) <= 0) {
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen /* error / waiting for unambiguity */
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen return ret < 0;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen }
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen ret = imap_search_args_build(cmd, args, charset, &sargs);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen if (ret <= 0)
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen return ret < 0;
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen return imap_search_start(ctx, sargs, sort_program);
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen}
6a33ecc05e60b511c1ae176ef113546e1012c18fTimo Sirainen