]> git.notmuchmail.org Git - notmuch/blobdiff - lib/notmuch-private.h
lib: provide _notmuch_database_log_append
[notmuch] / lib / notmuch-private.h
index b956634057f9dcae62b6b9778ff5415250574a0a..643d9dd9d68867b9fa05cba23b5f65b3ab62ebea 100644 (file)
@@ -13,7 +13,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see http://www.gnu.org/licenses/ .
+ * along with this program.  If not, see https://www.gnu.org/licenses/ .
  *
  * Author: Carl Worth <cworth@cworth.org>
  */
@@ -46,7 +46,13 @@ NOTMUCH_BEGIN_DECLS
 
 #include <talloc.h>
 
+#include <gmime/gmime.h>
+
 #include "xutil.h"
+#include "error_util.h"
+#include "string-util.h"
+
+#pragma GCC visibility push(hidden)
 
 #ifdef DEBUG
 # define DEBUG_DATABASE_SANITY 1
@@ -55,27 +61,27 @@ NOTMUCH_BEGIN_DECLS
 
 #define COMPILE_TIME_ASSERT(pred) ((void)sizeof(char[1 - 2*!(pred)]))
 
-/* There's no point in continuing when we've detected that we've done
- * something wrong internally (as opposed to the user passing in a
- * bogus value).
- *
- * Note that PRINTF_ATTRIBUTE comes from talloc.h
- */
-int
-_internal_error (const char *format, ...) PRINTF_ATTRIBUTE (1, 2);
+#define STRNCMP_LITERAL(var, literal) \
+    strncmp ((var), (literal), sizeof (literal) - 1)
 
-/* There's no point in continuing when we've detected that we've done
- * something wrong internally (as opposed to the user passing in a
- * bogus value).
- *
- * Note that __location__ comes from talloc.h.
- */
-#define INTERNAL_ERROR(format, ...)                    \
-    _internal_error (format " (%s).\n",                        \
-                    ##__VA_ARGS__, __location__)
+/* Robust bit test/set/reset macros */
+#define _NOTMUCH_VALID_BIT(bit) \
+    ((bit) >= 0 && ((unsigned long) bit) < CHAR_BIT * sizeof (unsigned long long))
+#define NOTMUCH_TEST_BIT(val, bit) \
+    (_NOTMUCH_VALID_BIT(bit) ? !!((val) & (1ull << (bit))) : 0)
+#define NOTMUCH_SET_BIT(valp, bit) \
+    (_NOTMUCH_VALID_BIT(bit) ? (*(valp) |= (1ull << (bit))) : *(valp))
+#define NOTMUCH_CLEAR_BIT(valp,  bit) \
+    (_NOTMUCH_VALID_BIT(bit) ? (*(valp) &= ~(1ull << (bit))) : *(valp))
 
 #define unused(x) x __attribute__ ((unused))
 
+#ifdef __cplusplus
+# define visible __attribute__((visibility("default")))
+#else
+# define visible
+#endif
+
 /* Thanks to Andrew Tridgell's (SAMBA's) talloc for this definition of
  * unlikely. The talloc source code comes to us via the GNU LGPL v. 3.
  */
@@ -100,7 +106,10 @@ _internal_error (const char *format, ...) PRINTF_ATTRIBUTE (1, 2);
 
 typedef enum {
     NOTMUCH_VALUE_TIMESTAMP = 0,
-    NOTMUCH_VALUE_MESSAGE_ID
+    NOTMUCH_VALUE_MESSAGE_ID,
+    NOTMUCH_VALUE_FROM,
+    NOTMUCH_VALUE_SUBJECT,
+    NOTMUCH_VALUE_LAST_MOD,
 } notmuch_value_t;
 
 /* Xapian (with flint backend) complains if we provide a term longer
@@ -108,11 +117,21 @@ typedef enum {
  * programmatically. */
 #define NOTMUCH_TERM_MAX 245
 
+#define NOTMUCH_METADATA_THREAD_ID_PREFIX "thread_id_"
+
+/* For message IDs we have to be even more restrictive. Beyond fitting
+ * into the term limit, we also use message IDs to construct
+ * metadata-key values. And the documentation says that these should
+ * be restricted to about 200 characters. (The actual limit for the
+ * chert backend at least is 252.)
+ */
+#define NOTMUCH_MESSAGE_ID_MAX (200 - sizeof (NOTMUCH_METADATA_THREAD_ID_PREFIX))
+
 typedef enum _notmuch_private_status {
     /* First, copy all the public status values. */
     NOTMUCH_PRIVATE_STATUS_SUCCESS = NOTMUCH_STATUS_SUCCESS,
     NOTMUCH_PRIVATE_STATUS_OUT_OF_MEMORY = NOTMUCH_STATUS_OUT_OF_MEMORY,
-    NOTMUCH_PRIVATE_STATUS_READONLY_DATABASE = NOTMUCH_STATUS_READONLY_DATABASE,
+    NOTMUCH_PRIVATE_STATUS_READ_ONLY_DATABASE = NOTMUCH_STATUS_READ_ONLY_DATABASE,
     NOTMUCH_PRIVATE_STATUS_XAPIAN_EXCEPTION = NOTMUCH_STATUS_XAPIAN_EXCEPTION,
     NOTMUCH_PRIVATE_STATUS_FILE_NOT_EMAIL = NOTMUCH_STATUS_FILE_NOT_EMAIL,
     NOTMUCH_PRIVATE_STATUS_NULL_POINTER = NOTMUCH_STATUS_NULL_POINTER,
@@ -131,16 +150,32 @@ typedef enum _notmuch_private_status {
  * to or greater than NOTMUCH_STATUS_LAST_STATUS. (The idea here is
  * that the caller has previously handled any expected
  * notmuch_private_status_t values.)
+ *
+ * Note that the function _internal_error does not return. Evaluating
+ * to NOTMUCH_STATUS_SUCCESS is done purely to appease the compiler.
  */
 #define COERCE_STATUS(private_status, format, ...)                     \
     ((private_status >= (notmuch_private_status_t) NOTMUCH_STATUS_LAST_STATUS)\
      ?                                                                 \
-     (notmuch_status_t) _internal_error (format " (%s).\n",            \
-                                         ##__VA_ARGS__,                        \
-                                         __location__)                 \
+     _internal_error (format " (%s).\n",                               \
+                     ##__VA_ARGS__,                                    \
+                     __location__),                                    \
+     (notmuch_status_t) NOTMUCH_PRIVATE_STATUS_SUCCESS                 \
      :                                                                 \
      (notmuch_status_t) private_status)
 
+/* Flags shared by various lookup functions. */
+typedef enum _notmuch_find_flags {
+    /* Lookup without creating any documents.  This is the default
+     * behavior. */
+    NOTMUCH_FIND_LOOKUP = 0,
+    /* If set, create the necessary document (or documents) if they
+     * are missing.  Requires a read/write database. */
+    NOTMUCH_FIND_CREATE = 1<<0,
+} notmuch_find_flags_t;
+
+typedef struct _notmuch_doc_id_set notmuch_doc_id_set_t;
+
 /* database.cc */
 
 /* Lookup a prefix value by name.
@@ -151,13 +186,73 @@ typedef enum _notmuch_private_status {
 const char *
 _find_prefix (const char *name);
 
-/* thread.cc */
+char *
+_notmuch_message_id_compressed (void *ctx, const char *message_id);
 
-notmuch_thread_t *
-_notmuch_thread_create (void *ctx,
-                       notmuch_database_t *notmuch,
-                       const char *thread_id,
-                       const char *query_string);
+notmuch_status_t
+_notmuch_database_ensure_writable (notmuch_database_t *notmuch);
+
+void
+_notmuch_database_log (notmuch_database_t *notmuch,
+                      const char *format, ...);
+
+void
+_notmuch_database_log_append (notmuch_database_t *notmuch,
+                             const char *format, ...);
+
+unsigned long
+_notmuch_database_new_revision (notmuch_database_t *notmuch);
+
+const char *
+_notmuch_database_relative_path (notmuch_database_t *notmuch,
+                                const char *path);
+
+notmuch_status_t
+_notmuch_database_split_path (void *ctx,
+                             const char *path,
+                             const char **directory,
+                             const char **basename);
+
+const char *
+_notmuch_database_get_directory_db_path (const char *path);
+
+unsigned int
+_notmuch_database_generate_doc_id (notmuch_database_t *notmuch);
+
+notmuch_private_status_t
+_notmuch_database_find_unique_doc_id (notmuch_database_t *notmuch,
+                                     const char *prefix_name,
+                                     const char *value,
+                                     unsigned int *doc_id);
+
+notmuch_status_t
+_notmuch_database_find_directory_id (notmuch_database_t *database,
+                                    const char *path,
+                                    notmuch_find_flags_t flags,
+                                    unsigned int *directory_id);
+
+const char *
+_notmuch_database_get_directory_path (void *ctx,
+                                     notmuch_database_t *notmuch,
+                                     unsigned int doc_id);
+
+notmuch_status_t
+_notmuch_database_filename_to_direntry (void *ctx,
+                                       notmuch_database_t *notmuch,
+                                       const char *filename,
+                                       notmuch_find_flags_t flags,
+                                       char **direntry);
+
+/* directory.cc */
+
+notmuch_directory_t *
+_notmuch_directory_create (notmuch_database_t *notmuch,
+                          const char *path,
+                          notmuch_find_flags_t flags,
+                          notmuch_status_t *status_ret);
+
+unsigned int
+_notmuch_directory_get_document_id (notmuch_directory_t *directory);
 
 /* message.cc */
 
@@ -172,6 +267,9 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
                                        const char *message_id,
                                        notmuch_private_status_t *status);
 
+unsigned int
+_notmuch_message_get_doc_id (notmuch_message_t *message);
+
 const char *
 _notmuch_message_get_in_reply_to (notmuch_message_t *message);
 
@@ -185,33 +283,84 @@ _notmuch_message_remove_term (notmuch_message_t *message,
                              const char *prefix_name,
                              const char *value);
 
+notmuch_private_status_t
+_notmuch_message_has_term (notmuch_message_t *message,
+                          const char *prefix_name,
+                          const char *value,
+                          notmuch_bool_t *result);
+
 notmuch_private_status_t
 _notmuch_message_gen_terms (notmuch_message_t *message,
                            const char *prefix_name,
                            const char *text);
 
 void
-_notmuch_message_set_filename (notmuch_message_t *message,
+_notmuch_message_upgrade_filename_storage (notmuch_message_t *message);
+
+void
+_notmuch_message_upgrade_folder (notmuch_message_t *message);
+
+notmuch_status_t
+_notmuch_message_add_filename (notmuch_message_t *message,
                               const char *filename);
 
+notmuch_status_t
+_notmuch_message_remove_filename (notmuch_message_t *message,
+                                 const char *filename);
+
+notmuch_status_t
+_notmuch_message_rename (notmuch_message_t *message,
+                        const char *new_filename);
+
 void
 _notmuch_message_ensure_thread_id (notmuch_message_t *message);
 
 void
-_notmuch_message_set_date (notmuch_message_t *message,
-                          const char *date);
+_notmuch_message_set_header_values (notmuch_message_t *message,
+                                   const char *date,
+                                   const char *from,
+                                   const char *subject);
+
+void
+_notmuch_message_upgrade_last_mod (notmuch_message_t *message);
 
 void
 _notmuch_message_sync (notmuch_message_t *message);
 
+notmuch_status_t
+_notmuch_message_delete (notmuch_message_t *message);
+
+notmuch_private_status_t
+_notmuch_message_initialize_ghost (notmuch_message_t *message,
+                                  const char *thread_id);
+
 void
 _notmuch_message_close (notmuch_message_t *message);
 
-/* index.cc */
+/* Get a copy of the data in this message document.
+ *
+ * Caller should talloc_free the result when done.
+ *
+ * This function is intended to support database upgrade and really
+ * shouldn't be used otherwise. */
+char *
+_notmuch_message_talloc_copy_data (notmuch_message_t *message);
 
-notmuch_status_t
-_notmuch_message_index_file (notmuch_message_t *message,
-                            const char *filename);
+/* Clear the data in this message document.
+ *
+ * This function is intended to support database upgrade and really
+ * shouldn't be used otherwise. */
+void
+_notmuch_message_clear_data (notmuch_message_t *message);
+
+/* Set the author member of 'message' - this is the representation used
+ * when displaying the message */
+void
+_notmuch_message_set_author (notmuch_message_t *message, const char *author);
+
+/* Get the author member of 'message' */
+const char *
+_notmuch_message_get_author (notmuch_message_t *message);
 
 /* message-file.c */
 
@@ -228,55 +377,65 @@ typedef struct _notmuch_message_file notmuch_message_file_t;
  * Returns NULL if any error occurs.
  */
 notmuch_message_file_t *
-notmuch_message_file_open (const char *filename);
+_notmuch_message_file_open (notmuch_database_t *notmuch, const char *filename);
 
 /* Like notmuch_message_file_open but with 'ctx' as the talloc owner. */
 notmuch_message_file_t *
-_notmuch_message_file_open_ctx (void *ctx, const char *filename);
+_notmuch_message_file_open_ctx (notmuch_database_t *notmuch,
+                               void *ctx, const char *filename);
 
 /* Close a notmuch message previously opened with notmuch_message_open. */
 void
-notmuch_message_file_close (notmuch_message_file_t *message);
+_notmuch_message_file_close (notmuch_message_file_t *message);
 
-/* Restrict 'message' to only save the named headers.
+/* Parse the message.
  *
- * When the caller is only interested in a short list of headers,
- * known in advance, calling this function can avoid wasted time and
- * memory parsing/saving header values that will never be needed.
+ * This will be done automatically as necessary on other calls
+ * depending on it, but an explicit call allows for better error
+ * status reporting.
+ */
+notmuch_status_t
+_notmuch_message_file_parse (notmuch_message_file_t *message);
+
+/* Get the gmime message of a message file.
  *
- * The variable arguments should be a list of const char * with a
- * final '(const char *) NULL' to terminate the list.
+ * The message file is parsed as necessary.
  *
- * If this function is called, it must be called before any calls to
- * notmuch_message_get_header for this message.
+ * The GMimeMessage* is set to *mime_message on success (which the
+ * caller must not unref).
  *
- * After calling this function, if notmuch_message_get_header is
- * called with a header name not in this list, then NULL will be
- * returned even if that header exists in the actual message.
+ * XXX: Would be nice to not have to expose GMimeMessage here.
  */
-void
-notmuch_message_file_restrict_headers (notmuch_message_file_t *message, ...);
-
-/* Identical to notmuch_message_restrict_headers but accepting a va_list. */
-void
-notmuch_message_file_restrict_headersv (notmuch_message_file_t *message,
-                                       va_list va_headers);
+notmuch_status_t
+_notmuch_message_file_get_mime_message (notmuch_message_file_t *message,
+                                       GMimeMessage **mime_message);
 
-/* Get the value of the specified header from the message.
+/* Get the value of the specified header from the message as a UTF-8 string.
+ *
+ * The message file is parsed as necessary.
  *
  * The header name is case insensitive.
  *
+ * The Received: header is special - for it all Received: headers in
+ * the message are concatenated
+ *
  * The returned value is owned by the notmuch message and is valid
  * only until the message is closed. The caller should copy it if
  * needing to modify the value or to hold onto it for longer.
  *
- * Returns NULL if the message does not contain a header line matching
- * 'header'.
+ * Returns NULL on errors, empty string if the message does not
+ * contain a header line matching 'header'.
  */
 const char *
-notmuch_message_file_get_header (notmuch_message_file_t *message,
+_notmuch_message_file_get_header (notmuch_message_file_t *message,
                                 const char *header);
 
+/* index.cc */
+
+notmuch_status_t
+_notmuch_message_index_file (notmuch_message_t *message,
+                            notmuch_message_file_t *message_file);
+
 /* messages.c */
 
 typedef struct _notmuch_message_node {
@@ -293,18 +452,15 @@ typedef struct _notmuch_message_list {
  * somewhere with some nasty C++ objects in it. We'll try to maintain
  * ignorance of that here. (See notmuch_mset_messages_t in query.cc)
  */
-struct _notmuch_messages {
+struct visible _notmuch_messages {
     notmuch_bool_t is_of_list_type;
+    notmuch_doc_id_set_t *excluded_doc_ids;
     notmuch_message_node_t *iterator;
 };
 
 notmuch_message_list_t *
 _notmuch_message_list_create (const void *ctx);
 
-void
-_notmuch_message_list_append (notmuch_message_list_t *list,
-                             notmuch_message_node_t *node);
-
 void
 _notmuch_message_list_add_message (notmuch_message_list_t *list,
                                   notmuch_message_t *message);
@@ -315,39 +471,120 @@ _notmuch_messages_create (notmuch_message_list_t *list);
 /* query.cc */
 
 notmuch_bool_t
-_notmuch_mset_messages_has_more (notmuch_messages_t *messages);
+_notmuch_mset_messages_valid (notmuch_messages_t *messages);
 
 notmuch_message_t *
 _notmuch_mset_messages_get (notmuch_messages_t *messages);
 
 void
-_notmuch_mset_messages_advance (notmuch_messages_t *messages);
+_notmuch_mset_messages_move_to_next (notmuch_messages_t *messages);
+
+notmuch_bool_t
+_notmuch_doc_id_set_contains (notmuch_doc_id_set_t *doc_ids,
+                             unsigned int doc_id);
+
+void
+_notmuch_doc_id_set_remove (notmuch_doc_id_set_t *doc_ids,
+                           unsigned int doc_id);
+
+/* querying xapian documents by type (e.g. "mail" or "ghost"): */
+notmuch_status_t
+_notmuch_query_search_documents (notmuch_query_t *query,
+                                const char *type,
+                                notmuch_messages_t **out);
+
+notmuch_status_t
+_notmuch_query_count_documents (notmuch_query_t *query,
+                               const char *type,
+                               unsigned *count_out);
 
 /* message.cc */
 
 void
 _notmuch_message_add_reply (notmuch_message_t *message,
-                           notmuch_message_node_t *reply);
+                           notmuch_message_t *reply);
+notmuch_database_t *
+_notmuch_message_database (notmuch_message_t *message);
 
 /* sha1.c */
 
 char *
-notmuch_sha1_of_string (const char *str);
+_notmuch_sha1_of_string (const char *str);
 
 char *
-notmuch_sha1_of_file (const char *filename);
+_notmuch_sha1_of_file (const char *filename);
 
-/* tags.c */
+/* string-list.c */
 
-notmuch_tags_t *
-_notmuch_tags_create (void *ctx);
+typedef struct _notmuch_string_node {
+    char *string;
+    struct _notmuch_string_node *next;
+} notmuch_string_node_t;
+
+typedef struct visible _notmuch_string_list {
+    int length;
+    notmuch_string_node_t *head;
+    notmuch_string_node_t **tail;
+} notmuch_string_list_t;
 
+notmuch_string_list_t *
+_notmuch_string_list_create (const void *ctx);
+
+/* Add 'string' to 'list'.
+ *
+ * The list will create its own talloced copy of 'string'.
+ */
 void
-_notmuch_tags_add_tag (notmuch_tags_t *tags, const char *tag);
+_notmuch_string_list_append (notmuch_string_list_t *list,
+                            const char *string);
 
 void
-_notmuch_tags_prepare_iterator (notmuch_tags_t *tags);
+_notmuch_string_list_sort (notmuch_string_list_t *list);
+
+/* tags.c */
+
+notmuch_tags_t *
+_notmuch_tags_create (const void *ctx, notmuch_string_list_t *list);
+
+/* filenames.c */
+
+/* The notmuch_filenames_t iterates over a notmuch_string_list_t of
+ * file names */
+notmuch_filenames_t *
+_notmuch_filenames_create (const void *ctx,
+                          notmuch_string_list_t *list);
+
+/* thread.cc */
+
+notmuch_thread_t *
+_notmuch_thread_create (void *ctx,
+                       notmuch_database_t *notmuch,
+                       unsigned int seed_doc_id,
+                       notmuch_doc_id_set_t *match_set,
+                       notmuch_string_list_t *excluded_terms,
+                       notmuch_exclude_t omit_exclude,
+                       notmuch_sort_t sort);
 
 NOTMUCH_END_DECLS
 
+#ifdef __cplusplus
+/* Implicit typecast from 'void *' to 'T *' is okay in C, but not in
+ * C++. In talloc_steal, an explicit cast is provided for type safety
+ * in some GCC versions. Otherwise, a cast is required. Provide a
+ * template function for this to maintain type safety, and redefine
+ * talloc_steal to use it.
+ */
+#if !(__GNUC__ >= 3)
+template <class T> T *
+_notmuch_talloc_steal (const void *new_ctx, const T *ptr)
+{
+    return static_cast<T *> (talloc_steal (new_ctx, ptr));
+}
+#undef talloc_steal
+#define talloc_steal _notmuch_talloc_steal
+#endif
+#endif
+
+#pragma GCC visibility pop
+
 #endif