mail-search.c revision 38537f71055adbbf214ba2a682f13d5947957298
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "array.h"
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index.h"
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen#include "mail-storage.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "mail-search.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool mail_search_arg_equals(const struct mail_search_arg *arg1,
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen const struct mail_search_arg *arg2);
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainenstatic void
3ed2d0f6b5e67e2663d44489d9da3176823789a8Timo Sirainenmailbox_uidset_change(struct mail_search_arg *arg, struct mailbox *box,
65f8fb656051f1059f7b5a2da9c5555adcc30439Timo Sirainen const ARRAY_TYPE(seq_range) *search_saved_uidset)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct seq_range *uids;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int i, count;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen uint32_t seq1, seq2;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (arg->value.str != NULL && strcmp(arg->value.str, "$") == 0) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* SEARCHRES: Replace with saved uidset */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen array_clear(&arg->value.seqset);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (search_saved_uidset == NULL ||
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen !array_is_created(search_saved_uidset))
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return;
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_append_array(&arg->value.seqset, search_saved_uidset);
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen arg->type = SEARCH_SEQSET;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* make a copy of the UIDs */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen count = array_count(&arg->value.seqset);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (count == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* empty set, keep it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen uids = t_new(struct seq_range, count);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen memcpy(uids, array_idx(&arg->value.seqset, 0), sizeof(*uids) * count);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen /* put them back to the range as sequences */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen array_clear(&arg->value.seqset);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen for (i = 0; i < count; i++) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mailbox_get_seq_range(box, uids[i].seq1, uids[i].seq2,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen &seq1, &seq2);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (seq1 != 0) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen seq_range_array_add_range(&arg->value.seqset,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen seq1, seq2);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen }
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen if (uids[i].seq2 == (uint32_t)-1) {
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen /* make sure the last message is in the range */
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen mailbox_get_seq_range(box, 1, (uint32_t)-1,
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen &seq1, &seq2);
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen seq_range_array_add(&arg->value.seqset, 0, seq2);
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen }
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen }
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen}
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainenstatic void
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenmail_search_args_init_sub(struct mail_search_args *args,
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen struct mail_search_arg *arg,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen bool change_uidsets,
57a8c6a95e4bce3eeaba36985adb81c07dd683ffTimo Sirainen const ARRAY_TYPE(seq_range) *search_saved_uidset)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct mail_search_args *thread_args;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen const char *keywords[2];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (; arg != NULL; arg = arg->next) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen switch (arg->type) {
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen case SEARCH_UIDSET:
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen if (change_uidsets) T_BEGIN {
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen mailbox_uidset_change(arg, args->box,
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen search_saved_uidset);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen } T_END;
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen break;
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen case SEARCH_MODSEQ:
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen if (arg->value.str == NULL)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen break;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen /* modseq with keyword */
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen case SEARCH_KEYWORDS:
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen keywords[0] = arg->value.str;
f1743785713e7632459d623d5df2108f4b93accbTimo Sirainen keywords[1] = NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen i_assert(arg->value.keywords == NULL);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen arg->value.keywords =
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen mailbox_keywords_create_valid(args->box,
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen keywords);
8d630c15a8ed6f85553467c3a231a273defca5f6Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen case SEARCH_INTHREAD:
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen thread_args = arg->value.search_args;
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen if (thread_args == NULL) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen arg->value.search_args = thread_args =
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen p_new(args->pool,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_search_args, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen thread_args->pool = args->pool;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen thread_args->args = arg->value.subargs;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen thread_args->charset = args->charset;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen thread_args->simplified = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* simplification should have unnested all
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen inthreads, so we'll assume that
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen have_inthreads=FALSE */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen thread_args->refcount++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen thread_args->box = args->box;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen /* fall through */
c29216637957d4b3126c6929ac5ba98138256ce1Timo Sirainen case SEARCH_SUB:
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen case SEARCH_OR:
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen mail_search_args_init_sub(args, arg->value.subargs,
e03d986a74128f5ba30fcfda9f6e36578f5d8decTimo Sirainen change_uidsets,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen search_saved_uidset);
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen break;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen default:
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen break;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen}
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainenvoid mail_search_args_init(struct mail_search_args *args,
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainen struct mailbox *box, bool change_uidsets,
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen const ARRAY_TYPE(seq_range) *search_saved_uidset)
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen{
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (args->init_refcount++ > 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(args->box == box);
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen return;
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen }
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen args->box = box;
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen if (!args->simplified)
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen mail_search_args_simplify(args);
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen mail_search_args_init_sub(args, args->args, change_uidsets,
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen search_saved_uidset);
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen}
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainenstatic void mail_search_args_deinit_sub(struct mail_search_args *args,
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen struct mail_search_arg *arg)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen{
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen for (; arg != NULL; arg = arg->next) {
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen switch (arg->type) {
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen case SEARCH_MODSEQ:
2584e86cc2d8c31ba30a4109cf4ba09d1e37e28aTimo Sirainen case SEARCH_KEYWORDS:
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen if (arg->value.keywords == NULL)
4b41116563110d00330896a568eff1078c382827Timo Sirainen break;
4b41116563110d00330896a568eff1078c382827Timo Sirainen mailbox_keywords_free(args->box, &arg->value.keywords);
4b41116563110d00330896a568eff1078c382827Timo Sirainen break;
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen case SEARCH_INTHREAD:
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen i_assert(arg->value.search_args->refcount > 0);
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen arg->value.search_args->refcount--;
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen arg->value.search_args->box = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (args->refcount == 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen arg->value.search_result != NULL) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mailbox_search_result_free(
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen &arg->value.search_result);
b2c1349cf07410aefab0f5b17153af9e5cfcf48fTimo Sirainen }
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen /* fall through */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case SEARCH_SUB:
dbe64f3893616a4005c8946be75d2dc8f6823d72Timo Sirainen case SEARCH_OR:
8a13b020f90e080570658b18c042e7e352c8b14fTimo Sirainen mail_search_args_deinit_sub(args, arg->value.subargs);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen default:
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen break;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_search_args_deinit(struct mail_search_args *args)
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (--args->init_refcount > 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen mail_search_args_deinit_sub(args, args->args);
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen args->box = NULL;
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenstatic void mail_search_args_seq2uid_sub(struct mail_search_args *args,
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen struct mail_search_arg *arg,
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen ARRAY_TYPE(seq_range) *uids)
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen{
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen for (; arg != NULL; arg = arg->next) {
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen switch (arg->type) {
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen case SEARCH_SEQSET:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_clear(uids);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen mailbox_get_uid_range(args->box,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &arg->value.seqset, uids);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* replace sequences with UIDs in the existing array.
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen this way it's possible to switch between uidsets and
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen seqsets constantly without leaking memory */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen arg->type = SEARCH_UIDSET;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen array_clear(&arg->value.seqset);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen array_append_array(&arg->value.seqset, uids);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen break;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen case SEARCH_SUB:
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen case SEARCH_OR:
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen case SEARCH_INTHREAD:
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen mail_search_args_seq2uid_sub(args, arg->value.subargs,
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen uids);
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen break;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen default:
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen break;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen}
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid mail_search_args_seq2uid(struct mail_search_args *args)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen T_BEGIN {
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen ARRAY_TYPE(seq_range) uids;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen t_array_init(&uids, 128);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mail_search_args_seq2uid_sub(args, args->args, &uids);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen } T_END;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen}
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainenvoid mail_search_args_ref(struct mail_search_args *args)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen{
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen i_assert(args->refcount > 0);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen args->refcount++;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen}
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainenvoid mail_search_args_unref(struct mail_search_args **_args)
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen struct mail_search_args *args = *_args;
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_assert(args->refcount > 0);
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen *_args = NULL;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (--args->refcount > 0) {
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen i_assert(args->init_refcount <= args->refcount);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen return;
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen }
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen i_assert(args->init_refcount <= 1);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen if (args->init_refcount == 1)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen mail_search_args_deinit(args);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen pool_unref(&args->pool);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenvoid mail_search_args_reset(struct mail_search_arg *args, bool full_reset)
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen{
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen while (args != NULL) {
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen if (args->type == SEARCH_OR || args->type == SEARCH_SUB)
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen mail_search_args_reset(args->value.subargs, full_reset);
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen if (!args->match_always)
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen args->result = -1;
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen else {
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen if (!full_reset)
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen args->result = 1;
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen else {
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen args->match_always = FALSE;
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen args->result = -1;
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen }
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen }
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen args = args->next;
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen }
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen}
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic void search_arg_foreach(struct mail_search_arg *arg,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen mail_search_foreach_callback_t *callback,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen void *context)
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct mail_search_arg *subarg;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (arg->result != -1)
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen return;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (arg->type == SEARCH_SUB) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* sublist of conditions */
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen i_assert(arg->value.subargs != NULL);
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen arg->result = 1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen subarg = arg->value.subargs;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen while (subarg != NULL) {
c0225f7f6b43d34dc58c17d3304f0fd60ab89894Timo Sirainen if (subarg->result == -1)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen search_arg_foreach(subarg, callback, context);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (subarg->result == -1)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen arg->result = -1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen else if (subarg->result == 0) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* didn't match */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen arg->result = 0;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen break;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen subarg = subarg->next;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (arg->not && arg->result != -1)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen arg->result = !arg->result;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen } else if (arg->type == SEARCH_OR) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* OR-list of conditions */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_assert(arg->value.subargs != NULL);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen subarg = arg->value.subargs;
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainen arg->result = 0;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen while (subarg != NULL) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (subarg->result == -1)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen search_arg_foreach(subarg, callback, context);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (subarg->result == -1)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen arg->result = -1;
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen else if (subarg->result > 0) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* matched */
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen arg->result = 1;
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen break;
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen subarg = subarg->next;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (arg->not && arg->result != -1)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen arg->result = !arg->result;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } else {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* just a single condition */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen callback(arg, context);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen#undef mail_search_args_foreach
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainenint mail_search_args_foreach(struct mail_search_arg *args,
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen mail_search_foreach_callback_t *callback,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen void *context)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen int result;
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen result = 1;
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen for (; args != NULL; args = args->next) {
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen search_arg_foreach(args, callback, context);
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen
e29f8a6a52ca72fc6010132fb86dd00e9d96432aTimo Sirainen if (args->result == 0) {
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen /* didn't match */
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen return 0;
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen }
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen if (args->result == -1)
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen result = -1;
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen }
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen return result;
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen}
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainenstatic void
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainensearch_arg_analyze(struct mail_search_arg *arg, buffer_t *headers,
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen bool *have_body, bool *have_text)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen static const char *date_hdr = "Date";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_search_arg *subarg;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e4c90f0b88e40a8f92b8f5e1f1a3ea701e5c965cTimo Sirainen if (arg->result != -1)
defb12ecd360df672ffb2f4dbf4d1218a0a9549cTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (arg->type) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen case SEARCH_OR:
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen case SEARCH_SUB:
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen subarg = arg->value.subargs;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen while (subarg != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (subarg->result == -1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen search_arg_analyze(subarg, headers,
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen have_body, have_text);
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen }
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen subarg = subarg->next;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen }
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen break;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen case SEARCH_SENTBEFORE:
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen case SEARCH_SENTON:
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen case SEARCH_SENTSINCE:
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen buffer_append(headers, &date_hdr, sizeof(const char *));
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen break;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen case SEARCH_HEADER:
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen case SEARCH_HEADER_ADDRESS:
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen case SEARCH_HEADER_COMPRESS_LWSP:
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen buffer_append(headers, &arg->hdr_field_name,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen sizeof(const char *));
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen break;
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen case SEARCH_BODY:
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen case SEARCH_BODY_FAST:
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen *have_body = TRUE;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen break;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen case SEARCH_TEXT:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case SEARCH_TEXT_FAST:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *have_text = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *have_body = TRUE;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen break;
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen default:
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen break;
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen }
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen}
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenconst char *const *
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenmail_search_args_analyze(struct mail_search_arg *args,
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen bool *have_headers, bool *have_body)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen{
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen const char *null = NULL;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen buffer_t *headers;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen bool have_text;
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen *have_headers = *have_body = have_text = FALSE;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen headers = buffer_create_dynamic(pool_datastack_create(), 128);
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen for (; args != NULL; args = args->next)
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen search_arg_analyze(args, headers, have_body, &have_text);
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *have_headers = have_text || headers->used != 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen if (headers->used == 0 || have_text)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return NULL;
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen buffer_append(headers, &null, sizeof(const char *));
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen return buffer_get_data(headers, NULL);
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen}
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenstatic struct mail_keywords *
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainenmail_search_keywords_merge(struct mail_keywords **_kw1,
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen struct mail_keywords **_kw2)
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen{
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen struct mail_keywords *kw1 = *_kw1, *kw2 = *_kw2;
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen struct mail_keywords *new_kw;
e050e5c9b1688765f1fdfce9b7141f7b614383fdTimo Sirainen
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen i_assert(kw1->index == kw2->index);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen T_BEGIN {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ARRAY_TYPE(keyword_indexes) new_indexes;
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen unsigned int i, j;
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen t_array_init(&new_indexes, kw1->count + kw2->count + 1);
b62140c5849297a800fee942026d9c3cb8c60206Timo Sirainen array_append(&new_indexes, kw1->idx, kw1->count);
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen for (i = 0; i < kw2->count; i++) {
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen /* don't add duplicates */
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen for (j = 0; j < kw1->count; j++) {
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen if (kw1->idx[j] == kw2->idx[i])
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen break;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen if (j == kw1->count)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen array_append(&new_indexes, kw2->idx+i, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen new_kw = mail_index_keywords_create_from_indexes(kw1->index,
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen &new_indexes);
de58be41126e5d68008d2ea706d62ccdc1f29337Timo Sirainen } T_END;
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen mail_index_keywords_free(_kw1);
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen mail_index_keywords_free(_kw2);
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen return new_kw;
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenmail_search_args_simplify_sub(struct mail_search_arg *args, bool parent_and)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct mail_search_arg *sub, *prev = NULL;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen struct mail_search_arg *prev_flags_arg, *prev_not_flags_arg;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen struct mail_search_arg *prev_kw_arg, *prev_not_kw_arg;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen prev_flags_arg = prev_not_flags_arg = NULL;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen prev_kw_arg = prev_not_kw_arg = NULL;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen while (args != NULL) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (args->not && (args->type == SEARCH_SUB ||
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen args->type == SEARCH_OR)) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* neg(p and q and ..) == neg(p) or neg(q) or ..
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen neg(p or q or ..) == neg(p) and neg(q) and .. */
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen args->type = args->type == SEARCH_SUB ?
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen SEARCH_OR : SEARCH_SUB;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen args->not = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sub = args->value.subargs;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (; sub != NULL; sub = sub->next)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sub->not = !sub->not;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen if ((args->type == SEARCH_SUB && parent_and) ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (args->type == SEARCH_OR && !parent_and) ||
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen ((args->type == SEARCH_SUB || args->type == SEARCH_OR) &&
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen args->value.subargs->next == NULL)) {
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen /* p and (q and ..) == p and q and ..
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen p or (q or ..) == p or q or ..
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen (p) = p */
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen sub = args->value.subargs;
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen for (; sub->next != NULL; sub = sub->next) ;
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen sub->next = args->next;
b83deefd2cf1e293373673eefb4d5cf60907978cTimo Sirainen *args = *args->value.subargs;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen continue;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen }
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (args->type == SEARCH_SUB ||
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen args->type == SEARCH_OR ||
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen args->type == SEARCH_INTHREAD) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen mail_search_args_simplify_sub(args->value.subargs,
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen args->type != SEARCH_OR);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen }
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen /* merge all flags arguments */
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen if (args->type == SEARCH_FLAGS && !args->not && parent_and) {
b3b4f3875850099c9292ad74d08bb385c3988f8fTimo Sirainen if (prev_flags_arg == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen prev_flags_arg = args;
else {
prev_flags_arg->value.flags |=
args->value.flags;
prev->next = args->next;
args = args->next;
continue;
}
} else if (args->type == SEARCH_FLAGS && args->not &&
!parent_and) {
if (prev_not_flags_arg == NULL)
prev_not_flags_arg = args;
else {
prev_not_flags_arg->value.flags |=
args->value.flags;
prev->next = args->next;
args = args->next;
continue;
}
}
/* merge all keywords arguments */
if (args->type == SEARCH_KEYWORDS && !args->not && parent_and) {
if (prev_kw_arg == NULL)
prev_kw_arg = args;
else {
prev_kw_arg->value.keywords =
mail_search_keywords_merge(
&prev_kw_arg->value.keywords,
&args->value.keywords);
prev->next = args->next;
args = args->next;
continue;
}
} else if (args->type == SEARCH_KEYWORDS && args->not &&
!parent_and) {
if (prev_not_kw_arg == NULL)
prev_not_kw_arg = args;
else {
prev_not_kw_arg->value.keywords =
mail_search_keywords_merge(
&prev_not_kw_arg->value.keywords,
&args->value.keywords);
prev->next = args->next;
args = args->next;
continue;
}
}
prev = args;
args = args->next;
}
}
static bool
mail_search_args_unnest_inthreads(struct mail_search_args *args,
struct mail_search_arg **argp,
bool parent_inthreads, bool parent_and)
{
struct mail_search_arg *arg, *thread_arg, *or_arg;
bool child_inthreads = FALSE, non_inthreads = FALSE;
for (arg = *argp; arg != NULL; arg = arg->next) {
switch (arg->type) {
case SEARCH_SUB:
case SEARCH_OR:
if (!mail_search_args_unnest_inthreads(args,
&arg->value.subargs, parent_inthreads,
arg->type != SEARCH_OR)) {
arg->result = 1;
child_inthreads = TRUE;
} else {
arg->result = 0;
non_inthreads = TRUE;
}
break;
case SEARCH_INTHREAD:
if (mail_search_args_unnest_inthreads(args,
&arg->value.subargs, TRUE, TRUE)) {
/* children converted to SEARCH_INTHREADs */
arg->type = SEARCH_SUB;
}
args->have_inthreads = TRUE;
arg->result = 1;
child_inthreads = TRUE;
break;
default:
arg->result = 0;
non_inthreads = TRUE;
break;
}
}
if (!parent_inthreads || !child_inthreads || !non_inthreads)
return FALSE;
/* put all non-INTHREADs under a single INTHREAD */
thread_arg = p_new(args->pool, struct mail_search_arg, 1);
thread_arg->type = SEARCH_INTHREAD;
while (*argp != NULL) {
arg = *argp;
argp = &(*argp)->next;
if (arg->result == 0) {
/* not an INTHREAD or a SUB/OR with only INTHREADs */
arg->next = thread_arg->value.subargs;
thread_arg->value.subargs = arg;
}
}
if (!parent_and) {
/* We want to OR the args */
or_arg = p_new(args->pool, struct mail_search_arg, 1);
or_arg->type = SEARCH_OR;
or_arg->value.subargs = thread_arg->value.subargs;
thread_arg->value.subargs = or_arg;
}
return TRUE;
}
void mail_search_args_simplify(struct mail_search_args *args)
{
args->simplified = TRUE;
mail_search_args_simplify_sub(args->args, TRUE);
if (mail_search_args_unnest_inthreads(args, &args->args,
FALSE, TRUE)) {
/* we may have added some extra SUBs that could be dropped */
mail_search_args_simplify_sub(args->args, TRUE);
}
}
static bool mail_search_arg_one_equals(const struct mail_search_arg *arg1,
const struct mail_search_arg *arg2)
{
if (arg1->type != arg2->type ||
arg1->not != arg2->not)
return FALSE;
switch (arg1->type) {
case SEARCH_OR:
case SEARCH_SUB:
return mail_search_arg_equals(arg1->value.subargs,
arg2->value.subargs);
case SEARCH_ALL:
return TRUE;
case SEARCH_SEQSET:
/* sequences may point to different messages at different times,
never assume they match */
return FALSE;
case SEARCH_UIDSET:
return array_cmp(&arg1->value.seqset, &arg2->value.seqset);
case SEARCH_FLAGS:
return arg1->value.flags == arg2->value.flags;
case SEARCH_KEYWORDS:
return strcasecmp(arg1->value.str, arg2->value.str);
case SEARCH_BEFORE:
case SEARCH_ON:
case SEARCH_SINCE:
case SEARCH_SENTBEFORE:
case SEARCH_SENTON:
case SEARCH_SENTSINCE:
return arg1->value.time == arg2->value.time;
case SEARCH_SMALLER:
case SEARCH_LARGER:
return arg1->value.size == arg2->value.size;
case SEARCH_HEADER:
case SEARCH_HEADER_ADDRESS:
case SEARCH_HEADER_COMPRESS_LWSP:
if (strcasecmp(arg1->hdr_field_name, arg2->hdr_field_name) != 0)
return FALSE;
/* fall through */
case SEARCH_BODY:
case SEARCH_TEXT:
case SEARCH_BODY_FAST:
case SEARCH_TEXT_FAST:
case SEARCH_GUID:
case SEARCH_MAILBOX:
/* don't bother doing case-insensitive comparison. it must not
be done for guid/mailbox, and for others we should support
full i18n case-insensitivity (or the active comparator
in future). */
return strcmp(arg1->value.str, arg2->value.str);
case SEARCH_MODSEQ: {
const struct mail_search_modseq *m1 = arg1->value.modseq;
const struct mail_search_modseq *m2 = arg2->value.modseq;
return m1->modseq == m2->modseq &&
m1->type == m2->type;
}
case SEARCH_INTHREAD:
return mail_search_args_equal(arg1->value.search_args,
arg2->value.search_args);
}
i_unreached();
return FALSE;
}
static bool mail_search_arg_equals(const struct mail_search_arg *arg1,
const struct mail_search_arg *arg2)
{
while (arg1 != NULL && arg2 != NULL) {
if (!mail_search_arg_one_equals(arg1, arg2))
return FALSE;
arg1 = arg1->next;
arg2 = arg2->next;
}
return arg1 == NULL && arg2 == NULL;
}
bool mail_search_args_equal(const struct mail_search_args *args1,
const struct mail_search_args *args2)
{
i_assert(args1->simplified == args2->simplified);
i_assert(args1->box == args2->box);
if (null_strcmp(args1->charset, args2->charset) != 0)
return FALSE;
return mail_search_arg_equals(args1->args, args2->args);
}