index-search.c revision fd4632d0060b2e9eef513b544ccff1e26d1fc222
/* Copyright (C) 2002 Timo Sirainen */
#include "lib.h"
#include "istream.h"
#include "ostream.h"
#include "mmap-util.h"
#include "message-date.h"
#include "message-size.h"
#include "message-body-search.h"
#include "message-header-search.h"
#include "imap-date.h"
#include "imap-envelope.h"
#include "index-storage.h"
#include "index-sort.h"
#include "mail-index-util.h"
#include "mail-modifylog.h"
#include "mail-custom-flags.h"
#include "mail-search.h"
#include "mail-thread.h"
#include <stdlib.h>
#include <ctype.h>
STMT_START { \
} STMT_END
#define TXT_UNKNOWN_CHARSET "[BADCHARSET] Unknown charset"
#define TXT_INVALID_SEARCH_KEY "Invalid search key"
struct search_index_context {
struct index_mailbox *ibox;
struct mail_index_record *rec;
unsigned int client_seq;
const char *charset;
const char *error;
unsigned int cached:1;
unsigned int threading:1;
/* for threading: */
};
struct search_header_context {
struct search_index_context *index_context;
struct mail_search_arg *args;
unsigned int custom_header:1;
unsigned int threading:1;
};
struct search_body_context {
struct search_index_context *index_ctx;
struct message_part *part;
};
unsigned int max_num)
{
while (*set != '\0') {
if (*set == '*') {
set++;
} else {
num = 0;
set++;
}
}
return TRUE;
if (*set == '\0')
return FALSE;
} else if (*set == ':') {
set++;
if (*set == '*') {
set++;
return TRUE;
} else {
num2 = 0;
set++;
}
return TRUE;
}
if (*set != ',')
return FALSE;
}
set++;
}
return FALSE;
}
{
num = 0;
while (*str != '\0') {
return 0;
str++;
}
return num;
}
{
const char **custom_flags;
int i;
return FALSE;
for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
if (custom_flags[i] != NULL &&
(1 << (MAIL_CUSTOM_FLAG_1_BIT+i));
}
}
return FALSE;
}
/* Returns >0 = matched, 0 = not matched, -1 = unknown */
struct mail_index_record *rec,
unsigned int client_seq,
enum mail_search_arg_type type,
const char *value)
{
switch (type) {
case SEARCH_ALL:
return TRUE;
case SEARCH_SET:
case SEARCH_UID:
/* flags */
case SEARCH_ANSWERED:
case SEARCH_DELETED:
case SEARCH_DRAFT:
case SEARCH_FLAGGED:
case SEARCH_SEEN:
case SEARCH_RECENT:
case SEARCH_KEYWORD:
default:
return -1;
}
}
{
case -1:
/* unknown */
break;
case 0:
break;
default:
break;
}
}
static struct imap_message_cache *
{
}
}
/* Returns >0 = matched, 0 = not matched, -1 = unknown */
enum mail_search_arg_type type,
const char *value)
{
switch (type) {
/* internal dates */
case SEARCH_BEFORE:
case SEARCH_ON:
case SEARCH_SINCE:
return -1;
return 0;
switch (type) {
case SEARCH_BEFORE:
return internal_date < search_time;
case SEARCH_ON:
return internal_date >= search_time &&
case SEARCH_SINCE:
return internal_date >= search_time;
default:
/* unreachable */
break;
}
/* sizes */
case SEARCH_SMALLER:
case SEARCH_LARGER:
return -1;
if (type == SEARCH_SMALLER)
return virtual_size < search_size;
else
return virtual_size > search_size;
default:
return -1;
}
}
{
case -1:
/* unknown */
break;
case 0:
break;
default:
break;
}
}
const char *sent_value)
{
int timezone_offset;
if (sent_value == NULL)
return 0;
return 0;
/* NOTE: Latest IMAP4rev1 draft specifies that timezone is ignored
in searches. */
return 0;
switch (type) {
case SEARCH_SENTBEFORE:
return sent_time < search_time;
case SEARCH_SENTON:
return sent_time >= search_time &&
case SEARCH_SENTSINCE:
return sent_time >= search_time;
default:
i_unreached();
}
}
static struct header_search_context *
struct mail_search_arg *arg)
{
int unknown_charset;
}
}
}
}
/* Returns >0 = matched, 0 = not matched, -1 = unknown */
struct mail_search_arg *arg)
{
enum imap_envelope_field env_field;
struct header_search_context *hdr_search_ctx;
int ret;
case SEARCH_SENTBEFORE:
case SEARCH_SENTON:
case SEARCH_SENTSINCE:
break;
case SEARCH_FROM:
break;
case SEARCH_TO:
break;
case SEARCH_CC:
break;
case SEARCH_BCC:
break;
case SEARCH_SUBJECT:
break;
case SEARCH_IN_REPLY_TO:
break;
case SEARCH_MESSAGE_ID:
break;
default:
return -1;
}
t_push();
/* get field from hopefully cached envelope */
} else {
ret = -1;
}
if (ret != -1) {
case SEARCH_SENTBEFORE:
case SEARCH_SENTON:
case SEARCH_SENTSINCE:
default:
/* we're just testing existence of the field.
assume it matches with non-NIL values. */
break;
}
/* doesn't exist */
ret = 0;
break;
}
if (hdr_search_ctx == NULL) {
ret = 0;
break;
}
(const unsigned char *) field,
hdr_search_ctx) ? 1 : 0;
}
}
t_pop();
return ret;
}
{
case -1:
/* unknown */
break;
case 0:
break;
default:
break;
}
}
{
struct header_search_context *hdr_search_ctx;
int ret;
/* first check that the field name matches to argument. */
case SEARCH_SENTBEFORE:
case SEARCH_SENTON:
case SEARCH_SENTSINCE:
/* date is handled differently than others */
}
return;
case SEARCH_FROM:
return;
break;
case SEARCH_TO:
return;
break;
case SEARCH_CC:
return;
break;
case SEARCH_BCC:
return;
break;
case SEARCH_SUBJECT:
return;
break;
case SEARCH_HEADER:
return;
case SEARCH_TEXT:
/* TEXT goes through all headers */
break;
default:
return;
}
/* we're just testing existence of the field. always matches. */
ret = 1;
} else {
t_push();
/* then check if the value matches */
if (hdr_search_ctx == NULL)
ret = 0;
else {
hdr_search_ctx) ? 1 : 0;
}
t_pop();
}
}
void *context)
{
else if (name_len == 11 &&
else if (name_len == 10 &&
}
}
}
{
int ret, unknown_charset;
return;
if (ret < 0) {
}
}
}
struct search_index_context *ctx)
{
/* first check what we need to use */
have_headers = TRUE;
return TRUE;
if (have_headers || have_text) {
struct search_header_context hdr_ctx;
return FALSE;
search_header, &hdr_ctx);
} else {
return FALSE;
}
struct search_body_context body_ctx;
}
return TRUE;
}
{
unsigned int seq;
while (*set != '\0') {
if (*set == '*') {
set++;
} else {
seq = 0;
set++;
}
}
if (seq != 0) {
}
set++;
}
}
struct mail_search_arg *args,
{
/* go through everything */
*first_seq = 1;
return;
}
}
}
struct mail_search_arg *args,
unsigned int *first_uid,
unsigned int *last_uid)
{
struct mail_index_header *hdr;
unsigned int uid;
/* SEEN with 0 seen? */
return FALSE;
/* UNSEEN with all seen? */
return FALSE;
/* UNSEEN with lowwater limiting */
}
/* DELETED with 0 deleted? */
return FALSE;
/* UNDELETED with all deleted? */
return FALSE;
/* DELETED with lowwater limiting */
}
}
}
}
unsigned int seq)
{
struct mail_index_record *rec;
unsigned int expunges_before;
seq -= expunges_before;
}
struct mail_search_arg *args,
unsigned int *first_uid,
unsigned int *last_uid)
{
/* seq_update() should make sure that these can't happen */
if (first_seq > 1) {
if (uid == 0)
return FALSE;
}
if (uid == 0)
return FALSE;
}
if (*first_uid == 0)
*first_uid = 1;
if (*last_uid == 0)
/* UNSEEN and DELETED in root search level may limit the range */
return FALSE;
return TRUE;
}
struct mail_search_arg *args,
struct mail_sort_context *sort_ctx,
struct mail_thread_context *thread_ctx,
{
struct search_index_context ctx;
struct mail_index_record *rec;
struct mail_search_arg *arg;
const struct modify_log_expunge *expunges;
const char *str;
if (ibox->synced_messages_count == 0)
return TRUE;
/* see if we can limit the records we look at */
return TRUE;
&client_seq);
return TRUE;
expunges++;
}
t_push();
t_pop();
break;
}
if (!failed) {
break;
}
}
if (found) {
else if (thread_ctx != NULL) {
} else {
}
}
}
t_pop();
}
}
struct mail_search_arg *args,
enum mail_sort_type *sorting,
enum mail_thread_type threading,
{
struct mail_sort_context *sort_ctx;
struct mail_thread_context *thread_ctx;
struct index_sort_context index_sort_ctx;
int failed;
return FALSE;
thread_ctx = NULL;
} else if (threading != MAIL_THREAD_NONE) {
} else {
thread_ctx = NULL;
}
output, uid_result);
if (thread_ctx != NULL)
return FALSE;
return !failed;
}