view src/imap/cmd-sort.c @ 6429:65c69a53a7be HEAD

Replaced my Copyright notices. The year range always ends with 2007 now. My name was replaced with "Dovecot authors". In many cases I didn't really even own the copyright, so this is more correct.
author Timo Sirainen <tss@iki.fi>
date Sun, 16 Sep 2007 14:34:22 +0300
parents 7cad076906eb
children 7ed926ed7aa4
line wrap: on
line source

/* Copyright (c) 2002-2007 Dovecot authors, see the included COPYING file */

#include "common.h"
#include "buffer.h"
#include "commands.h"
#include "imap-search.h"
#include "imap-sort.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_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;
	unsigned int i, pos;
	bool reverse;

	if (args->type == IMAP_ARG_EOL) {
		/* empyty list */
		client_send_command_error(cmd, "Empty sort program.");
		return -1;
	}

	pos = 0; reverse = FALSE;
	for (; args->type == IMAP_ARG_ATOM || args->type == IMAP_ARG_STRING;
	     args++) {
		const char *arg = IMAP_ARG_STR(args);

		if (strcasecmp(arg, "reverse") == 0) {
			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;
	}

	program[pos++] = MAIL_SORT_END;

	if (args->type != IMAP_ARG_EOL) {
		client_send_command_error(cmd,
					  "Invalid sort list argument.");
		return -1;
	}

	return 0;
}

bool cmd_sort(struct client_command_context *cmd)
{
	struct client *client = cmd->client;
	struct mail_search_arg *sargs;
	enum mail_sort_type sorting[MAX_SORT_PROGRAM_SIZE];
	const struct imap_arg *args;
	int args_count;
	pool_t pool;
	const char *error, *charset;

	args_count = imap_parser_read_args(cmd->parser, 0, 0, &args);
	if (args_count == -2)
		return FALSE;
	client->input_lock = NULL;

	if (args_count < 3) {
		client_send_command_error(cmd, args_count < 0 ? NULL :
					  "Missing or invalid arguments.");
		return TRUE;
	}

	if (!client_verify_open_mailbox(cmd))
		return TRUE;

	/* sort program */
	if (args->type != IMAP_ARG_LIST) {
		client_send_command_error(cmd, "Invalid sort argument.");
		return TRUE;
	}

	if (get_sort_program(cmd, IMAP_ARG_LIST_ARGS(args), sorting) < 0)
		return TRUE;
	args++;

	/* charset */
	if (args->type != IMAP_ARG_ATOM && args->type != IMAP_ARG_STRING) {
		client_send_command_error(cmd,
					  "Invalid charset argument.");
		return TRUE;
	}
	charset = IMAP_ARG_STR(args);
	args++;

	pool = pool_alloconly_create("mail_search_args", 2048);

	sargs = imap_search_args_build(pool, client->mailbox, args, &error);
	if (sargs == NULL) {
		/* error in search arguments */
		client_send_tagline(cmd, t_strconcat("NO ", error, NULL));
	} else if (imap_sort(cmd, charset, sargs, sorting) == 0) {
		pool_unref(&pool);
		return cmd_sync(cmd, MAILBOX_SYNC_FLAG_FAST |
				(cmd->uid ? 0 : MAILBOX_SYNC_FLAG_NO_EXPUNGES),
				0, "OK Sort completed.");
	} else {
		client_send_storage_error(cmd,
					  mailbox_get_storage(client->mailbox));
	}

	pool_unref(&pool);
	return TRUE;
}