1 #ifndef MAIL_SEARCH_H 2 #define MAIL_SEARCH_H 3 4 #include "seq-range-array.h" 5 #include "mail-types.h" 6 #include "mail-thread.h" 7 8 struct mail_search_mime_part; 9 10 enum mail_search_arg_type { 11 SEARCH_OR, 12 SEARCH_SUB, 13 14 /* sequence sets */ 15 SEARCH_ALL, 16 SEARCH_SEQSET, 17 SEARCH_UIDSET, 18 19 /* flags */ 20 SEARCH_FLAGS, 21 SEARCH_KEYWORDS, 22 23 /* dates (date_type required) */ 24 SEARCH_BEFORE, 25 SEARCH_ON, /* time must point to beginning of the day */ 26 SEARCH_SINCE, 27 28 /* sizes */ 29 SEARCH_SMALLER, 30 SEARCH_LARGER, 31 32 /* headers */ 33 SEARCH_HEADER, 34 SEARCH_HEADER_ADDRESS, 35 SEARCH_HEADER_COMPRESS_LWSP, 36 37 /* body */ 38 SEARCH_BODY, 39 SEARCH_TEXT, 40 41 /* extensions */ 42 SEARCH_MODSEQ, 43 SEARCH_SAVEDATESUPPORTED, 44 SEARCH_INTHREAD, 45 SEARCH_GUID, 46 SEARCH_MAILBOX, 47 SEARCH_MAILBOX_GUID, 48 SEARCH_MAILBOX_GLOB, 49 SEARCH_REAL_UID, 50 SEARCH_MIMEPART 51 }; 52 53 enum mail_search_date_type { 54 MAIL_SEARCH_DATE_TYPE_SENT = 1, 55 MAIL_SEARCH_DATE_TYPE_RECEIVED, 56 MAIL_SEARCH_DATE_TYPE_SAVED 57 }; 58 59 enum mail_search_arg_flag { 60 /* Used by *BEFORE/SINCE/ON searches. 61 62 When NOT set: Adjust search timestamps so that the email's timezone 63 is included in the comparisons. For example 64 "04-Nov-2016 00:00:00 +0200" would match 4th day. This allows 65 searching for mails with dates from the email sender's point of 66 view. For received/saved dates there is no known timezone, and 67 without this flag the dates are compared using the server's local 68 timezone. 69 70 When set: Compare the timestamp as UTC. For example 71 "04-Nov-2016 00:00:00 +0200" would be treated as 72 "03-Nov-2016 22:00:00 UTC" and would match 3rd day. This allows 73 searching for mails within precise time interval. Since imap-dates 74 don't allow specifying timezone this isn't really possible with IMAP 75 protocol, except using OLDER/YOUNGER searches. */ 76 MAIL_SEARCH_ARG_FLAG_UTC_TIMES = 0x01, 77 }; 78 79 enum mail_search_modseq_type { 80 MAIL_SEARCH_MODSEQ_TYPE_ANY = 0, 81 MAIL_SEARCH_MODSEQ_TYPE_PRIVATE, 82 MAIL_SEARCH_MODSEQ_TYPE_SHARED 83 }; 84 85 struct mail_search_modseq { 86 uint64_t modseq; 87 enum mail_search_modseq_type type; 88 }; 89 90 struct mail_search_arg { 91 /* NOTE: when adding new fields, make sure mail_search_arg_dup_one() 92 and mail_search_arg_one_equals() are updated. */ 93 struct mail_search_arg *next; 94 95 enum mail_search_arg_type type; 96 struct { 97 struct mail_search_arg *subargs; 98 ARRAY_TYPE(seq_range) seqset; 99 const char *str; 100 time_t time; 101 uoff_t size; 102 enum mail_flags flags; 103 enum mail_search_arg_flag search_flags; 104 enum mail_search_date_type date_type; 105 enum mail_thread_type thread_type; 106 struct mail_search_modseq *modseq; 107 struct mail_search_result *search_result; 108 struct mail_search_mime_part *mime_part; 109 } value; 110 /* set by mail_search_args_init(): */ 111 struct { 112 struct mail_search_args *search_args; 113 /* Note that initialized keywords may be empty if the keyword 114 wasn't valid in this mailbox. */ 115 struct mail_keywords *keywords; 116 struct imap_match_glob *mailbox_glob; 117 } initialized; 118 119 void *context; 120 const char *hdr_field_name; /* for SEARCH_HEADER* */ 121 bool match_not:1; /* result = !result */ 122 bool match_always:1; /* result = 1 always */ 123 bool nonmatch_always:1; /* result = 0 always */ 124 bool fuzzy:1; /* use fuzzy matching for this arg */ 125 bool no_fts:1; /* do NOT call FTS */ 126 127 int result; /* -1 = unknown, 0 = unmatched, 1 = matched */ 128 }; 129 130 struct mail_search_args { 131 /* There are two types of refcount: 132 133 1) The normal refcount tracks the lifetime of the struct itself. 134 This allows using the same args for multiple search queries, even 135 across different mailboxes. 136 137 2) The init_refcount tracks how many times mail_search_args_init() has 138 been called. This can happen when the same mail_search_args have been 139 shared by referencing them in different parts of the code. Only after 140 each one of them has called mail_search_args_deinit() the init_refcount 141 drops to 0 and it can really be deinitialized. 142 143 Note that all of the inits must be within the same mailbox - attempting 144 to init the same args in different mailboxes at the same time will 145 result in assert-crash. */ 146 int refcount, init_refcount; 147 148 pool_t pool; 149 struct mailbox *box; 150 struct mail_search_arg *args; 151 152 bool simplified:1; 153 bool have_inthreads:1; 154 /* Stop mail_search_next() when finding a non-matching mail. 155 (Could be useful when wanting to find only the oldest mails.) */ 156 bool stop_on_nonmatch:1; 157 /* fts plugin has already expanded the search args - no need to do 158 it again. */ 159 bool fts_expanded:1; 160 }; 161 162 #define ARG_SET_RESULT(arg, res) \ 163 STMT_START { \ 164 (arg)->result = !(arg)->match_not ? (res) : \ 165 ((res) == -1 ? -1 : ((res) == 0 ? 1 : 0)); \ 166 } STMT_END 167 168 typedef void mail_search_foreach_callback_t(struct mail_search_arg *arg, 169 void *context); 170 171 /* Fully initialize and optimize the args for searching within the specified 172 mailbox. This should always be called before the args are actually used 173 for searching. After search is finished, the args must be deinitialized. 174 It's possible to initialize the same args multiple times, as long as it's 175 done within the same mailbox. This would allow multiple concurrent searches 176 to be done within the shared search args. 177 178 This will implicitly call mail_search_args_simplify() if it wasn't called 179 yet. It also allocates any necessary per-mailbox data like keywords. 180 181 If change_sets is TRUE, change uidsets to seqsets and convert "*" in seqsets 182 to the current highest message sequence. */ 183 void mail_search_args_init(struct mail_search_args *args, 184 struct mailbox *box, bool change_sets, 185 const ARRAY_TYPE(seq_range) *search_saved_uidset) 186 ATTR_NULL(4); 187 /* Initialize arg and its children. args is used for getting mailbox and 188 pool. */ 189 void mail_search_arg_init(struct mail_search_args *args, 190 struct mail_search_arg *arg); 191 /* Free memory allocated by mail_search_args_init(). The args can initialized 192 afterwards again if needed. The args can be reused for other queries after 193 calling this. */ 194 void mail_search_args_deinit(struct mail_search_args *args); 195 /* Free arg and its siblings and children. */ 196 void mail_search_arg_deinit(struct mail_search_arg *arg); 197 /* Free arg and its children, but not its siblings. */ 198 void mail_search_arg_one_deinit(struct mail_search_arg *arg); 199 /* Convert sequence sets in args to UIDs. */ 200 void mail_search_args_seq2uid(struct mail_search_args *args); 201 /* Returns TRUE if the two search arguments are fully compatible. 202 Always returns FALSE if there are seqsets, since they may point to different 203 messages depending on when the search is run. */ 204 bool mail_search_args_equal(const struct mail_search_args *args1, 205 const struct mail_search_args *args2); 206 /* Same as mail_search_args_equal(), but for individual mail_search_arg 207 structs. All the siblings of arg1 and arg2 are also compared. */ 208 bool mail_search_arg_equals(const struct mail_search_arg *arg1, 209 const struct mail_search_arg *arg2); 210 /* Same as mail_search_arg_equals(), but don't compare siblings. */ 211 bool mail_search_arg_one_equals(const struct mail_search_arg *arg1, 212 const struct mail_search_arg *arg2); 213 214 void mail_search_args_ref(struct mail_search_args *args); 215 void mail_search_args_unref(struct mail_search_args **args); 216 217 struct mail_search_args * 218 mail_search_args_dup(const struct mail_search_args *args); 219 struct mail_search_arg * 220 mail_search_arg_dup(pool_t pool, const struct mail_search_arg *arg); 221 222 /* Reset the results in search arguments. match_always is reset only if 223 full_reset is TRUE. */ 224 void mail_search_args_reset(struct mail_search_arg *args, bool full_reset); 225 226 /* goes through arguments in list that don't have a result yet. 227 Returns 1 = search matched, 0 = search unmatched, -1 = don't know yet */ 228 int mail_search_args_foreach(struct mail_search_arg *args, 229 mail_search_foreach_callback_t *callback, 230 void *context) ATTR_NULL(3); 231 #define mail_search_args_foreach(args, callback, context) \ 232 mail_search_args_foreach(args - \ 233 CALLBACK_TYPECHECK(callback, void (*)( \ 234 struct mail_search_arg *, typeof(context))), \ 235 (mail_search_foreach_callback_t *)callback, context) 236 237 /* Fills have_headers and have_body based on if such search argument exists 238 that needs to be checked. Returns the headers that we're searching for, or 239 NULL if we're searching for TEXT. */ 240 const char *const * 241 mail_search_args_analyze(struct mail_search_arg *args, 242 bool *have_headers, bool *have_body); 243 244 /* Returns FALSE if search query contains MAILBOX[_GLOB] args such that the 245 query can never match any messages in the given mailbox. */ 246 bool mail_search_args_match_mailbox(struct mail_search_args *args, 247 const char *vname, char sep); 248 249 /* Simplify/optimize search arguments. Afterwards all OR/SUB args are 250 guaranteed to have match_not=FALSE. */ 251 void mail_search_args_simplify(struct mail_search_args *args); 252 253 /* Append all args as IMAP SEARCH AND-query to the dest string and returns TRUE. 254 If some search arg can't be written as IMAP SEARCH parameter, error_r is set 255 and FALSE is returned. */ 256 bool mail_search_args_to_imap(string_t *dest, const struct mail_search_arg *args, 257 const char **error_r); 258 /* Like mail_search_args_to_imap(), but append only a single arg. */ 259 bool mail_search_arg_to_imap(string_t *dest, const struct mail_search_arg *arg, 260 const char **error_r); 261 /* Write all args to dest string as cmdline/human compatible input. */ 262 void mail_search_args_to_cmdline(string_t *dest, 263 const struct mail_search_arg *args); 264 265 /* Serialization for search args' results. */ 266 void mail_search_args_result_serialize(const struct mail_search_args *args, 267 buffer_t *dest); 268 void mail_search_args_result_deserialize(struct mail_search_args *args, 269 const unsigned char *data, 270 size_t size); 271 272 #endif 273