view src/imap/imap-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 5f03738219a6
children 1a3604c8ee05
line wrap: on
line source

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

/* Implementation of draft-ietf-imapext-sort-10 sorting algorithm.
   Pretty messy code actually, adding any sort types requires care.
   This is pretty fast however and takes only as much memory as needed to be
   reasonably fast. */

#include "common.h"
#include "array.h"
#include "hash.h"
#include "ostream.h"
#include "str.h"
#include "imap-base-subject.h"
#include "mail-storage.h"
#include "message-address.h"
#include "imap-sort.h"

#include <stdlib.h>

#define MAX_WANTED_HEADERS 10
#define STRBUF_SIZE 1024

#define IS_SORT_STRING(type) \
	((type) == MAIL_SORT_CC || (type) == MAIL_SORT_FROM || \
	 (type) == MAIL_SORT_SUBJECT || (type) == MAIL_SORT_TO)

#define IS_SORT_TIME(type) \
	((type) == MAIL_SORT_ARRIVAL || (type) == MAIL_SORT_DATE)

struct sort_context {
	enum mail_sort_type sort_program[MAX_SORT_PROGRAM_SIZE];

	struct mailbox *box;
	struct ostream *output;
	string_t *str;

	bool written;
};

int imap_sort(struct client_command_context *cmd, const char *charset,
	      struct mail_search_arg *args,
	      const enum mail_sort_type *sort_program)
{
	struct client *client = cmd->client;
	const char *wanted_headers[2];
	enum mail_fetch_field wanted_fields;
	struct mail_search_context *search_ctx;
	struct mailbox_transaction_context *t;
	struct mailbox_header_lookup_ctx *headers_ctx;
	struct mail *mail;
	string_t *str;
	bool written = FALSE;
	int ret;

	wanted_fields = 0;
	wanted_headers[0] = wanted_headers[1] = NULL;
	switch (*sort_program & MAIL_SORT_MASK) {
	case MAIL_SORT_ARRIVAL:
		wanted_fields = MAIL_FETCH_RECEIVED_DATE;
		break;
	case MAIL_SORT_CC:
		wanted_headers[0] = "Cc";
		break;
	case MAIL_SORT_DATE:
		wanted_fields = MAIL_FETCH_DATE;
		break;
	case MAIL_SORT_FROM:
		wanted_headers[0] = "From";
		break;
	case MAIL_SORT_SIZE:
		wanted_fields = MAIL_FETCH_VIRTUAL_SIZE;
		break;
	case MAIL_SORT_SUBJECT:
		wanted_headers[0] = "Subject";
		break;
	case MAIL_SORT_TO:
		wanted_headers[0] = "To";
		break;
	}

	headers_ctx = wanted_headers[0] == NULL ? NULL :
		mailbox_header_lookup_init(client->mailbox, wanted_headers);

	t = mailbox_transaction_begin(client->mailbox, 0);
	search_ctx = mailbox_search_init(t, charset, args, sort_program);

	str = t_str_new(STRBUF_SIZE);
	str_append(str, "* SORT");

	mail = mail_alloc(t, wanted_fields, headers_ctx);
	while (mailbox_search_next(search_ctx, mail) > 0) {
		if (str_len(str) >= STRBUF_SIZE-MAX_INT_STRLEN) {
			o_stream_send(client->output, str_data(str),
				      str_len(str));
			str_truncate(str, 0);
			written = TRUE;
		}
		str_printfa(str, " %u", cmd->uid ? mail->uid : mail->seq);
	}
	ret = mailbox_search_deinit(&search_ctx);
	mail_free(&mail);

	if (mailbox_transaction_commit(&t, 0) < 0)
		ret = -1;

	if (written || ret == 0) {
		str_append(str, "\r\n");
		o_stream_send(client->output, str_data(str), str_len(str));
	}

	if (headers_ctx != NULL)
		mailbox_header_lookup_deinit(&headers_ctx);
	return ret;
}