]> git.notmuchmail.org Git - notmuch/blob - lib/notmuch-private.h
emacs: Add new option notmuch-search-hide-excluded
[notmuch] / lib / notmuch-private.h
1 /* notmuch-private.h - Internal interfaces for notmuch.
2  *
3  * Copyright © 2009 Carl Worth
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see https://www.gnu.org/licenses/ .
17  *
18  * Author: Carl Worth <cworth@cworth.org>
19  */
20
21 #ifndef NOTMUCH_PRIVATE_H
22 #define NOTMUCH_PRIVATE_H
23
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE /* For getline and asprintf */
26 #endif
27 #include <stdbool.h>
28 #include <stdio.h>
29
30 #include "compat.h"
31
32 #include "notmuch.h"
33
34 #include "xutil.h"
35 #include "error_util.h"
36 #include "string-util.h"
37 #include "crypto.h"
38 #include "repair.h"
39
40 NOTMUCH_BEGIN_DECLS
41
42 #include <stdlib.h>
43 #include <stdarg.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/mman.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <unistd.h>
51 #include <ctype.h>
52 #include <assert.h>
53
54 #include <talloc.h>
55
56 #ifdef DEBUG
57 # define DEBUG_DATABASE_SANITY 1
58 # define DEBUG_THREADING 1
59 # define DEBUG_QUERY 1
60 #endif
61
62 #define COMPILE_TIME_ASSERT(pred) ((void) sizeof (char[1 - 2 * ! (pred)]))
63
64 #define STRNCMP_LITERAL(var, literal) \
65     strncmp ((var), (literal), sizeof (literal) - 1)
66
67 /* Robust bit test/set/reset macros */
68 #define _NOTMUCH_VALID_BIT(bit) \
69     ((bit) >= 0 && ((unsigned long) bit) < CHAR_BIT * sizeof (unsigned long long))
70 #define NOTMUCH_TEST_BIT(val, bit) \
71     (_NOTMUCH_VALID_BIT (bit) ? ! ! ((val) & (1ull << (bit))) : 0)
72 #define NOTMUCH_SET_BIT(valp, bit) \
73     (_NOTMUCH_VALID_BIT (bit) ? (*(valp) |= (1ull << (bit))) : *(valp))
74 #define NOTMUCH_CLEAR_BIT(valp,  bit) \
75     (_NOTMUCH_VALID_BIT (bit) ? (*(valp) &= ~(1ull << (bit))) : *(valp))
76
77 #define unused(x) x ## _unused __attribute__ ((unused))
78
79 /* Thanks to Andrew Tridgell's (SAMBA's) talloc for this definition of
80  * unlikely. The talloc source code comes to us via the GNU LGPL v. 3.
81  */
82 /* these macros gain us a few percent of speed on gcc */
83 #if (__GNUC__ >= 3)
84 /* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
85  * as its first argument */
86 #ifndef likely
87 #define likely(x)   __builtin_expect (! ! (x), 1)
88 #endif
89 #ifndef unlikely
90 #define unlikely(x) __builtin_expect (! ! (x), 0)
91 #endif
92 #else
93 #ifndef likely
94 #define likely(x) (x)
95 #endif
96 #ifndef unlikely
97 #define unlikely(x) (x)
98 #endif
99 #endif
100
101 typedef enum {
102     NOTMUCH_VALUE_TIMESTAMP = 0,
103     NOTMUCH_VALUE_MESSAGE_ID,
104     NOTMUCH_VALUE_FROM,
105     NOTMUCH_VALUE_SUBJECT,
106     NOTMUCH_VALUE_LAST_MOD,
107 } notmuch_value_t;
108
109 /* Xapian (with flint backend) complains if we provide a term longer
110  * than this, but I haven't yet found a way to query the limit
111  * programmatically. */
112 #define NOTMUCH_TERM_MAX 245
113
114 #define NOTMUCH_METADATA_THREAD_ID_PREFIX "thread_id_"
115
116 /* For message IDs we have to be even more restrictive. Beyond fitting
117  * into the term limit, we also use message IDs to construct
118  * metadata-key values. And the documentation says that these should
119  * be restricted to about 200 characters. (The actual limit for the
120  * chert backend at least is 252.)
121  */
122 #define NOTMUCH_MESSAGE_ID_MAX (200 - sizeof (NOTMUCH_METADATA_THREAD_ID_PREFIX))
123
124 typedef enum {
125     /* First, copy all the public status values. */
126     NOTMUCH_PRIVATE_STATUS_SUCCESS                      = NOTMUCH_STATUS_SUCCESS,
127     NOTMUCH_PRIVATE_STATUS_OUT_OF_MEMORY                = NOTMUCH_STATUS_OUT_OF_MEMORY,
128     NOTMUCH_PRIVATE_STATUS_READ_ONLY_DATABASE           = NOTMUCH_STATUS_READ_ONLY_DATABASE,
129     NOTMUCH_PRIVATE_STATUS_XAPIAN_EXCEPTION             = NOTMUCH_STATUS_XAPIAN_EXCEPTION,
130     NOTMUCH_PRIVATE_STATUS_FILE_ERROR                   = NOTMUCH_STATUS_FILE_ERROR,
131     NOTMUCH_PRIVATE_STATUS_FILE_NOT_EMAIL               = NOTMUCH_STATUS_FILE_NOT_EMAIL,
132     NOTMUCH_PRIVATE_STATUS_NULL_POINTER                 = NOTMUCH_STATUS_NULL_POINTER,
133     NOTMUCH_PRIVATE_STATUS_TAG_TOO_LONG                 = NOTMUCH_STATUS_TAG_TOO_LONG,
134     NOTMUCH_PRIVATE_STATUS_UNBALANCED_FREEZE_THAW       = NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW,
135     NOTMUCH_PRIVATE_STATUS_UNBALANCED_ATOMIC            = NOTMUCH_STATUS_UNBALANCED_ATOMIC,
136     NOTMUCH_PRIVATE_STATUS_UNSUPPORTED_OPERATION        = NOTMUCH_STATUS_UNSUPPORTED_OPERATION,
137     NOTMUCH_PRIVATE_STATUS_UPGRADE_REQUIRED             = NOTMUCH_STATUS_UPGRADE_REQUIRED,
138     NOTMUCH_PRIVATE_STATUS_PATH_ERROR                   = NOTMUCH_STATUS_PATH_ERROR,
139     NOTMUCH_PRIVATE_STATUS_IGNORED                      = NOTMUCH_STATUS_IGNORED,
140     NOTMUCH_PRIVATE_STATUS_ILLEGAL_ARGUMENT             = NOTMUCH_STATUS_ILLEGAL_ARGUMENT,
141     NOTMUCH_PRIVATE_STATUS_MALFORMED_CRYPTO_PROTOCOL            = NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL,
142     NOTMUCH_PRIVATE_STATUS_FAILED_CRYPTO_CONTEXT_CREATION       = NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION,
143     NOTMUCH_PRIVATE_STATUS_UNKNOWN_CRYPTO_PROTOCOL              = NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL,
144     NOTMUCH_PRIVATE_STATUS_NO_CONFIG                            = NOTMUCH_STATUS_NO_CONFIG,
145     NOTMUCH_PRIVATE_STATUS_NO_DATABASE                          = NOTMUCH_STATUS_NO_DATABASE,
146     NOTMUCH_PRIVATE_STATUS_DATABASE_EXISTS                      = NOTMUCH_STATUS_DATABASE_EXISTS,
147     NOTMUCH_PRIVATE_STATUS_NO_MAIL_ROOT                         = NOTMUCH_STATUS_NO_MAIL_ROOT,
148     NOTMUCH_PRIVATE_STATUS_BAD_QUERY_SYNTAX                     = NOTMUCH_STATUS_BAD_QUERY_SYNTAX,
149     NOTMUCH_PRIVATE_STATUS_CLOSED_DATABASE                      = NOTMUCH_STATUS_CLOSED_DATABASE,
150
151     /* Then add our own private values. */
152     NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG                = NOTMUCH_STATUS_LAST_STATUS,
153     NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND,
154     NOTMUCH_PRIVATE_STATUS_BAD_PREFIX,
155
156     NOTMUCH_PRIVATE_STATUS_LAST_STATUS
157 } notmuch_private_status_t;
158
159 /* Coerce a notmuch_private_status_t value to a notmuch_status_t
160  * value, generating an internal error if the private value is equal
161  * to or greater than NOTMUCH_STATUS_LAST_STATUS. (The idea here is
162  * that the caller has previously handled any expected
163  * notmuch_private_status_t values.)
164  *
165  * Note that the function _internal_error does not return. Evaluating
166  * to NOTMUCH_STATUS_SUCCESS is done purely to appease the compiler.
167  */
168 #define COERCE_STATUS(private_status, format, ...)                      \
169     ((private_status >= (notmuch_private_status_t) NOTMUCH_STATUS_LAST_STATUS) \
170      ?                                                                  \
171      _internal_error (format " (%s).\n",                                \
172                       ##__VA_ARGS__,                                    \
173                       __location__),                                    \
174      (notmuch_status_t) NOTMUCH_PRIVATE_STATUS_SUCCESS                  \
175      :                                                                  \
176      (notmuch_status_t) private_status)
177
178 /* Flags shared by various lookup functions. */
179 typedef enum {
180     /* Lookup without creating any documents.  This is the default
181      * behavior. */
182     NOTMUCH_FIND_LOOKUP = 0,
183     /* If set, create the necessary document (or documents) if they
184      * are missing.  Requires a read/write database. */
185     NOTMUCH_FIND_CREATE = 1 << 0,
186 } notmuch_find_flags_t;
187
188 typedef struct _notmuch_doc_id_set notmuch_doc_id_set_t;
189
190 /* database.cc */
191
192 /* Lookup a prefix value by name.
193  *
194  * XXX: This should really be static inside of message.cc, and we can
195  * do that once we convert database.cc to use the
196  * _notmuch_message_add/remove_term functions. */
197 const char *
198 _find_prefix (const char *name);
199
200 /* Lookup a prefix value by name, including possibly user defined prefixes
201  */
202 const char *
203 _notmuch_database_prefix (notmuch_database_t *notmuch, const char *name);
204
205 char *
206 _notmuch_message_id_compressed (void *ctx, const char *message_id);
207
208 notmuch_status_t
209 _notmuch_database_ensure_writable (notmuch_database_t *notmuch);
210
211 void
212 _notmuch_database_log (notmuch_database_t *notmuch,
213                        const char *format, ...);
214
215 void
216 _notmuch_database_log_append (notmuch_database_t *notmuch,
217                               const char *format, ...);
218
219 unsigned long
220 _notmuch_database_new_revision (notmuch_database_t *notmuch);
221
222 const char *
223 _notmuch_database_relative_path (notmuch_database_t *notmuch,
224                                  const char *path);
225
226 notmuch_status_t
227 _notmuch_database_split_path (void *ctx,
228                               const char *path,
229                               const char **directory,
230                               const char **basename);
231
232 const char *
233 _notmuch_database_get_directory_db_path (const char *path);
234
235 unsigned int
236 _notmuch_database_generate_doc_id (notmuch_database_t *notmuch);
237
238 notmuch_private_status_t
239 _notmuch_database_find_unique_doc_id (notmuch_database_t *notmuch,
240                                       const char *prefix_name,
241                                       const char *value,
242                                       unsigned int *doc_id);
243
244 notmuch_status_t
245 _notmuch_database_find_directory_id (notmuch_database_t *database,
246                                      const char *path,
247                                      notmuch_find_flags_t flags,
248                                      unsigned int *directory_id);
249
250 const char *
251 _notmuch_database_get_directory_path (void *ctx,
252                                       notmuch_database_t *notmuch,
253                                       unsigned int doc_id);
254
255 notmuch_status_t
256 _notmuch_database_filename_to_direntry (void *ctx,
257                                         notmuch_database_t *notmuch,
258                                         const char *filename,
259                                         notmuch_find_flags_t flags,
260                                         char **direntry);
261
262 bool
263 _notmuch_database_indexable_as_text (notmuch_database_t *notmuch,
264                                      const char *mime_string);
265
266 /* directory.cc */
267
268 notmuch_directory_t *
269 _notmuch_directory_find_or_create (notmuch_database_t *notmuch,
270                                    const char *path,
271                                    notmuch_find_flags_t flags,
272                                    notmuch_status_t *status_ret);
273
274 unsigned int
275 _notmuch_directory_get_document_id (notmuch_directory_t *directory);
276
277 notmuch_database_mode_t
278 _notmuch_database_mode (notmuch_database_t *notmuch);
279
280 /* message.cc */
281
282 notmuch_message_t *
283 _notmuch_message_create (const void *talloc_owner,
284                          notmuch_database_t *notmuch,
285                          unsigned int doc_id,
286                          notmuch_private_status_t *status);
287
288 notmuch_message_t *
289 _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
290                                         const char *message_id,
291                                         notmuch_private_status_t *status);
292
293 unsigned int
294 _notmuch_message_get_doc_id (notmuch_message_t *message);
295
296 const char *
297 _notmuch_message_get_in_reply_to (notmuch_message_t *message);
298
299 notmuch_private_status_t
300 _notmuch_message_add_term (notmuch_message_t *message,
301                            const char *prefix_name,
302                            const char *value);
303
304 notmuch_private_status_t
305 _notmuch_message_remove_term (notmuch_message_t *message,
306                               const char *prefix_name,
307                               const char *value);
308
309 notmuch_private_status_t
310 _notmuch_message_has_term (notmuch_message_t *message,
311                            const char *prefix_name,
312                            const char *value,
313                            bool *result);
314
315 notmuch_private_status_t
316 _notmuch_message_gen_terms (notmuch_message_t *message,
317                             const char *prefix_name,
318                             const char *text);
319
320 void
321 _notmuch_message_upgrade_filename_storage (notmuch_message_t *message);
322
323 void
324 _notmuch_message_upgrade_folder (notmuch_message_t *message);
325
326 notmuch_status_t
327 _notmuch_message_add_filename (notmuch_message_t *message,
328                                const char *filename);
329
330 notmuch_status_t
331 _notmuch_message_remove_filename (notmuch_message_t *message,
332                                   const char *filename);
333
334 notmuch_status_t
335 _notmuch_message_rename (notmuch_message_t *message,
336                          const char *new_filename);
337
338 void
339 _notmuch_message_ensure_thread_id (notmuch_message_t *message);
340
341 void
342 _notmuch_message_set_header_values (notmuch_message_t *message,
343                                     const char *date,
344                                     const char *from,
345                                     const char *subject);
346
347 void
348 _notmuch_message_update_subject (notmuch_message_t *message,
349                                  const char *subject);
350
351 void
352 _notmuch_message_upgrade_last_mod (notmuch_message_t *message);
353
354 void
355 _notmuch_message_sync (notmuch_message_t *message);
356
357 notmuch_status_t
358 _notmuch_message_delete (notmuch_message_t *message);
359
360 notmuch_private_status_t
361 _notmuch_message_initialize_ghost (notmuch_message_t *message,
362                                    const char *thread_id);
363
364 void
365 _notmuch_message_close (notmuch_message_t *message);
366
367 /* Get a copy of the data in this message document.
368  *
369  * Caller should talloc_free the result when done.
370  *
371  * This function is intended to support database upgrade and really
372  * shouldn't be used otherwise. */
373 char *
374 _notmuch_message_talloc_copy_data (notmuch_message_t *message);
375
376 /* Clear the data in this message document.
377  *
378  * This function is intended to support database upgrade and really
379  * shouldn't be used otherwise. */
380 void
381 _notmuch_message_clear_data (notmuch_message_t *message);
382
383 /* Set the author member of 'message' - this is the representation used
384  * when displaying the message */
385 void
386 _notmuch_message_set_author (notmuch_message_t *message, const char *author);
387
388 /* Get the author member of 'message' */
389 const char *
390 _notmuch_message_get_author (notmuch_message_t *message);
391
392 /* message-file.c */
393
394 /* XXX: I haven't decided yet whether these will actually get exported
395  * into the public interface in notmuch.h
396  */
397
398 typedef struct _notmuch_message_file notmuch_message_file_t;
399
400 /* Open a file containing a single email message.
401  *
402  * The caller should call notmuch_message_close when done with this.
403  *
404  * Returns NULL if any error occurs.
405  */
406 notmuch_message_file_t *
407 _notmuch_message_file_open (notmuch_database_t *notmuch, const char *filename);
408
409 /* Like notmuch_message_file_open but with 'ctx' as the talloc owner. */
410 notmuch_message_file_t *
411 _notmuch_message_file_open_ctx (notmuch_database_t *notmuch,
412                                 void *ctx, const char *filename);
413
414 /* Close a notmuch message previously opened with notmuch_message_open. */
415 void
416 _notmuch_message_file_close (notmuch_message_file_t *message);
417
418 /* Parse the message.
419  *
420  * This will be done automatically as necessary on other calls
421  * depending on it, but an explicit call allows for better error
422  * status reporting.
423  */
424 notmuch_status_t
425 _notmuch_message_file_parse (notmuch_message_file_t *message);
426
427 /* Get the gmime message of a message file.
428  *
429  * The message file is parsed as necessary.
430  *
431  * The GMimeMessage* is set to *mime_message on success (which the
432  * caller must not unref).
433  *
434  * XXX: Would be nice to not have to expose GMimeMessage here.
435  */
436 notmuch_status_t
437 _notmuch_message_file_get_mime_message (notmuch_message_file_t *message,
438                                         GMimeMessage **mime_message);
439
440 /* Get the value of the specified header from the message as a UTF-8 string.
441  *
442  * The message file is parsed as necessary.
443  *
444  * The header name is case insensitive.
445  *
446  * The Received: header is special - for it all Received: headers in
447  * the message are concatenated
448  *
449  * The returned value is owned by the notmuch message and is valid
450  * only until the message is closed. The caller should copy it if
451  * needing to modify the value or to hold onto it for longer.
452  *
453  * Returns NULL on errors, empty string if the message does not
454  * contain a header line matching 'header'.
455  */
456 const char *
457 _notmuch_message_file_get_header (notmuch_message_file_t *message,
458                                   const char *header);
459
460 notmuch_status_t
461 _notmuch_message_file_get_headers (notmuch_message_file_t *message_file,
462                                    const char **from_out,
463                                    const char **subject_out,
464                                    const char **to_out,
465                                    const char **date_out,
466                                    char **message_id_out);
467
468 const char *
469 _notmuch_message_file_get_filename (notmuch_message_file_t *message);
470
471 /* add-message.cc */
472 notmuch_status_t
473 _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
474                                            notmuch_message_t *message,
475                                            notmuch_message_file_t *message_file,
476                                            const char **thread_id);
477 /* index.cc */
478
479 void
480 _notmuch_filter_init ();
481
482 notmuch_status_t
483 _notmuch_message_index_file (notmuch_message_t *message,
484                              notmuch_indexopts_t *indexopts,
485                              notmuch_message_file_t *message_file);
486
487 /* init.cc */
488 void
489 _notmuch_init ();
490
491 /* messages.c */
492
493 typedef struct _notmuch_message_node {
494     notmuch_message_t *message;
495     struct _notmuch_message_node *next;
496 } notmuch_message_node_t;
497
498 typedef struct _notmuch_message_list {
499     notmuch_message_node_t *head;
500     notmuch_message_node_t **tail;
501 } notmuch_message_list_t;
502
503 /* There's a rumor that there's an alternate struct _notmuch_messages
504  * somewhere with some nasty C++ objects in it. We'll try to maintain
505  * ignorance of that here. (See notmuch_mset_messages_t in query.cc)
506  */
507 struct _notmuch_messages {
508     bool is_of_list_type;
509     notmuch_doc_id_set_t *excluded_doc_ids;
510     notmuch_message_node_t *iterator;
511 };
512
513 notmuch_message_list_t *
514 _notmuch_message_list_create (const void *ctx);
515
516 bool
517 _notmuch_message_list_empty (notmuch_message_list_t *list);
518
519 void
520 _notmuch_message_list_add_message (notmuch_message_list_t *list,
521                                    notmuch_message_t *message);
522
523 notmuch_messages_t *
524 _notmuch_messages_create (notmuch_message_list_t *list);
525
526 bool
527 _notmuch_messages_has_next (notmuch_messages_t *messages);
528
529 /* query.cc */
530
531 bool
532 _notmuch_mset_messages_valid (notmuch_messages_t *messages);
533
534 notmuch_message_t *
535 _notmuch_mset_messages_get (notmuch_messages_t *messages);
536
537 void
538 _notmuch_mset_messages_move_to_next (notmuch_messages_t *messages);
539
540 bool
541 _notmuch_doc_id_set_contains (notmuch_doc_id_set_t *doc_ids,
542                               unsigned int doc_id);
543
544 void
545 _notmuch_doc_id_set_remove (notmuch_doc_id_set_t *doc_ids,
546                             unsigned int doc_id);
547
548 /* querying xapian documents by type (e.g. "mail" or "ghost"): */
549 notmuch_status_t
550 _notmuch_query_search_documents (notmuch_query_t *query,
551                                  const char *type,
552                                  notmuch_messages_t **out);
553
554 notmuch_status_t
555 _notmuch_query_count_documents (notmuch_query_t *query,
556                                 const char *type,
557                                 unsigned *count_out);
558 /* message-id.c */
559
560 /* Parse an RFC 822 message-id, discarding whitespace, any RFC 822
561  * comments, and the '<' and '>' delimiters.
562  *
563  * If not NULL, then *next will be made to point to the first character
564  * not parsed, (possibly pointing to the final '\0' terminator.
565  *
566  * Returns a newly talloc'ed string belonging to 'ctx'.
567  *
568  * Returns NULL if there is any error parsing the message-id. */
569 char *
570 _notmuch_message_id_parse (void *ctx, const char *message_id, const char **next);
571
572 /* Parse a message-id, discarding leading and trailing whitespace, and
573  * '<' and '>' delimiters.
574  *
575  * Apply a probably-stricter-than RFC definition of what is allowed in
576  * a message-id. In particular, forbid whitespace.
577  *
578  * Returns a newly talloc'ed string belonging to 'ctx'.
579  *
580  * Returns NULL if there is any error parsing the message-id.
581  */
582
583 char *
584 _notmuch_message_id_parse_strict (void *ctx, const char *message_id);
585
586
587 /* message.cc */
588
589 void
590 _notmuch_message_add_reply (notmuch_message_t *message,
591                             notmuch_message_t *reply);
592
593 void
594 _notmuch_message_remove_unprefixed_terms (notmuch_message_t *message);
595
596 size_t _notmuch_message_get_thread_depth (notmuch_message_t *message);
597
598 void
599 _notmuch_message_label_depths (notmuch_message_t *message,
600                                size_t depth);
601
602 notmuch_message_list_t *
603 _notmuch_message_sort_subtrees (void *ctx, notmuch_message_list_t *list);
604
605 /* sha1.c */
606
607 char *
608 _notmuch_sha1_of_string (const char *str);
609
610 char *
611 _notmuch_sha1_of_file (const char *filename);
612
613 /* string-list.c */
614
615 typedef struct _notmuch_string_node {
616     char *string;
617     struct _notmuch_string_node *next;
618 } notmuch_string_node_t;
619
620 typedef struct _notmuch_string_list {
621     int length;
622     notmuch_string_node_t *head;
623     notmuch_string_node_t **tail;
624 } notmuch_string_list_t;
625
626 notmuch_string_list_t *
627 _notmuch_string_list_create (const void *ctx);
628
629 /*
630  * return the number of strings in 'list'
631  */
632 int
633 _notmuch_string_list_length (notmuch_string_list_t *list);
634
635 /* Add 'string' to 'list'.
636  *
637  * The list will create its own talloced copy of 'string'.
638  */
639 void
640 _notmuch_string_list_append (notmuch_string_list_t *list,
641                              const char *string);
642
643 void
644 _notmuch_string_list_sort (notmuch_string_list_t *list);
645
646 const notmuch_string_list_t *
647 _notmuch_message_get_references (notmuch_message_t *message);
648
649 /* string-map.c */
650 typedef struct _notmuch_string_map notmuch_string_map_t;
651 typedef struct _notmuch_string_map_iterator notmuch_string_map_iterator_t;
652 notmuch_string_map_t *
653 _notmuch_string_map_create (const void *ctx);
654
655 void
656 _notmuch_string_map_append (notmuch_string_map_t *map,
657                             const char *key,
658                             const char *value);
659
660 void
661 _notmuch_string_map_set (notmuch_string_map_t *map,
662                          const char *key,
663                          const char *value);
664
665 const char *
666 _notmuch_string_map_get (notmuch_string_map_t *map, const char *key);
667
668 notmuch_string_map_iterator_t *
669 _notmuch_string_map_iterator_create (notmuch_string_map_t *map, const char *key,
670                                      bool exact);
671
672 bool
673 _notmuch_string_map_iterator_valid (notmuch_string_map_iterator_t *iter);
674
675 void
676 _notmuch_string_map_iterator_move_to_next (notmuch_string_map_iterator_t *iter);
677
678 const char *
679 _notmuch_string_map_iterator_key (notmuch_string_map_iterator_t *iterator);
680
681 const char *
682 _notmuch_string_map_iterator_value (notmuch_string_map_iterator_t *iterator);
683
684 void
685 _notmuch_string_map_iterator_destroy (notmuch_string_map_iterator_t *iterator);
686
687 /* Create an iterator for user headers. Destroy with
688  * _notmuch_string_map_iterator_destroy. Actually in database.cc*/
689 notmuch_string_map_iterator_t *
690 _notmuch_database_user_headers (notmuch_database_t *notmuch);
691
692 /* tags.c */
693
694 notmuch_tags_t *
695 _notmuch_tags_create (const void *ctx, notmuch_string_list_t *list);
696
697 /* filenames.c */
698
699 /* The notmuch_filenames_t iterates over a notmuch_string_list_t of
700  * file names */
701 notmuch_filenames_t *
702 _notmuch_filenames_create (const void *ctx,
703                            notmuch_string_list_t *list);
704
705 /* thread.cc */
706
707 notmuch_thread_t *
708 _notmuch_thread_create (void *ctx,
709                         notmuch_database_t *notmuch,
710                         unsigned int seed_doc_id,
711                         notmuch_doc_id_set_t *match_set,
712                         notmuch_string_list_t *excluded_terms,
713                         notmuch_exclude_t omit_exclude,
714                         notmuch_sort_t sort);
715
716 /* indexopts.c */
717
718 struct _notmuch_indexopts;
719
720 #define CONFIG_HEADER_PREFIX "index.header."
721
722 #define EMPTY_STRING(s) ((s)[0] == '\0')
723
724 /* config.cc */
725 notmuch_status_t
726 _notmuch_config_load_from_database (notmuch_database_t *db);
727
728 notmuch_status_t
729 _notmuch_config_load_from_file (notmuch_database_t *db, GKeyFile *file, char **status_string);
730
731 notmuch_status_t
732 _notmuch_config_load_defaults (notmuch_database_t *db);
733
734 void
735 _notmuch_config_cache (notmuch_database_t *db, notmuch_config_key_t key, const char *val);
736
737 /* open.cc */
738 notmuch_status_t
739 _notmuch_choose_xapian_path (void *ctx, const char *database_path, const char **xapian_path,
740                              char **message);
741
742 NOTMUCH_END_DECLS
743
744 #ifdef __cplusplus
745 /* Implicit typecast from 'void *' to 'T *' is okay in C, but not in
746  * C++. In talloc_steal, an explicit cast is provided for type safety
747  * in some GCC versions. Otherwise, a cast is required. Provide a
748  * template function for this to maintain type safety, and redefine
749  * talloc_steal to use it.
750  */
751 #if ! (__GNUC__ >= 3)
752 template <class T> T *
753 _notmuch_talloc_steal (const void *new_ctx, const T *ptr)
754 {
755     return static_cast<T *> (talloc_steal (new_ctx, ptr));
756 }
757 #undef talloc_steal
758 #define talloc_steal _notmuch_talloc_steal
759 #endif
760
761 #if __cplusplus >= 201703L || __cppcheck__
762 #define NODISCARD [[nodiscard]]
763 #else
764 #define NODISCARD /**/
765 #endif
766 #endif
767
768 #endif