NeoMutt  2020-08-21-74-g346364
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 "mutt_globals.h"
42 #include "mutt_logging.h"
43 
53 const char *nm_db_get_filename(struct Mailbox *m)
54 {
55  struct NmMboxData *mdata = nm_mdata_get(m);
56  char *db_filename = NULL;
57 
58  if (mdata && mdata->db_url && mdata->db_url->path)
59  db_filename = mdata->db_url->path;
60  else
61  db_filename = C_NmDefaultUrl;
62 
63  if (!db_filename && !C_Folder)
64  return NULL;
65 
66  if (!db_filename)
67  db_filename = C_Folder;
68 
69  if (nm_path_probe(db_filename, NULL) == MUTT_NOTMUCH)
70  db_filename += NmUrlProtocolLen;
71 
72  mutt_debug(LL_DEBUG2, "nm: db filename '%s'\n", db_filename);
73  return db_filename;
74 }
75 
83 notmuch_database_t *nm_db_do_open(const char *filename, bool writable, bool verbose)
84 {
85  notmuch_database_t *db = NULL;
86  int ct = 0;
87  notmuch_status_t st = NOTMUCH_STATUS_SUCCESS;
88 #if LIBNOTMUCH_CHECK_VERSION(4, 2, 0)
89  char *msg = NULL;
90 #endif
91 
92  mutt_debug(LL_DEBUG1, "nm: db open '%s' %s (timeout %d)\n", filename,
93  writable ? "[WRITE]" : "[READ]", C_NmOpenTimeout);
94 
95  const notmuch_database_mode_t mode =
96  writable ? NOTMUCH_DATABASE_MODE_READ_WRITE : NOTMUCH_DATABASE_MODE_READ_ONLY;
97 
98  do
99  {
100 #if LIBNOTMUCH_CHECK_VERSION(4, 2, 0)
101  st = notmuch_database_open_verbose(filename, mode, &db, &msg);
102 #elif defined(NOTMUCH_API_3)
103  st = notmuch_database_open(filename, mode, &db);
104 #else
105  db = notmuch_database_open(filename, mode);
106 #endif
107  if ((st == NOTMUCH_STATUS_FILE_ERROR) || db || !C_NmOpenTimeout || ((ct / 2) > C_NmOpenTimeout))
108  break;
109 
110  if (verbose && ct && ((ct % 2) == 0))
111  mutt_error(_("Waiting for notmuch DB... (%d sec)"), ct / 2);
112  mutt_date_sleep_ms(500000); /* Half a second */
113  ct++;
114  } while (true);
115 
116  if (verbose)
117  {
118  if (!db)
119  {
120 #if LIBNOTMUCH_CHECK_VERSION(4, 2, 0)
121  if (msg)
122  {
123  mutt_error(msg);
124  FREE(&msg);
125  }
126  else
127 #endif
128  {
129  mutt_error(_("Can't open notmuch database: %s: %s"), filename,
130  st ? notmuch_status_to_string(st) : _("unknown reason"));
131  }
132  }
133  else if (ct > 1)
134  {
136  }
137  }
138  return db;
139 }
140 
147 notmuch_database_t *nm_db_get(struct Mailbox *m, bool writable)
148 {
149  struct NmAccountData *adata = nm_adata_get(m);
150 
151  if (!adata)
152  return NULL;
153 
154  // Use an existing open db if we have one.
155  if (adata->db)
156  return adata->db;
157 
158  const char *db_filename = nm_db_get_filename(m);
159  if (db_filename)
160  adata->db = nm_db_do_open(db_filename, writable, true);
161 
162  return adata->db;
163 }
164 
171 int nm_db_release(struct Mailbox *m)
172 {
173  struct NmAccountData *adata = nm_adata_get(m);
174  if (!adata || !adata->db || nm_db_is_longrun(m))
175  return -1;
176 
177  mutt_debug(LL_DEBUG1, "nm: db close\n");
178  nm_db_free(adata->db);
179  adata->db = NULL;
180  adata->longrun = false;
181  return 0;
182 }
183 
188 void nm_db_free(notmuch_database_t *db)
189 {
190 #ifdef NOTMUCH_API_3
191  notmuch_database_destroy(db);
192 #else
193  notmuch_database_close(db);
194 #endif
195 }
196 
205 {
206  struct NmAccountData *adata = nm_adata_get(m);
207  if (!adata || !adata->db)
208  return -1;
209 
210  if (adata->trans)
211  return 0;
212 
213  mutt_debug(LL_DEBUG2, "nm: db trans start\n");
214  if (notmuch_database_begin_atomic(adata->db))
215  return -1;
216  adata->trans = true;
217  return 1;
218 }
219 
226 int nm_db_trans_end(struct Mailbox *m)
227 {
228  struct NmAccountData *adata = nm_adata_get(m);
229  if (!adata || !adata->db)
230  return -1;
231 
232  if (!adata->trans)
233  return 0;
234 
235  mutt_debug(LL_DEBUG2, "nm: db trans end\n");
236  adata->trans = false;
237  if (notmuch_database_end_atomic(adata->db))
238  return -1;
239 
240  return 0;
241 }
242 
253 int nm_db_get_mtime(struct Mailbox *m, time_t *mtime)
254 {
255  if (!m || !mtime)
256  return -1;
257 
258  char path[PATH_MAX];
259  snprintf(path, sizeof(path), "%s/.notmuch/xapian", nm_db_get_filename(m));
260  mutt_debug(LL_DEBUG2, "nm: checking '%s' mtime\n", path);
261 
262  struct stat st;
263  if (stat(path, &st) != 0)
264  return -1;
265 
266  *mtime = st.st_mtime;
267  return 0;
268 }
269 
275 bool nm_db_is_longrun(struct Mailbox *m)
276 {
277  struct NmAccountData *adata = nm_adata_get(m);
278  if (!adata)
279  return false;
280 
281  return adata->longrun;
282 }
283 
289 void nm_db_longrun_init(struct Mailbox *m, bool writable)
290 {
291  struct NmAccountData *adata = nm_adata_get(m);
292 
293  if (!(adata && nm_db_get(m, writable)))
294  return;
295 
296  adata->longrun = true;
297  mutt_debug(LL_DEBUG2, "nm: long run initialized\n");
298 }
299 
305 {
306  struct NmAccountData *adata = nm_adata_get(m);
307 
308  if (adata)
309  {
310  adata->longrun = false; /* to force nm_db_release() released DB */
311  if (nm_db_release(m) == 0)
312  mutt_debug(LL_DEBUG2, "nm: long run deinitialized\n");
313  else
314  adata->longrun = true;
315  }
316 }
317 
322 void nm_db_debug_check(struct Mailbox *m)
323 {
324  struct NmAccountData *adata = nm_adata_get(m);
325  if (!adata || !adata->db)
326  return;
327 
328  mutt_debug(LL_DEBUG1, "nm: ERROR: db is open, closing\n");
329  nm_db_release(m);
330 }
notmuch_database_t * nm_db_do_open(const char *filename, bool writable, bool verbose)
Open a Notmuch database.
Definition: db.c:83
int C_NmOpenTimeout
Config: (notmuch) Database timeout.
Definition: config.c:41
int nm_db_get_mtime(struct Mailbox *m, time_t *mtime)
Get the database modification time.
Definition: db.c:253
Structs that make up an email.
NeoMutt Logging.
#define _(a)
Definition: message.h:28
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:289
bool longrun
A long-lived action is in progress.
Definition: private.h:51
int nm_db_trans_begin(struct Mailbox *m)
Start a Notmuch database transaction.
Definition: db.c:204
notmuch_database_t * nm_db_get(struct Mailbox *m, bool writable)
Get the Notmuch database.
Definition: db.c:147
notmuch_database_t * db
Definition: private.h:50
bool nm_db_is_longrun(struct Mailbox *m)
Is Notmuch in the middle of a long-running transaction.
Definition: db.c:275
struct NmAccountData * nm_adata_get(struct Mailbox *m)
Get the Notmuch Account data.
Definition: notmuch.c:152
Log at debug level 2.
Definition: logging.h:41
Notmuch-specific Mailbox data -.
Definition: private.h:69
char * C_NmDefaultUrl
Config: (notmuch) Path to the Notmuch database.
Definition: config.c:38
Convenience wrapper for the core headers.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
void * mdata
Driver specific data.
Definition: mailbox.h:136
void nm_db_debug_check(struct Mailbox *m)
Check if the database is open.
Definition: db.c:322
int nm_db_trans_end(struct Mailbox *m)
End a database transaction.
Definition: db.c:226
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:44
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
void nm_db_free(notmuch_database_t *db)
decoupled way to close a Notmuch database
Definition: db.c:188
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:304
bool verbose
Display status messages?
Definition: mailbox.h:118
bool trans
Atomic transaction in progress.
Definition: private.h:52
enum MailboxType nm_path_probe(const char *path, const struct stat *st)
Is this a Notmuch Mailbox? - Implements MxOps::path_probe()
Definition: notmuch.c:2594
struct Url * db_url
Parsed view url of the Notmuch database.
Definition: private.h:71
char * path
Path.
Definition: url.h:73
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
struct NmMboxData * nm_mdata_get(struct Mailbox *m)
Get the Notmuch Mailbox data.
Definition: notmuch.c:219
Log at debug level 1.
Definition: logging.h:40
int nm_db_release(struct Mailbox *m)
Close the Notmuch database.
Definition: db.c:171
#define mutt_error(...)
Definition: logging.h:84
#define FREE(x)
Definition: memory.h:40
const int NmUrlProtocolLen
Definition: notmuch.c:74
Hundreds of global variables to back the user variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Convenience wrapper for the library headers.
Notmuch private types.
void mutt_date_sleep_ms(size_t ms)
Sleep for milliseconds.
Definition: date.c:693
Notmuch-specific Account data -.
Definition: private.h:48
const char * nm_db_get_filename(struct Mailbox *m)
Get the filename of the Notmuch database.
Definition: db.c:53