NeoMutt  2021-02-05-89-gabe350
Teaching an old dog new tricks
DOXYGEN
db.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <limits.h>
31 #include <notmuch.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <sys/stat.h>
35 #include <time.h>
36 #include "private.h"
37 #include "mutt/lib.h"
38 #include "email/lib.h"
39 #include "core/lib.h"
40 #include "lib.h"
41 #include "adata.h"
42 #include "mdata.h"
43 #include "mutt_globals.h"
44 #include "mutt_logging.h"
45 
55 const char *nm_db_get_filename(struct Mailbox *m)
56 {
57  struct NmMboxData *mdata = nm_mdata_get(m);
58  char *db_filename = NULL;
59 
60  if (mdata && mdata->db_url && mdata->db_url->path)
61  db_filename = mdata->db_url->path;
62  else
63  db_filename = C_NmDefaultUrl;
64 
65  if (!db_filename && !C_Folder)
66  return NULL;
67 
68  if (!db_filename)
69  db_filename = C_Folder;
70 
71  if (nm_path_probe(db_filename, NULL) == MUTT_NOTMUCH)
72  db_filename += NmUrlProtocolLen;
73 
74  mutt_debug(LL_DEBUG2, "nm: db filename '%s'\n", db_filename);
75  return db_filename;
76 }
77 
85 notmuch_database_t *nm_db_do_open(const char *filename, bool writable, bool verbose)
86 {
87  notmuch_database_t *db = NULL;
88  int ct = 0;
89  notmuch_status_t st = NOTMUCH_STATUS_SUCCESS;
90 #if LIBNOTMUCH_CHECK_VERSION(4, 2, 0)
91  char *msg = NULL;
92 #endif
93 
94  mutt_debug(LL_DEBUG1, "nm: db open '%s' %s (timeout %d)\n", filename,
95  writable ? "[WRITE]" : "[READ]", C_NmOpenTimeout);
96 
97  const notmuch_database_mode_t mode =
98  writable ? NOTMUCH_DATABASE_MODE_READ_WRITE : NOTMUCH_DATABASE_MODE_READ_ONLY;
99 
100  do
101  {
102 #if LIBNOTMUCH_CHECK_VERSION(4, 2, 0)
103  st = notmuch_database_open_verbose(filename, mode, &db, &msg);
104 #elif defined(NOTMUCH_API_3)
105  st = notmuch_database_open(filename, mode, &db);
106 #else
107  db = notmuch_database_open(filename, mode);
108 #endif
109  if ((st == NOTMUCH_STATUS_FILE_ERROR) || db || !C_NmOpenTimeout || ((ct / 2) > C_NmOpenTimeout))
110  break;
111 
112  if (verbose && ct && ((ct % 2) == 0))
113  mutt_error(_("Waiting for notmuch DB... (%d sec)"), ct / 2);
114  mutt_date_sleep_ms(500000); /* Half a second */
115  ct++;
116  } while (true);
117 
118  if (verbose)
119  {
120  if (!db)
121  {
122 #if LIBNOTMUCH_CHECK_VERSION(4, 2, 0)
123  if (msg)
124  {
125  mutt_error(msg);
126  FREE(&msg);
127  }
128  else
129 #endif
130  {
131  mutt_error(_("Can't open notmuch database: %s: %s"), filename,
132  st ? notmuch_status_to_string(st) : _("unknown reason"));
133  }
134  }
135  else if (ct > 1)
136  {
138  }
139  }
140  return db;
141 }
142 
149 notmuch_database_t *nm_db_get(struct Mailbox *m, bool writable)
150 {
151  struct NmAccountData *adata = nm_adata_get(m);
152 
153  if (!adata)
154  return NULL;
155 
156  // Use an existing open db if we have one.
157  if (adata->db)
158  return adata->db;
159 
160  const char *db_filename = nm_db_get_filename(m);
161  if (db_filename)
162  adata->db = nm_db_do_open(db_filename, writable, true);
163 
164  return adata->db;
165 }
166 
173 int nm_db_release(struct Mailbox *m)
174 {
175  struct NmAccountData *adata = nm_adata_get(m);
176  if (!adata || !adata->db || nm_db_is_longrun(m))
177  return -1;
178 
179  mutt_debug(LL_DEBUG1, "nm: db close\n");
180  nm_db_free(adata->db);
181  adata->db = NULL;
182  adata->longrun = false;
183  return 0;
184 }
185 
190 void nm_db_free(notmuch_database_t *db)
191 {
192 #ifdef NOTMUCH_API_3
193  notmuch_database_destroy(db);
194 #else
195  notmuch_database_close(db);
196 #endif
197 }
198 
207 {
208  struct NmAccountData *adata = nm_adata_get(m);
209  if (!adata || !adata->db)
210  return -1;
211 
212  if (adata->trans)
213  return 0;
214 
215  mutt_debug(LL_DEBUG2, "nm: db trans start\n");
216  if (notmuch_database_begin_atomic(adata->db))
217  return -1;
218  adata->trans = true;
219  return 1;
220 }
221 
228 int nm_db_trans_end(struct Mailbox *m)
229 {
230  struct NmAccountData *adata = nm_adata_get(m);
231  if (!adata || !adata->db)
232  return -1;
233 
234  if (!adata->trans)
235  return 0;
236 
237  mutt_debug(LL_DEBUG2, "nm: db trans end\n");
238  adata->trans = false;
239  if (notmuch_database_end_atomic(adata->db))
240  return -1;
241 
242  return 0;
243 }
244 
255 int nm_db_get_mtime(struct Mailbox *m, time_t *mtime)
256 {
257  if (!m || !mtime)
258  return -1;
259 
260  char path[PATH_MAX];
261  snprintf(path, sizeof(path), "%s/.notmuch/xapian", nm_db_get_filename(m));
262  mutt_debug(LL_DEBUG2, "nm: checking '%s' mtime\n", path);
263 
264  struct stat st;
265  if (stat(path, &st) != 0)
266  return -1;
267 
268  *mtime = st.st_mtime;
269  return 0;
270 }
271 
277 bool nm_db_is_longrun(struct Mailbox *m)
278 {
279  struct NmAccountData *adata = nm_adata_get(m);
280  if (!adata)
281  return false;
282 
283  return adata->longrun;
284 }
285 
291 void nm_db_longrun_init(struct Mailbox *m, bool writable)
292 {
293  struct NmAccountData *adata = nm_adata_get(m);
294 
295  if (!(adata && nm_db_get(m, writable)))
296  return;
297 
298  adata->longrun = true;
299  mutt_debug(LL_DEBUG2, "nm: long run initialized\n");
300 }
301 
307 {
308  struct NmAccountData *adata = nm_adata_get(m);
309 
310  if (adata)
311  {
312  adata->longrun = false; /* to force nm_db_release() released DB */
313  if (nm_db_release(m) == 0)
314  mutt_debug(LL_DEBUG2, "nm: long run deinitialized\n");
315  else
316  adata->longrun = true;
317  }
318 }
319 
324 void nm_db_debug_check(struct Mailbox *m)
325 {
326  struct NmAccountData *adata = nm_adata_get(m);
327  if (!adata || !adata->db)
328  return;
329 
330  mutt_debug(LL_DEBUG1, "nm: ERROR: db is open, closing\n");
331  nm_db_release(m);
332 }
nm_db_get_mtime
int nm_db_get_mtime(struct Mailbox *m, time_t *mtime)
Get the database modification time.
Definition: db.c:255
nm_db_trans_begin
int nm_db_trans_begin(struct Mailbox *m)
Start a Notmuch database transaction.
Definition: db.c:206
_
#define _(a)
Definition: message.h:28
Mailbox
A mailbox.
Definition: mailbox.h:81
private.h
nm_db_get_filename
const char * nm_db_get_filename(struct Mailbox *m)
Get the filename of the Notmuch database.
Definition: db.c:55
NmAccountData::db
notmuch_database_t * db
Definition: adata.h:36
mutt_globals.h
LL_DEBUG1
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
FREE
#define FREE(x)
Definition: memory.h:40
nm_db_do_open
notmuch_database_t * nm_db_do_open(const char *filename, bool writable, bool verbose)
Open a Notmuch database.
Definition: db.c:85
PATH_MAX
#define PATH_MAX
Definition: mutt.h:44
nm_mdata_get
struct NmMboxData * nm_mdata_get(struct Mailbox *m)
Get the Notmuch Mailbox data.
Definition: mdata.c:89
nm_adata_get
struct NmAccountData * nm_adata_get(struct Mailbox *m)
Get the Notmuch Account data.
Definition: adata.c:69
mdata.h
Mailbox::mdata
void * mdata
Driver specific data.
Definition: mailbox.h:136
lib.h
C_Folder
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
lib.h
mutt_clear_error
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
adata.h
nm_db_longrun_init
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:291
NmAccountData
Notmuch-specific Account data -.
Definition: adata.h:34
MUTT_NOTMUCH
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:54
mutt_date_sleep_ms
void mutt_date_sleep_ms(size_t ms)
Sleep for milliseconds.
Definition: date.c:693
nm_path_probe
enum MailboxType nm_path_probe(const char *path, const struct stat *st)
Is this a Notmuch Mailbox? - Implements MxOps::path_probe()
Definition: notmuch.c:2522
C_NmOpenTimeout
int C_NmOpenTimeout
Config: (notmuch) Database timeout.
Definition: config.c:41
nm_db_longrun_done
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:306
mutt_debug
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
nm_db_trans_end
int nm_db_trans_end(struct Mailbox *m)
End a database transaction.
Definition: db.c:228
Mailbox::verbose
bool verbose
Display status messages?
Definition: mailbox.h:118
nm_db_release
int nm_db_release(struct Mailbox *m)
Close the Notmuch database.
Definition: db.c:173
nm_db_debug_check
void nm_db_debug_check(struct Mailbox *m)
Check if the database is open.
Definition: db.c:324
mutt_logging.h
nm_db_free
void nm_db_free(notmuch_database_t *db)
decoupled way to close a Notmuch database
Definition: db.c:190
lib.h
nm_db_get
notmuch_database_t * nm_db_get(struct Mailbox *m, bool writable)
Get the Notmuch database.
Definition: db.c:149
Account::adata
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
NmUrlProtocolLen
const int NmUrlProtocolLen
Definition: notmuch.c:86
C_NmDefaultUrl
char * C_NmDefaultUrl
Config: (notmuch) Path to the Notmuch database.
Definition: config.c:38
NmMboxData
Notmuch-specific Mailbox data -.
Definition: mdata.h:35
nm_db_is_longrun
bool nm_db_is_longrun(struct Mailbox *m)
Is Notmuch in the middle of a long-running transaction.
Definition: db.c:277
LL_DEBUG2
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
mutt_error
#define mutt_error(...)
Definition: logging.h:84