diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 17:36:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 17:36:47 +0000 |
commit | 0441d265f2bb9da249c7abf333f0f771fadb4ab5 (patch) | |
tree | 3f3789daa2f6db22da6e55e92bee0062a7d613fe /src/lib-storage/mail-search.h | |
parent | Initial commit. (diff) | |
download | dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.tar.xz dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.zip |
Adding upstream version 1:2.3.21+dfsg1.upstream/1%2.3.21+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib-storage/mail-search.h')
-rw-r--r-- | src/lib-storage/mail-search.h | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/src/lib-storage/mail-search.h b/src/lib-storage/mail-search.h new file mode 100644 index 0000000..46bcbcb --- /dev/null +++ b/src/lib-storage/mail-search.h @@ -0,0 +1,278 @@ +#ifndef MAIL_SEARCH_H +#define MAIL_SEARCH_H + +#include "seq-range-array.h" +#include "mail-types.h" +#include "mail-thread.h" + +struct mail_search_mime_part; + +enum mail_search_arg_type { + SEARCH_OR, + SEARCH_SUB, + + /* sequence sets */ + SEARCH_ALL, + SEARCH_SEQSET, + SEARCH_UIDSET, + + /* flags */ + SEARCH_FLAGS, + SEARCH_KEYWORDS, + + /* dates (date_type required) */ + SEARCH_BEFORE, + SEARCH_ON, /* time must point to beginning of the day */ + SEARCH_SINCE, + + /* sizes */ + SEARCH_SMALLER, + SEARCH_LARGER, + + /* headers */ + SEARCH_HEADER, + SEARCH_HEADER_ADDRESS, + SEARCH_HEADER_COMPRESS_LWSP, + + /* body */ + SEARCH_BODY, + SEARCH_TEXT, + + /* extensions */ + SEARCH_MODSEQ, + SEARCH_SAVEDATESUPPORTED, + SEARCH_INTHREAD, + SEARCH_GUID, + SEARCH_MAILBOX, + SEARCH_MAILBOX_GUID, + SEARCH_MAILBOX_GLOB, + SEARCH_REAL_UID, + SEARCH_MIMEPART, + + /* This term is allowed only in SEARCH_OR and SEARCH_SUB sublists. + When it is encountered during the simplification, it must be removed */ + SEARCH_NIL, +}; + +enum mail_search_date_type { + MAIL_SEARCH_DATE_TYPE_SENT = 1, + MAIL_SEARCH_DATE_TYPE_RECEIVED, + MAIL_SEARCH_DATE_TYPE_SAVED +}; + +enum mail_search_arg_flag { + /* Used by *BEFORE/SINCE/ON searches. + + When NOT set: Adjust search timestamps so that the email's timezone + is included in the comparisons. For example + "04-Nov-2016 00:00:00 +0200" would match 4th day. This allows + searching for mails with dates from the email sender's point of + view. For received/saved dates there is no known timezone, and + without this flag the dates are compared using the server's local + timezone. + + When set: Compare the timestamp as UTC. For example + "04-Nov-2016 00:00:00 +0200" would be treated as + "03-Nov-2016 22:00:00 UTC" and would match 3rd day. This allows + searching for mails within precise time interval. Since imap-dates + don't allow specifying timezone this isn't really possible with IMAP + protocol, except using OLDER/YOUNGER searches. */ + MAIL_SEARCH_ARG_FLAG_UTC_TIMES = 0x01, +}; + +enum mail_search_modseq_type { + MAIL_SEARCH_MODSEQ_TYPE_ANY = 0, + MAIL_SEARCH_MODSEQ_TYPE_PRIVATE, + MAIL_SEARCH_MODSEQ_TYPE_SHARED +}; + +struct mail_search_modseq { + uint64_t modseq; + enum mail_search_modseq_type type; +}; + +struct mail_search_arg { + /* NOTE: when adding new fields, make sure mail_search_arg_dup_one() + and mail_search_arg_one_equals() are updated. */ + struct mail_search_arg *next; + + enum mail_search_arg_type type; + struct { + struct mail_search_arg *subargs; + ARRAY_TYPE(seq_range) seqset; + const char *str; + time_t time; + uoff_t size; + enum mail_flags flags; + enum mail_search_arg_flag search_flags; + enum mail_search_date_type date_type; + enum mail_thread_type thread_type; + struct mail_search_modseq *modseq; + struct mail_search_result *search_result; + struct mail_search_mime_part *mime_part; + } value; + /* set by mail_search_args_init(): */ + struct { + struct mail_search_args *search_args; + /* Note that initialized keywords may be empty if the keyword + wasn't valid in this mailbox. */ + struct mail_keywords *keywords; + struct imap_match_glob *mailbox_glob; + } initialized; + + void *context; + const char *hdr_field_name; /* for SEARCH_HEADER* */ + bool match_not:1; /* result = !result */ + bool match_always:1; /* result = 1 always */ + bool nonmatch_always:1; /* result = 0 always */ + bool fuzzy:1; /* use fuzzy matching for this arg */ + bool no_fts:1; /* do NOT call FTS */ + + int result; /* -1 = unknown, 0 = unmatched, 1 = matched */ +}; + +struct mail_search_args { + /* There are two types of refcount: + + 1) The normal refcount tracks the lifetime of the struct itself. + This allows using the same args for multiple search queries, even + across different mailboxes. + + 2) The init_refcount tracks how many times mail_search_args_init() has + been called. This can happen when the same mail_search_args have been + shared by referencing them in different parts of the code. Only after + each one of them has called mail_search_args_deinit() the init_refcount + drops to 0 and it can really be deinitialized. + + Note that all of the inits must be within the same mailbox - attempting + to init the same args in different mailboxes at the same time will + result in assert-crash. */ + int refcount, init_refcount; + + pool_t pool; + struct mailbox *box; + struct mail_search_arg *args; + + bool simplified:1; + bool have_inthreads:1; + /* Stop mail_search_next() when finding a non-matching mail. + (Could be useful when wanting to find only the oldest mails.) */ + bool stop_on_nonmatch:1; + /* fts plugin has already expanded the search args - no need to do + it again. */ + bool fts_expanded:1; +}; + +#define ARG_SET_RESULT(arg, res) \ + STMT_START { \ + (arg)->result = !(arg)->match_not ? (res) : \ + ((res) == -1 ? -1 : ((res) == 0 ? 1 : 0)); \ + } STMT_END + +typedef void mail_search_foreach_callback_t(struct mail_search_arg *arg, + void *context); + +/* Fully initialize and optimize the args for searching within the specified + mailbox. This should always be called before the args are actually used + for searching. After search is finished, the args must be deinitialized. + It's possible to initialize the same args multiple times, as long as it's + done within the same mailbox. This would allow multiple concurrent searches + to be done within the shared search args. + + This will implicitly call mail_search_args_simplify() if it wasn't called + yet. It also allocates any necessary per-mailbox data like keywords. + + If change_sets is TRUE, change uidsets to seqsets and convert "*" in seqsets + to the current highest message sequence. */ +void mail_search_args_init(struct mail_search_args *args, + struct mailbox *box, bool change_sets, + const ARRAY_TYPE(seq_range) *search_saved_uidset) + ATTR_NULL(4); +/* Initialize arg and its children. args is used for getting mailbox and + pool. */ +void mail_search_arg_init(struct mail_search_args *args, + struct mail_search_arg *arg); +/* Free memory allocated by mail_search_args_init(). The args can initialized + afterwards again if needed. The args can be reused for other queries after + calling this. */ +void mail_search_args_deinit(struct mail_search_args *args); +/* Free arg and its siblings and children. */ +void mail_search_arg_deinit(struct mail_search_arg *arg); +/* Free arg and its children, but not its siblings. */ +void mail_search_arg_one_deinit(struct mail_search_arg *arg); +/* Convert sequence sets in args to UIDs. */ +void mail_search_args_seq2uid(struct mail_search_args *args); +/* Returns TRUE if the two search arguments are fully compatible. + Always returns FALSE if there are seqsets, since they may point to different + messages depending on when the search is run. */ +bool mail_search_args_equal(const struct mail_search_args *args1, + const struct mail_search_args *args2); +/* Same as mail_search_args_equal(), but for individual mail_search_arg + structs. All the siblings of arg1 and arg2 are also compared. */ +bool mail_search_arg_equals(const struct mail_search_arg *arg1, + const struct mail_search_arg *arg2); +int mail_search_arg_equals_p(const struct mail_search_arg *const *arg1, + const struct mail_search_arg *const *arg2); +/* Same as mail_search_arg_equals(), but don't compare siblings. */ +bool mail_search_arg_one_equals(const struct mail_search_arg *arg1, + const struct mail_search_arg *arg2); + +void mail_search_args_ref(struct mail_search_args *args); +void mail_search_args_unref(struct mail_search_args **args); + +struct mail_search_args * +mail_search_args_dup(const struct mail_search_args *args); +struct mail_search_arg * +mail_search_arg_dup(pool_t pool, const struct mail_search_arg *arg); + +/* Reset the results in search arguments. match_always is reset only if + full_reset is TRUE. */ +void mail_search_args_reset(struct mail_search_arg *args, bool full_reset); + +/* goes through arguments in list that don't have a result yet. + Returns 1 = search matched, 0 = search unmatched, -1 = don't know yet */ +int mail_search_args_foreach(struct mail_search_arg *args, + mail_search_foreach_callback_t *callback, + void *context) ATTR_NULL(3); +#define mail_search_args_foreach(args, callback, context) \ + mail_search_args_foreach(args - \ + CALLBACK_TYPECHECK(callback, void (*)( \ + struct mail_search_arg *, typeof(context))), \ + (mail_search_foreach_callback_t *)callback, context) + +/* Fills have_headers and have_body based on if such search argument exists + that needs to be checked. Returns the headers that we're searching for, or + NULL if we're searching for TEXT. */ +const char *const * +mail_search_args_analyze(struct mail_search_arg *args, + bool *have_headers, bool *have_body); + +/* Returns FALSE if search query contains MAILBOX[_GLOB] args such that the + query can never match any messages in the given mailbox. */ +bool mail_search_args_match_mailbox(struct mail_search_args *args, + const char *vname, char sep); + +/* Simplify/optimize search arguments. Afterwards all OR/SUB args are + guaranteed to have match_not=FALSE. */ +void mail_search_args_simplify(struct mail_search_args *args); + +/* Append all args as IMAP SEARCH AND-query to the dest string and returns TRUE. + If some search arg can't be written as IMAP SEARCH parameter, error_r is set + and FALSE is returned. */ +bool mail_search_args_to_imap(string_t *dest, const struct mail_search_arg *args, + const char **error_r); +/* Like mail_search_args_to_imap(), but append only a single arg. */ +bool mail_search_arg_to_imap(string_t *dest, const struct mail_search_arg *arg, + const char **error_r); +/* Write all args to dest string as cmdline/human compatible input. */ +void mail_search_args_to_cmdline(string_t *dest, + const struct mail_search_arg *args); + +/* Serialization for search args' results. */ +void mail_search_args_result_serialize(const struct mail_search_args *args, + buffer_t *dest); +void mail_search_args_result_deserialize(struct mail_search_args *args, + const unsigned char *data, + size_t size); + +#endif |