mail-search.c revision 91dff5e44902c234524ef19e1d1b72a4d0513f56
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (C) 2002 Timo Sirainen */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen#include "mail-search.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainentypedef struct {
7a7d2aa11e46195e2d92d6c337d7e78052a5ce67Timo Sirainen Pool pool;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *error;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen} SearchBuildData;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic MailSearchArg *search_arg_new(Pool pool, MailSearchArgType type)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MailSearchArg *arg;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen arg = p_new(pool, MailSearchArg, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen arg->type = type;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return arg;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define ARG_NEW(type, value) \
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen arg_new(data, args, next_sarg, type, value)
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int arg_new(SearchBuildData *data, ImapArg **args,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MailSearchArg **next_sarg, MailSearchArgType type, int value)
afa201e7e1d2447e8dfa1aff43de0fdad564105fTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MailSearchArg *sarg;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *next_sarg = sarg = search_arg_new(data->pool, type);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (value == 0)
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* first arg */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((*args)->type == IMAP_ARG_EOL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen data->error = "Missing parameter for argument";
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sarg->value.str = str_ucase((*args)->data.str);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *args += 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen /* second arg */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (value == 2) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if ((*args)->type == IMAP_ARG_EOL) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen data->error = "Missing parameter for argument";
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return FALSE;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sarg->hdr_field_name = sarg->value.str;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen sarg->value.str = str_ucase((*args)->data.str);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen *args += 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return TRUE;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstatic int search_arg_build(SearchBuildData *data, ImapArg **args,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MailSearchArg **next_sarg)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MailSearchArg **subargs;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen ImapArg *arg;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen char *str;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((*args)->type == IMAP_ARG_EOL) {
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen data->error = "Missing argument";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen arg = *args;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (arg->type == IMAP_ARG_NIL) {
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen /* NIL not allowed */
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen data->error = "NIL not allowed";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen if (arg->type == IMAP_ARG_LIST) {
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen ImapArg *listargs = arg->data.list->args;
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen *next_sarg = search_arg_new(data->pool, SEARCH_SUB);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen subargs = &(*next_sarg)->value.subargs;
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen while (listargs->type != IMAP_ARG_EOL) {
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen if (!search_arg_build(data, &listargs, subargs))
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen return FALSE;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen subargs = &(*subargs)->next;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen }
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *args += 1;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen return TRUE;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(arg->type == IMAP_ARG_ATOM ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen arg->type == IMAP_ARG_STRING);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* string argument - get the name and jump to next */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str = arg->data.str;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *args += 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_ucase(str);
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen switch (*str) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case 'A':
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(str, "ANSWERED") == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_ANSWERED, 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (strcmp(str, "ALL") == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_ALL, 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case 'B':
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(str, "BODY") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* <string> */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_BODY, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (strcmp(str, "BEFORE") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* <date> */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_BEFORE, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (strcmp(str, "BCC") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* <string> */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_BCC, 1);
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen }
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen break;
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen case 'C':
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(str, "CC") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* <string> */
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen return ARG_NEW(SEARCH_CC, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case 'D':
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen if (strcmp(str, "DELETED") == 0)
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen return ARG_NEW(SEARCH_DELETED, 0);
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen else if (strcmp(str, "DRAFT") == 0)
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen return ARG_NEW(SEARCH_DRAFT, 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen case 'F':
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(str, "FLAGGED") == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_FLAGGED, 0);
547e916f4e6f01af682f8b6e032c337f2a699364Timo Sirainen else if (strcmp(str, "FROM") == 0) {
547e916f4e6f01af682f8b6e032c337f2a699364Timo Sirainen /* <string> */
547e916f4e6f01af682f8b6e032c337f2a699364Timo Sirainen return ARG_NEW(SEARCH_FROM, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case 'H':
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(str, "HEADER") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* <field-name> <string> */
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen const char *key;
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen if ((*args)->type == IMAP_ARG_EOL) {
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen data->error = "Missing parameter for HEADER";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen key = str_ucase((*args)->data.str);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(key, "FROM") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *args += 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_FROM, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (strcmp(key, "TO") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *args += 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_TO, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (strcmp(key, "CC") == 0) {
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen *args += 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_CC, 1);
fa7c76955c6bc62689fbdf39318194f85905e6e2Timo Sirainen } else if (strcmp(key, "BCC") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *args += 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_BCC, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (strcmp(key, "SUBJECT") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *args += 1;
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen return ARG_NEW(SEARCH_SUBJECT, 1);
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen } else if (strcmp(key, "IN-REPLY-TO") == 0) {
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen *args += 1;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen return ARG_NEW(SEARCH_IN_REPLY_TO, 1);
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen } else if (strcmp(key, "MESSAGE-ID") == 0) {
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen *args += 1;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen return ARG_NEW(SEARCH_MESSAGE_ID, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ARG_NEW(SEARCH_HEADER, 2);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen case 'K':
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (strcmp(str, "KEYWORD") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <flag> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ARG_NEW(SEARCH_KEYWORD, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen case 'L':
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (strcmp(str, "LARGER") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <n> */
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen return ARG_NEW(SEARCH_LARGER, 1);
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen }
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen break;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen case 'N':
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen if (strcmp(str, "NOT") == 0) {
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen if (!search_arg_build(data, args, next_sarg))
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen return FALSE;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen (*next_sarg)->not = !(*next_sarg)->not;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen return TRUE;
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen } else if (strcmp(str, "NEW") == 0) {
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen /* NEW == (RECENT UNSEEN) */
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen *next_sarg = search_arg_new(data->pool, SEARCH_SUB);
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen subargs = &(*next_sarg)->value.subargs;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen *subargs = search_arg_new(data->pool, SEARCH_RECENT);
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen (*subargs)->next = search_arg_new(data->pool,
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen SEARCH_SEEN);
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen (*subargs)->next->not = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen case 'O':
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (strcmp(str, "OR") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <search-key1> <search-key2> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen *next_sarg = search_arg_new(data->pool, SEARCH_OR);
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen subargs = &(*next_sarg)->value.subargs;
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen for (;;) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (!search_arg_build(data, args, subargs))
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen return FALSE;
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen subargs = &(*subargs)->next;
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen /* <key> OR <key> OR ... <key> - put them all
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen under one SEARCH_OR list. */
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen if ((*args)->type == IMAP_ARG_EOL)
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen break;
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen if ((*args)->type != IMAP_ARG_ATOM ||
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen strcasecmp((*args)->data.str, "OR") != 0)
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen break;
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen *args += 1;
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen }
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen if (!search_arg_build(data, args, subargs))
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen return FALSE;
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen return TRUE;
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen } if (strcmp(str, "ON") == 0) {
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen /* <date> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ARG_NEW(SEARCH_ON, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } if (strcmp(str, "OLD") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* OLD == NOT RECENT */
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen if (!ARG_NEW(SEARCH_RECENT, 0))
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return FALSE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (*next_sarg)->not = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen case 'R':
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (strcmp(str, "RECENT") == 0)
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen return ARG_NEW(SEARCH_RECENT, 0);
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen break;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen case 'S':
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen if (strcmp(str, "SEEN") == 0)
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen return ARG_NEW(SEARCH_SEEN, 0);
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen else if (strcmp(str, "SUBJECT") == 0) {
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen /* <string> */
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen return ARG_NEW(SEARCH_SUBJECT, 1);
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen } else if (strcmp(str, "SENTBEFORE") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <date> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ARG_NEW(SEARCH_SENTBEFORE, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else if (strcmp(str, "SENTON") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <date> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ARG_NEW(SEARCH_SENTON, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else if (strcmp(str, "SENTSINCE") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <date> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ARG_NEW(SEARCH_SENTSINCE, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else if (strcmp(str, "SINCE") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <date> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ARG_NEW(SEARCH_SINCE, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else if (strcmp(str, "SMALLER") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <n> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ARG_NEW(SEARCH_SMALLER, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen case 'T':
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (strcmp(str, "TEXT") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <string> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ARG_NEW(SEARCH_TEXT, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else if (strcmp(str, "TO") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <string> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ARG_NEW(SEARCH_TO, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen case 'U':
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (strcmp(str, "UID") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <message set> */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ARG_NEW(SEARCH_UID, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else if (strcmp(str, "UNANSWERED") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (!ARG_NEW(SEARCH_ANSWERED, 0))
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return FALSE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (*next_sarg)->not = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else if (strcmp(str, "UNDELETED") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (!ARG_NEW(SEARCH_DELETED, 0))
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return FALSE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (*next_sarg)->not = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else if (strcmp(str, "UNDRAFT") == 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (!ARG_NEW(SEARCH_DRAFT, 0))
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return FALSE;
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen (*next_sarg)->not = TRUE;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen return TRUE;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen } else if (strcmp(str, "UNFLAGGED") == 0) {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (!ARG_NEW(SEARCH_FLAGGED, 0))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (*next_sarg)->not = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen } else if (strcmp(str, "UNKEYWORD") == 0) {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (!ARG_NEW(SEARCH_KEYWORD, 0))
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen return FALSE;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen (*next_sarg)->not = TRUE;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (strcmp(str, "UNSEEN") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!ARG_NEW(SEARCH_SEEN, 0))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (*next_sarg)->not = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
84e49ad7d7a840d600a961daeca60802e3d69cd0Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen default:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*str == '*' || (*str >= '0' && *str <= '9')) {
5539418f448cd9bb38fc085e654861479dd1130bTimo Sirainen /* <message-set> */
5539418f448cd9bb38fc085e654861479dd1130bTimo Sirainen if (!ARG_NEW(SEARCH_SET, 0))
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (*next_sarg)->value.str = str;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen return TRUE;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen data->error = t_strconcat("Unknown argument ", str, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
dca6d617a23e3f93af3b8df59acb46478179fe55Timo SirainenMailSearchArg *mail_search_args_build(Pool pool, ImapArg *args,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char **error)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen SearchBuildData data;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MailSearchArg *first_sarg, **sargs;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen data.pool = pool;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen data.error = NULL;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen /* get the first arg */
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen first_sarg = NULL; sargs = &first_sarg;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen while (args->type != IMAP_ARG_EOL) {
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen if (!search_arg_build(&data, &args, sargs)) {
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen *error = data.error;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen return NULL;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen sargs = &(*sargs)->next;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen }
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen *error = NULL;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen return first_sarg;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen}
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainenvoid mail_search_args_reset(MailSearchArg *args)
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen while (args != NULL) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (args->type == SEARCH_OR || args->type == SEARCH_SUB)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_search_args_reset(args->value.subargs);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen args->result = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
306cfd77100131c08b243de10f6d40500f4c27c6Timo Sirainen args = args->next;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen}
438f12d7a776da695019114884b48188d94613efTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void search_arg_foreach(MailSearchArg *arg, MailSearchForeachFunc func,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen void *context)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen MailSearchArg *subarg;
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (arg->result != 0)
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen return;
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (arg->type == SEARCH_SUB) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* sublist of conditions */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(arg->value.subargs != NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen arg->result = 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen subarg = arg->value.subargs;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen while (subarg != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (subarg->result == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen search_arg_foreach(subarg, func, context);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (subarg->result == -1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* failed */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen arg->result = -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (subarg->result == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen arg->result = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen subarg = subarg->next;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (arg->type == SEARCH_OR) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* OR-list of conditions */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(arg->value.subargs != NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen subarg = arg->value.subargs;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen arg->result = -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen while (subarg != NULL) {
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen if (subarg->result == 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen search_arg_foreach(subarg, func, context);
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen if (subarg->result == 1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* matched */
arg->result = 1;
break;
}
if (subarg->result == 0)
arg->result = 0;
subarg = subarg->next;
}
} else {
/* just a single condition */
func(arg, context);
}
}
int mail_search_args_foreach(MailSearchArg *args, MailSearchForeachFunc func,
void *context)
{
int result;
result = 1;
for (; args != NULL; args = args->next) {
search_arg_foreach(args, func, context);
if (args->result == -1) {
/* failed, abort */
return -1;
}
if (args->result == 0)
result = 0;
}
return result;
}
static void search_arg_analyze(MailSearchArg *arg, int *have_headers,
int *have_body, int *have_text)
{
MailSearchArg *subarg;
if (arg->result != 0)
return;
switch (arg->type) {
case SEARCH_OR:
case SEARCH_SUB:
subarg = arg->value.subargs;
while (subarg != NULL) {
if (subarg->result == 0) {
search_arg_analyze(subarg, have_headers,
have_body, have_text);
}
subarg = subarg->next;
}
break;
case SEARCH_SENTBEFORE:
case SEARCH_SENTON:
case SEARCH_SENTSINCE:
case SEARCH_FROM:
case SEARCH_TO:
case SEARCH_CC:
case SEARCH_BCC:
case SEARCH_SUBJECT:
case SEARCH_IN_REPLY_TO:
case SEARCH_MESSAGE_ID:
case SEARCH_HEADER:
*have_headers = TRUE;
break;
case SEARCH_BODY:
*have_body = TRUE;
break;
case SEARCH_TEXT:
*have_text = TRUE;
break;
default:
break;
}
}
void mail_search_args_analyze(MailSearchArg *args, int *have_headers,
int *have_body, int *have_text)
{
*have_headers = *have_body = *have_text = FALSE;
for (; args != NULL; args = args->next)
search_arg_analyze(args, have_headers, have_body, have_text);
}