summaryrefslogtreecommitdiffstats
path: root/src/lib-storage/mail-search.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:36:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:36:47 +0000
commit0441d265f2bb9da249c7abf333f0f771fadb4ab5 (patch)
tree3f3789daa2f6db22da6e55e92bee0062a7d613fe /src/lib-storage/mail-search.h
parentInitial commit. (diff)
downloaddovecot-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.h278
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