NeoMutt  2021-10-29-225-gb9986f
Teaching an old dog new tricks
DOXYGEN
notmuch.c File Reference

Notmuch virtual mailbox type. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <notmuch.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "lib.h"
#include "hcache/lib.h"
#include "index/lib.h"
#include "maildir/lib.h"
#include "progress/lib.h"
#include "adata.h"
#include "command_parse.h"
#include "edata.h"
#include "maildir/edata.h"
#include "mdata.h"
#include "mutt_commands.h"
#include "mutt_globals.h"
#include "mutt_thread.h"
#include "mx.h"
#include "protos.h"
#include "query.h"
#include "tag.h"
#include <libintl.h>
+ Include dependency graph for notmuch.c:

Go to the source code of this file.

Functions

void nm_init (void)
 Setup feature commands. More...
 
static struct HeaderCachenm_hcache_open (struct Mailbox *m)
 Open a header cache. More...
 
static void nm_hcache_close (struct HeaderCache *h)
 Close the header cache. More...
 
static char * nm_get_default_url (void)
 Create a Mailbox with default Notmuch settings. More...
 
static struct NmMboxDatanm_get_default_data (void)
 Create a Mailbox with default Notmuch settings. More...
 
static int init_mailbox (struct Mailbox *m)
 Add Notmuch data to the Mailbox. More...
 
static char * email_get_id (struct Email *e)
 Get the unique Notmuch Id. More...
 
static char * email_get_fullpath (struct Email *e, char *buf, size_t buflen)
 Get the full path of an email. More...
 
static void query_window_reset (void)
 Restore vfolder's search window to its original position. More...
 
static bool windowed_query_from_query (const char *query, char *buf, size_t buflen)
 Transforms a vfolder search query into a windowed one. More...
 
static char * get_query_string (struct NmMboxData *mdata, bool window)
 Builds the notmuch vfolder search string. More...
 
static int get_limit (struct NmMboxData *mdata)
 Get the database limit. More...
 
static void apply_exclude_tags (notmuch_query_t *query)
 Exclude the configured tags. More...
 
static notmuch_query_t * get_query (struct Mailbox *m, bool writable)
 Create a new query. More...
 
static int update_email_tags (struct Email *e, notmuch_message_t *msg)
 Update the Email's tags from Notmuch. More...
 
static int update_message_path (struct Email *e, const char *path)
 Set the path for a message. More...
 
static char * get_folder_from_path (const char *path)
 Find an email's folder from its path. More...
 
static char * nm2mutt_message_id (const char *id)
 Converts notmuch message Id to neomutt message Id. More...
 
static int init_email (struct Email *e, const char *path, notmuch_message_t *msg)
 Set up an email's Notmuch data. More...
 
static const char * get_message_last_filename (notmuch_message_t *msg)
 Get a message's last filename. More...
 
static void progress_setup (struct Mailbox *m)
 Set up the Progress Bar. More...
 
static void nm_progress_update (struct Mailbox *m)
 Update the progress counter. More...
 
static struct Emailget_mutt_email (struct Mailbox *m, notmuch_message_t *msg)
 Get the Email of a Notmuch message. More...
 
static void append_message (struct HeaderCache *h, struct Mailbox *m, notmuch_message_t *msg, bool dedup)
 Associate a message. More...
 
static void append_replies (struct HeaderCache *h, struct Mailbox *m, notmuch_query_t *q, notmuch_message_t *top, bool dedup)
 Add all the replies to a given messages into the display. More...
 
static void append_thread (struct HeaderCache *h, struct Mailbox *m, notmuch_query_t *q, notmuch_thread_t *thread, bool dedup)
 Add each top level reply in the thread. More...
 
static notmuch_messages_t * get_messages (notmuch_query_t *query)
 Load messages for a query. More...
 
static bool read_mesgs_query (struct Mailbox *m, notmuch_query_t *q, bool dedup)
 Search for matching messages. More...
 
static notmuch_threads_t * get_threads (notmuch_query_t *query)
 Load threads for a query. More...
 
static bool read_threads_query (struct Mailbox *m, notmuch_query_t *q, bool dedup, int limit)
 Perform a query with threads. More...
 
static notmuch_message_t * get_nm_message (notmuch_database_t *db, struct Email *e)
 Find a Notmuch message. More...
 
static bool nm_message_has_tag (notmuch_message_t *msg, char *tag)
 Does a message have this tag? More...
 
static void sync_email_path_with_nm (struct Email *e, notmuch_message_t *msg)
 Synchronize Neomutt's Email path with notmuch. More...
 
static int update_tags (notmuch_message_t *msg, const char *tag_str)
 Update the tags on a message. More...
 
static int update_email_flags (struct Mailbox *m, struct Email *e, const char *tag_str)
 Update the Email's flags. More...
 
static int rename_maildir_filename (const char *old, char *buf, size_t buflen, struct Email *e)
 Rename a Maildir file. More...
 
static int remove_filename (struct Mailbox *m, const char *path)
 Delete a file. More...
 
static int rename_filename (struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
 Rename the file. More...
 
static unsigned int count_query (notmuch_database_t *db, const char *qstr, int limit)
 Count the results of a query. More...
 
char * nm_email_get_folder (struct Email *e)
 Get the folder for a Email. More...
 
char * nm_email_get_folder_rel_db (struct Mailbox *m, struct Email *e)
 Get the folder for a Email from the same level as the notmuch database. More...
 
int nm_read_entire_thread (struct Mailbox *m, struct Email *e)
 Get the entire thread of an email. More...
 
char * nm_url_from_query (struct Mailbox *m, char *buf, size_t buflen)
 Turn a query into a URL. More...
 
bool nm_query_window_available (void)
 Are windowed queries enabled for use? More...
 
void nm_query_window_forward (void)
 Function to move the current search window forward in time. More...
 
void nm_query_window_backward (void)
 Function to move the current search window backward in time. More...
 
void nm_query_window_reset (void)
 Resets the vfolder window position to the present. More...
 
bool nm_message_is_still_queried (struct Mailbox *m, struct Email *e)
 Is a message still visible in the query? More...
 
int nm_update_filename (struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
 Change the filename. More...
 
static enum MxStatus nm_mbox_check_stats (struct Mailbox *m, uint8_t flags)
 Check the Mailbox statistics - Implements MxOps::mbox_check_stats() -. More...
 
static struct Mailboxget_default_mailbox (void)
 Get Mailbox for notmuch without any parameters. More...
 
int nm_record_message (struct Mailbox *m, char *path, struct Email *e)
 Add a message to the Notmuch database. More...
 
int nm_get_all_tags (struct Mailbox *m, char **tag_list, int *tag_count)
 Fill a list with all notmuch tags. More...
 
static bool nm_ac_owns_path (struct Account *a, const char *path)
 Check whether an Account owns a Mailbox path - Implements MxOps::ac_owns_path() -. More...
 
static bool nm_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -. More...
 
static enum MxOpenReturns nm_mbox_open (struct Mailbox *m)
 Open a Mailbox - Implements MxOps::mbox_open() -. More...
 
static enum MxStatus nm_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -. More...
 
static enum MxStatus nm_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
static enum MxStatus nm_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -. More...
 
static bool nm_msg_open (struct Mailbox *m, struct Message *msg, int msgno)
 Open an email message in a Mailbox - Implements MxOps::msg_open() -. More...
 
static int nm_msg_commit (struct Mailbox *m, struct Message *msg)
 Save changes to an email - Implements MxOps::msg_commit() -. More...
 
static int nm_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -. More...
 
static int nm_tags_edit (struct Mailbox *m, const char *tags, struct Buffer *buf)
 Prompt and validate new messages tags - Implements MxOps::tags_edit() -. More...
 
static int nm_tags_commit (struct Mailbox *m, struct Email *e, const char *buf)
 Save the tags to a message - Implements MxOps::tags_commit() -. More...
 
enum MailboxType nm_path_probe (const char *path, const struct stat *st)
 Is this a Notmuch Mailbox? - Implements MxOps::path_probe() -. More...
 
static int nm_path_canon (char *buf, size_t buflen)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -. More...
 
static int nm_path_pretty (char *buf, size_t buflen, const char *folder)
 Abbreviate a Mailbox path - Implements MxOps::path_pretty() -. More...
 
static int nm_path_parent (char *buf, size_t buflen)
 Find the parent of a Mailbox path - Implements MxOps::path_parent() -. More...
 

Variables

static const struct Command nm_commands []
 
const char NmUrlProtocol [] = "notmuch://"
 
const int NmUrlProtocolLen = sizeof(NmUrlProtocol) - 1
 
struct MxOps MxNotmuchOps
 Notmuch Mailbox - Implements MxOps -. More...
 

Detailed Description

Notmuch virtual mailbox type.

Authors
  • Karel Zak
  • Richard Russon
  • Kevin Velghe
  • Bernard 'Guyzmo' Pratz

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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/.

Definition in file notmuch.c.

Function Documentation

◆ nm_init()

void nm_init ( void  )

Setup feature commands.

Definition at line 99 of file notmuch.c.

100 {
102 }
#define COMMANDS_REGISTER(cmds)
Definition: mutt_commands.h:47
static const struct Command nm_commands[]
Definition: notmuch.c:86
+ Here is the caller graph for this function:

◆ nm_hcache_open()

static struct HeaderCache* nm_hcache_open ( struct Mailbox m)
static

Open a header cache.

Parameters
mMailbox
Return values
ptrHeader cache handle

Definition at line 109 of file notmuch.c.

110 {
111 #ifdef USE_HCACHE
112  const char *const c_header_cache =
113  cs_subset_path(NeoMutt->sub, "header_cache");
114  return mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
115 #else
116  return NULL;
117 #endif
118 }
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:335
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:215
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_hcache_close()

static void nm_hcache_close ( struct HeaderCache h)
static

Close the header cache.

Parameters
hHeader cache handle

Definition at line 124 of file notmuch.c.

125 {
126 #ifdef USE_HCACHE
128 #endif
129 }
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:438
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_get_default_url()

static char* nm_get_default_url ( void  )
static

Create a Mailbox with default Notmuch settings.

Return values
ptrMailbox with default Notmuch settings
NULLError, it's impossible to create an NmMboxData

Definition at line 136 of file notmuch.c.

137 {
138  // path to DB + query + url "decoration"
139  size_t len = PATH_MAX + 1024 + 32;
140  char *url = mutt_mem_malloc(len);
141 
142  // Try to use `$nm_default_url` or `$folder`.
143  // If neither are set, it is impossible to create a Notmuch URL.
144  const char *const c_nm_default_url =
145  cs_subset_string(NeoMutt->sub, "nm_default_url");
146  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
147  if (c_nm_default_url)
148  snprintf(url, len, "%s", c_nm_default_url);
149  else if (c_folder)
150  snprintf(url, len, "notmuch://%s", c_folder);
151  else
152  {
153  FREE(&url);
154  return NULL;
155  }
156 
157  return url;
158 }
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:40
#define PATH_MAX
Definition: mutt.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_get_default_data()

static struct NmMboxData* nm_get_default_data ( void  )
static

Create a Mailbox with default Notmuch settings.

Return values
ptrMailbox with default Notmuch settings
NULLError, it's impossible to create an NmMboxData

Definition at line 165 of file notmuch.c.

166 {
167  // path to DB + query + url "decoration"
168  char *url = nm_get_default_url();
169  if (!url)
170  return NULL;
171 
172  struct NmMboxData *default_data = nm_mdata_new(url);
173  FREE(&url);
174 
175  return default_data;
176 }
struct NmMboxData * nm_mdata_new(const char *url)
Create a new NmMboxData object from a query.
Definition: mdata.c:69
static char * nm_get_default_url(void)
Create a Mailbox with default Notmuch settings.
Definition: notmuch.c:136
Notmuch-specific Mailbox data -.
Definition: mdata.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init_mailbox()

static int init_mailbox ( struct Mailbox m)
static

Add Notmuch data to the Mailbox.

Parameters
mMailbox
Return values
0Success
-1Error Bad format

Create a new NmMboxData struct and add it Mailbox::data. Notmuch-specific data will be stored in this struct. This struct can be freed using nm_mdata_free().

Definition at line 188 of file notmuch.c.

189 {
190  if (!m || (m->type != MUTT_NOTMUCH))
191  return -1;
192 
193  if (m->mdata)
194  return 0;
195 
197  if (!m->mdata)
198  return -1;
199 
201  return 0;
202 }
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:54
void nm_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:46
void(* mdata_free)(void **ptr)
Free the private data attached to the Mailbox.
Definition: mailbox.h:146
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
void * mdata
Driver specific data.
Definition: mailbox.h:136
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ email_get_id()

static char* email_get_id ( struct Email e)
static

Get the unique Notmuch Id.

Parameters
eEmail
Return values
ptrID string
NULLError

Definition at line 210 of file notmuch.c.

211 {
212  struct NmEmailData *edata = nm_edata_get(e);
213  if (!edata)
214  return NULL;
215 
216  return edata->virtual_id;
217 }
struct NmEmailData * nm_edata_get(struct Email *e)
Get the Notmuch Email data.
Definition: edata.c:72
void * edata
Driver-specific data.
Definition: email.h:72
Notmuch-specific Email data -.
Definition: edata.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ email_get_fullpath()

static char* email_get_fullpath ( struct Email e,
char *  buf,
size_t  buflen 
)
static

Get the full path of an email.

Parameters
eEmail
bufBuffer for the path
buflenLength of the buffer
Return values
ptrPath string

Definition at line 226 of file notmuch.c.

227 {
228  snprintf(buf, buflen, "%s/%s", nm_email_get_folder(e), e->path);
229  return buf;
230 }
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1463
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_window_reset()

static void query_window_reset ( void  )
static

Restore vfolder's search window to its original position.

After moving a vfolder search window backward and forward, calling this function will reset the search position to its original value, setting to 0 the user settable variable:

nm_query_window_current_position

Definition at line 241 of file notmuch.c.

242 {
243  mutt_debug(LL_DEBUG2, "entering\n");
244  cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position", 0, NULL);
245 }
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ windowed_query_from_query()

static bool windowed_query_from_query ( const char *  query,
char *  buf,
size_t  buflen 
)
static

Transforms a vfolder search query into a windowed one.

Parameters
[in]queryvfolder search string
[out]bufallocated string buffer to receive the modified search query
[in]buflenallocated maximum size of the buf string buffer
Return values
trueTransformed search query is available as a string in buf
falseSearch query shall not be transformed

Creates a date: search term window from the following user settings:

  • nm_query_window_enable (only required for nm_query_window_duration = 0)
  • nm_query_window_duration
  • nm_query_window_timebase
  • nm_query_window_current_position

The window won't be applied:

  • If the duration of the search query is set to 0 this function will be disabled unless a user explicitly enables windowed queries.
  • If the timebase is invalid, it will show an error message and do nothing.

If there's no search registered in nm_query_window_current_search or this is a new search, it will reset the window and do the search.

Definition at line 271 of file notmuch.c.

272 {
273  mutt_debug(LL_DEBUG2, "nm: %s\n", query);
274 
275  const bool c_nm_query_window_enable =
276  cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
277  const short c_nm_query_window_duration =
278  cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
279  const short c_nm_query_window_current_position =
280  cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
281  const char *const c_nm_query_window_current_search =
282  cs_subset_string(NeoMutt->sub, "nm_query_window_current_search");
283  const char *const c_nm_query_window_timebase =
284  cs_subset_string(NeoMutt->sub, "nm_query_window_timebase");
285  const char *const c_nm_query_window_or_terms =
286  cs_subset_string(NeoMutt->sub, "nm_query_window_or_terms");
287 
288  /* if the query has changed, reset the window position */
289  if (!c_nm_query_window_current_search ||
290  (strcmp(query, c_nm_query_window_current_search) != 0))
291  {
293  }
294 
296  buf, buflen, c_nm_query_window_enable, c_nm_query_window_duration,
297  c_nm_query_window_current_position, c_nm_query_window_current_search,
298  c_nm_query_window_timebase, c_nm_query_window_or_terms);
299 
300  switch (rc)
301  {
303  {
304  mutt_debug(LL_DEBUG2, "nm: %s -> %s\n", query, buf);
305  break;
306  }
308  {
310  return false;
311  }
313  {
314  mutt_message(
315  // L10N: The values 'hour', 'day', 'week', 'month', 'year' are literal.
316  // They should not be translated.
317  _("Invalid nm_query_window_timebase value (valid values are: "
318  "hour, day, week, month, year)"));
319  mutt_debug(LL_DEBUG2, "Invalid nm_query_window_timebase value\n");
320  return false;
321  }
322  }
323 
324  return true;
325 }
#define mutt_message(...)
Definition: logging.h:86
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define _(a)
Definition: message.h:28
static void query_window_reset(void)
Restore vfolder's search window to its original position.
Definition: notmuch.c:241
enum NmWindowQueryRc nm_windowed_query_from_query(char *buf, size_t buflen, const bool force_enable, const short duration, const short cur_pos, const char *cur_search, const char *timebase, const char *or_terms)
Windows buf with notmuch date: search term.
Definition: query.c:207
NmWindowQueryRc
Return codes for nm_windowed_query_from_query()
Definition: query.h:45
@ NM_WINDOW_QUERY_SUCCESS
Query was successful.
Definition: query.h:46
@ NM_WINDOW_QUERY_INVALID_DURATION
Invalid duration.
Definition: query.h:48
@ NM_WINDOW_QUERY_INVALID_TIMEBASE
Invalid timebase.
Definition: query.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_query_string()

static char* get_query_string ( struct NmMboxData mdata,
bool  window 
)
static

Builds the notmuch vfolder search string.

Parameters
mdataNotmuch Mailbox data
windowIf true enable application of the window on the search string
Return values
ptrString containing a notmuch search query
NULLNone can be generated

This function parses the internal representation of a search, and returns a search query string ready to be fed to the notmuch API, given the search is valid.

Note
The window parameter here is here to decide contextually whether we want to return a search query with window applied (for the actual search result in mailbox) or not (for the count in the sidebar). It is not aimed at enabling/disabling the feature.

Definition at line 343 of file notmuch.c.

344 {
345  mutt_debug(LL_DEBUG2, "nm: %s\n", window ? "true" : "false");
346 
347  if (!mdata)
348  return NULL;
349  if (mdata->db_query && !window)
350  return mdata->db_query;
351 
352  const char *const c_nm_query_type =
353  cs_subset_string(NeoMutt->sub, "nm_query_type");
354  mdata->query_type = nm_string_to_query_type(c_nm_query_type); /* user's default */
355 
356  struct UrlQuery *item = NULL;
357  STAILQ_FOREACH(item, &mdata->db_url->query_strings, entries)
358  {
359  if (!item->value || !item->name)
360  continue;
361 
362  if (strcmp(item->name, "limit") == 0)
363  {
364  if (!mutt_str_atoi_full(item->value, &mdata->db_limit))
365  {
366  mutt_error(_("failed to parse notmuch limit: %s"), item->value);
367  }
368  }
369  else if (strcmp(item->name, "type") == 0)
370  mdata->query_type = nm_string_to_query_type(item->value);
371  else if (strcmp(item->name, "query") == 0)
372  mutt_str_replace(&mdata->db_query, item->value);
373  }
374 
375  if (!mdata->db_query)
376  return NULL;
377 
378  if (window)
379  {
380  char buf[1024];
381  cs_subset_str_string_set(NeoMutt->sub, "nm_query_window_current_search",
382  mdata->db_query, NULL);
383 
384  /* if a date part is defined, do not apply windows (to avoid the risk of
385  * having a non-intersected date frame). A good improvement would be to
386  * accept if they intersect */
387  if (!strstr(mdata->db_query, "date:") &&
388  windowed_query_from_query(mdata->db_query, buf, sizeof(buf)))
389  {
390  mutt_str_replace(&mdata->db_query, buf);
391  }
392 
393  mutt_debug(LL_DEBUG2, "nm: query (windowed) '%s'\n", mdata->db_query);
394  }
395  else
396  mutt_debug(LL_DEBUG2, "nm: query '%s'\n", mdata->db_query);
397 
398  return mdata->db_query;
399 }
#define mutt_error(...)
Definition: logging.h:87
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:257
static bool windowed_query_from_query(const char *query, char *buf, size_t buflen)
Transforms a vfolder search query into a windowed one.
Definition: notmuch.c:271
enum NmQueryType nm_string_to_query_type(const char *str)
Lookup a query type.
Definition: query.c:110
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
struct Url * db_url
Parsed view url of the Notmuch database.
Definition: mdata.h:35
enum NmQueryType query_type
Messages or Threads.
Definition: mdata.h:38
int db_limit
Maximum number of results to return.
Definition: mdata.h:37
char * db_query
Previous query.
Definition: mdata.h:36
Parsed Query String.
Definition: url.h:58
char * name
Query name.
Definition: url.h:59
char * value
Query value.
Definition: url.h:60
struct UrlQueryList query_strings
List of query strings.
Definition: url.h:76
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:408
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_limit()

static int get_limit ( struct NmMboxData mdata)
static

Get the database limit.

Parameters
mdataNotmuch Mailbox data
Return values
numCurrent limit

Definition at line 406 of file notmuch.c.

407 {
408  return mdata ? mdata->db_limit : 0;
409 }
+ Here is the caller graph for this function:

◆ apply_exclude_tags()

static void apply_exclude_tags ( notmuch_query_t *  query)
static

Exclude the configured tags.

Parameters
queryNotmuch query

Definition at line 415 of file notmuch.c.

416 {
417  const char *const c_nm_exclude_tags =
418  cs_subset_string(NeoMutt->sub, "nm_exclude_tags");
419  if (!c_nm_exclude_tags || !query)
420  return;
421 
422  struct TagArray tags = nm_tag_str_to_tags(c_nm_exclude_tags);
423 
424  char **tag = NULL;
425  ARRAY_FOREACH(tag, &tags.tags)
426  {
427  mutt_debug(LL_DEBUG2, "nm: query exclude tag '%s'\n", *tag);
428  notmuch_query_add_tag_exclude(query, *tag);
429  }
430 
431  notmuch_query_set_omit_excluded(query, 1);
433 }
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:208
Array of Notmuch tags.
Definition: tag.h:37
struct Tags tags
Tags.
Definition: tag.h:38
void nm_tag_array_free(struct TagArray *tags)
Free all memory of a TagArray.
Definition: tag.c:39
struct TagArray nm_tag_str_to_tags(const char *tag_str)
Converts a comma and/or space-delimited string of tags into an array.
Definition: tag.c:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_query()

static notmuch_query_t* get_query ( struct Mailbox m,
bool  writable 
)
static

Create a new query.

Parameters
mMailbox
writableShould the query be updateable?
Return values
ptrNotmuch query
NULLError

Definition at line 442 of file notmuch.c.

443 {
444  struct NmMboxData *mdata = nm_mdata_get(m);
445  if (!mdata)
446  return NULL;
447 
448  notmuch_database_t *db = nm_db_get(m, writable);
449  const char *str = get_query_string(mdata, true);
450 
451  if (!db || !str)
452  goto err;
453 
454  notmuch_query_t *q = notmuch_query_create(db, str);
455  if (!q)
456  goto err;
457 
459  notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
460  mutt_debug(LL_DEBUG2, "nm: query successfully initialized (%s)\n", str);
461  return q;
462 err:
463  nm_db_release(m);
464  return NULL;
465 }
notmuch_database_t * nm_db_get(struct Mailbox *m, bool writable)
Get the Notmuch database.
Definition: db.c:174
int nm_db_release(struct Mailbox *m)
Close the Notmuch database.
Definition: db.c:198
struct NmMboxData * nm_mdata_get(struct Mailbox *m)
Get the Notmuch Mailbox data.
Definition: mdata.c:98
static void apply_exclude_tags(notmuch_query_t *query)
Exclude the configured tags.
Definition: notmuch.c:415
static char * get_query_string(struct NmMboxData *mdata, bool window)
Builds the notmuch vfolder search string.
Definition: notmuch.c:343
+ Here is the call graph for this function:

◆ update_email_tags()

static int update_email_tags ( struct Email e,
notmuch_message_t *  msg 
)
static

Update the Email's tags from Notmuch.

Parameters
eEmail
msgNotmuch message
Return values
0Success
1Tags unchanged

Definition at line 474 of file notmuch.c.

475 {
476  struct NmEmailData *edata = nm_edata_get(e);
477  char *new_tags = NULL;
478  char *old_tags = NULL;
479 
480  mutt_debug(LL_DEBUG2, "nm: tags update requested (%s)\n", edata->virtual_id);
481 
482  for (notmuch_tags_t *tags = notmuch_message_get_tags(msg);
483  tags && notmuch_tags_valid(tags); notmuch_tags_move_to_next(tags))
484  {
485  const char *t = notmuch_tags_get(tags);
486  if (!t || (*t == '\0'))
487  continue;
488 
489  mutt_str_append_item(&new_tags, t, ' ');
490  }
491 
492  old_tags = driver_tags_get(&e->tags);
493 
494  if (new_tags && old_tags && (strcmp(old_tags, new_tags) == 0))
495  {
496  FREE(&old_tags);
497  FREE(&new_tags);
498  mutt_debug(LL_DEBUG2, "nm: tags unchanged\n");
499  return 1;
500  }
501  FREE(&old_tags);
502 
503  /* new version */
504  driver_tags_replace(&e->tags, new_tags);
505  FREE(&new_tags);
506 
507  new_tags = driver_tags_get_transformed(&e->tags);
508  mutt_debug(LL_DEBUG2, "nm: new tags: '%s'\n", new_tags);
509  FREE(&new_tags);
510 
511  new_tags = driver_tags_get(&e->tags);
512  mutt_debug(LL_DEBUG2, "nm: new tag transforms: '%s'\n", new_tags);
513  FREE(&new_tags);
514 
515  return 0;
516 }
void mutt_str_append_item(char **str, const char *item, char sep)
Add string to another separated by sep.
Definition: string.c:277
struct TagList tags
For drivers that support server tagging.
Definition: email.h:70
bool driver_tags_replace(struct TagList *head, const char *tags)
Replace all tags.
Definition: tags.c:185
char * driver_tags_get_transformed(struct TagList *list)
Get transformed tags.
Definition: tags.c:132
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:144
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_message_path()

static int update_message_path ( struct Email e,
const char *  path 
)
static

Set the path for a message.

Parameters
eEmail
pathPath
Return values
0Success
1Failure

Definition at line 525 of file notmuch.c.

526 {
527  struct NmEmailData *edata = nm_edata_get(e);
528 
529  mutt_debug(LL_DEBUG2, "nm: path update requested path=%s, (%s)\n", path, edata->virtual_id);
530 
531  char *p = strrchr(path, '/');
532  if (p && ((p - path) > 3) &&
533  (mutt_strn_equal(p - 3, "cur", 3) || mutt_strn_equal(p - 3, "new", 3) ||
534  mutt_strn_equal(p - 3, "tmp", 3)))
535  {
536  edata->type = MUTT_MAILDIR;
537 
538  FREE(&e->path);
539  FREE(&edata->folder);
540 
541  p -= 3; /* skip subfolder (e.g. "new") */
542  if (cs_subset_bool(NeoMutt->sub, "mark_old"))
543  {
544  e->old = mutt_str_startswith(p, "cur");
545  }
546  e->path = mutt_str_dup(p);
547 
548  for (; (p > path) && (*(p - 1) == '/'); p--)
549  ; // do nothing
550 
551  edata->folder = mutt_strn_dup(path, p - path);
552 
553  mutt_debug(LL_DEBUG2, "nm: folder='%s', file='%s'\n", edata->folder, e->path);
554  return 0;
555  }
556 
557  return 1;
558 }
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:51
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:359
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:181
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:404
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:158
bool old
Email is seen, but unread.
Definition: email.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_folder_from_path()

static char* get_folder_from_path ( const char *  path)
static

Find an email's folder from its path.

Parameters
pathPath
Return values
ptrPath string
NULLError

Definition at line 566 of file notmuch.c.

567 {
568  char *p = strrchr(path, '/');
569 
570  if (p && ((p - path) > 3) &&
571  (mutt_strn_equal(p - 3, "cur", 3) || mutt_strn_equal(p - 3, "new", 3) ||
572  mutt_strn_equal(p - 3, "tmp", 3)))
573  {
574  p -= 3;
575  for (; (p > path) && (*(p - 1) == '/'); p--)
576  ; // do nothing
577 
578  return mutt_strn_dup(path, p - path);
579  }
580 
581  return NULL;
582 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm2mutt_message_id()

static char* nm2mutt_message_id ( const char *  id)
static

Converts notmuch message Id to neomutt message Id.

Parameters
idNotmuch ID to convert
Return values
ptrNeoMutt message ID

Caller must free the NeoMutt Message ID

Definition at line 591 of file notmuch.c.

592 {
593  size_t sz;
594  char *mid = NULL;
595 
596  if (!id)
597  return NULL;
598  sz = strlen(id) + 3;
599  mid = mutt_mem_malloc(sz);
600 
601  snprintf(mid, sz, "<%s>", id);
602  return mid;
603 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init_email()

static int init_email ( struct Email e,
const char *  path,
notmuch_message_t *  msg 
)
static

Set up an email's Notmuch data.

Parameters
eEmail
pathPath to email
msgNotmuch message
Return values
0Success
-1Failure

Definition at line 613 of file notmuch.c.

614 {
615  if (nm_edata_get(e))
616  return 0;
617 
618  struct NmEmailData *edata = nm_edata_new();
619  e->nm_edata = edata;
620 
621  /* Notmuch ensures that message Id exists (if not notmuch Notmuch will
622  * generate an ID), so it's more safe than use neomutt Email->env->id */
623  const char *id = notmuch_message_get_message_id(msg);
624  edata->virtual_id = mutt_str_dup(id);
625 
626  mutt_debug(LL_DEBUG2, "nm: [e=%p, edata=%p] (%s)\n", (void *) e, (void *) edata, id);
627 
628  char *nm_msg_id = nm2mutt_message_id(id);
629  if (!e->env->message_id)
630  {
631  e->env->message_id = nm_msg_id;
632  }
633  else if (!mutt_str_equal(e->env->message_id, nm_msg_id))
634  {
635  FREE(&e->env->message_id);
636  e->env->message_id = nm_msg_id;
637  }
638  else
639  {
640  FREE(&nm_msg_id);
641  }
642 
643  if (update_message_path(e, path) != 0)
644  return -1;
645 
646  update_email_tags(e, msg);
647 
648  return 0;
649 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:715
struct NmEmailData * nm_edata_new(void)
Create a new NmEmailData for an email.
Definition: edata.c:61
static char * nm2mutt_message_id(const char *id)
Converts notmuch message Id to neomutt message Id.
Definition: notmuch.c:591
static int update_message_path(struct Email *e, const char *path)
Set the path for a message.
Definition: notmuch.c:525
static int update_email_tags(struct Email *e, notmuch_message_t *msg)
Update the Email's tags from Notmuch.
Definition: notmuch.c:474
void * nm_edata
Notmuch private data.
Definition: email.h:93
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_message_last_filename()

static const char* get_message_last_filename ( notmuch_message_t *  msg)
static

Get a message's last filename.

Parameters
msgNotmuch message
Return values
ptrFilename
NULLError

Definition at line 657 of file notmuch.c.

658 {
659  const char *name = NULL;
660 
661  for (notmuch_filenames_t *ls = notmuch_message_get_filenames(msg);
662  ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
663  {
664  name = notmuch_filenames_get(ls);
665  }
666 
667  return name;
668 }
+ Here is the caller graph for this function:

◆ progress_setup()

static void progress_setup ( struct Mailbox m)
static

Set up the Progress Bar.

Parameters
mMailbox

Definition at line 674 of file notmuch.c.

675 {
676  if (!m->verbose)
677  return;
678 
679  struct NmMboxData *mdata = nm_mdata_get(m);
680  if (!mdata)
681  return;
682 
683  mdata->oldmsgcount = m->msg_count;
684  mdata->ignmsgcount = 0;
685  mdata->progress =
686  progress_new(_("Reading messages..."), MUTT_PROGRESS_READ, mdata->oldmsgcount);
687 }
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:46
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:252
int msg_count
Total number of messages.
Definition: mailbox.h:91
bool verbose
Display status messages?
Definition: mailbox.h:118
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_progress_update()

static void nm_progress_update ( struct Mailbox m)
static

Update the progress counter.

Parameters
mMailbox

Definition at line 693 of file notmuch.c.

694 {
695  struct NmMboxData *mdata = nm_mdata_get(m);
696 
697  if (!m->verbose || !mdata || !mdata->progress)
698  return;
699 
700  progress_update(mdata->progress, m->msg_count + mdata->ignmsgcount, -1);
701 }
void progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:177
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_mutt_email()

static struct Email* get_mutt_email ( struct Mailbox m,
notmuch_message_t *  msg 
)
static

Get the Email of a Notmuch message.

Parameters
mMailbox
msgNotmuch message
Return values
ptrEmail
NULLError

Definition at line 710 of file notmuch.c.

711 {
712  if (!m || !msg)
713  return NULL;
714 
715  const char *id = notmuch_message_get_message_id(msg);
716  if (!id)
717  return NULL;
718 
719  mutt_debug(LL_DEBUG2, "nm: neomutt email, id='%s'\n", id);
720 
721  if (!m->id_hash)
722  {
723  mutt_debug(LL_DEBUG2, "nm: init hash\n");
724  m->id_hash = mutt_make_id_hash(m);
725  if (!m->id_hash)
726  return NULL;
727  }
728 
729  char *mid = nm2mutt_message_id(id);
730  mutt_debug(LL_DEBUG2, "nm: neomutt id='%s'\n", mid);
731 
732  struct Email *e = mutt_hash_find(m->id_hash, mid);
733  FREE(&mid);
734  return e;
735 }
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:362
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for message-ids.
Definition: mutt_thread.c:1658
The envelope/body of an email.
Definition: email.h:37
struct HashTable * id_hash
Hash Table by msg id.
Definition: mailbox.h:127
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ append_message()

static void append_message ( struct HeaderCache h,
struct Mailbox m,
notmuch_message_t *  msg,
bool  dedup 
)
static

Associate a message.

Parameters
hHeader cache handle
mMailbox
msgNotmuch message
dedupDe-duplicate results

Definition at line 744 of file notmuch.c.

746 {
747  struct NmMboxData *mdata = nm_mdata_get(m);
748  if (!mdata)
749  return;
750 
751  char *newpath = NULL;
752  struct Email *e = NULL;
753 
754  /* deduplicate */
755  if (dedup && get_mutt_email(m, msg))
756  {
757  mdata->ignmsgcount++;
759  mutt_debug(LL_DEBUG2, "nm: ignore id=%s, already in the m\n",
760  notmuch_message_get_message_id(msg));
761  return;
762  }
763 
764  const char *path = get_message_last_filename(msg);
765  if (!path)
766  return;
767 
768  mutt_debug(LL_DEBUG2, "nm: appending message, i=%d, id=%s, path=%s\n",
769  m->msg_count, notmuch_message_get_message_id(msg), path);
770 
771  if (m->msg_count >= m->email_max)
772  {
773  mutt_debug(LL_DEBUG2, "nm: allocate mx memory\n");
774  mx_alloc_memory(m);
775  }
776 
777 #ifdef USE_HCACHE
779  if (!e)
780 #endif
781  {
782  if (access(path, F_OK) == 0)
783  {
784  /* We pass is_old=false as argument here, but e->old will be updated later
785  * by update_message_path() (called by init_email() below). */
786  e = maildir_parse_message(MUTT_MAILDIR, path, false, NULL);
787  }
788  else
789  {
790  /* maybe moved try find it... */
791  char *folder = get_folder_from_path(path);
792 
793  if (folder)
794  {
795  FILE *fp = maildir_open_find_message(folder, path, &newpath);
796  if (fp)
797  {
798  e = maildir_parse_stream(MUTT_MAILDIR, fp, newpath, false, NULL);
799  mutt_file_fclose(&fp);
800 
801  mutt_debug(LL_DEBUG1, "nm: not up-to-date: %s -> %s\n", path, newpath);
802  }
803  }
804  FREE(&folder);
805  }
806 
807  if (!e)
808  {
809  mutt_debug(LL_DEBUG1, "nm: failed to parse message: %s\n", path);
810  goto done;
811  }
812 
813 #ifdef USE_HCACHE
814  mutt_hcache_store(h, newpath ? newpath : path,
815  mutt_str_len(newpath ? newpath : path), e, 0);
816 #endif
817  }
818 
819  if (init_email(e, newpath ? newpath : path, msg) != 0)
820  {
821  email_free(&e);
822  mutt_debug(LL_DEBUG1, "nm: failed to append email!\n");
823  goto done;
824  }
825 
826  e->active = true;
827  e->index = m->msg_count;
828  mailbox_size_add(m, e);
829  m->emails[m->msg_count] = e;
830  m->msg_count++;
831 
832  if (newpath)
833  {
834  /* remember that file has been moved -- nm_mbox_sync() will update the DB */
835  struct NmEmailData *edata = nm_edata_get(e);
836  if (edata)
837  {
838  mutt_debug(LL_DEBUG1, "nm: remember obsolete path: %s\n", path);
839  edata->oldpath = mutt_str_dup(path);
840  }
841  }
843 done:
844  FREE(&newpath);
845 }
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
int mutt_hcache_store(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:559
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:464
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mailbox_size_add(struct Mailbox *m, const struct Email *e)
Add an email's size to the total size of a Mailbox.
Definition: mailbox.c:226
struct Email * maildir_parse_stream(enum MailboxType type, FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition: maildir.c:884
FILE * maildir_open_find_message(const char *folder, const char *msg, char **newname)
Find a new.
Definition: maildir.c:998
struct Email * maildir_parse_message(enum MailboxType type, const char *fname, bool is_old, struct Email *e)
Actually parse a maildir message.
Definition: maildir.c:931
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:475
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1218
static const char * get_message_last_filename(notmuch_message_t *msg)
Get a message's last filename.
Definition: notmuch.c:657
static char * get_folder_from_path(const char *path)
Find an email's folder from its path.
Definition: notmuch.c:566
static int init_email(struct Email *e, const char *path, notmuch_message_t *msg)
Set up an email's Notmuch data.
Definition: notmuch.c:613
static void nm_progress_update(struct Mailbox *m)
Update the progress counter.
Definition: notmuch.c:693
static struct Email * get_mutt_email(struct Mailbox *m, notmuch_message_t *msg)
Get the Email of a Notmuch message.
Definition: notmuch.c:710
bool active
Message is not to be removed.
Definition: email.h:74
int index
The absolute (unsorted) message number.
Definition: email.h:110
struct Email * email
Retrieved email.
Definition: lib.h:101
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
int ignmsgcount
Ignored messages.
Definition: mdata.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ append_replies()

static void append_replies ( struct HeaderCache h,
struct Mailbox m,
notmuch_query_t *  q,
notmuch_message_t *  top,
bool  dedup 
)
static

Add all the replies to a given messages into the display.

Parameters
hHeader cache handle
mMailbox
qNotmuch query
topNotmuch message
dedupDe-duplicate the results

Careful, this calls itself recursively to make sure we get everything.

Definition at line 857 of file notmuch.c.

859 {
860  notmuch_messages_t *msgs = NULL;
861 
862  for (msgs = notmuch_message_get_replies(top); notmuch_messages_valid(msgs);
863  notmuch_messages_move_to_next(msgs))
864  {
865  notmuch_message_t *nm = notmuch_messages_get(msgs);
866  append_message(h, m, nm, dedup);
867  /* recurse through all the replies to this message too */
868  append_replies(h, m, q, nm, dedup);
869  notmuch_message_destroy(nm);
870  }
871 }
static void append_replies(struct HeaderCache *h, struct Mailbox *m, notmuch_query_t *q, notmuch_message_t *top, bool dedup)
Add all the replies to a given messages into the display.
Definition: notmuch.c:857
static void append_message(struct HeaderCache *h, struct Mailbox *m, notmuch_message_t *msg, bool dedup)
Associate a message.
Definition: notmuch.c:744
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ append_thread()

static void append_thread ( struct HeaderCache h,
struct Mailbox m,
notmuch_query_t *  q,
notmuch_thread_t *  thread,
bool  dedup 
)
static

Add each top level reply in the thread.

Parameters
hHeader cache handle
mMailbox
qNotmuch query
threadNotmuch thread
dedupDe-duplicate the results

add each top level reply in the thread, and then add each reply to the top level replies

Definition at line 884 of file notmuch.c.

886 {
887  notmuch_messages_t *msgs = NULL;
888 
889  for (msgs = notmuch_thread_get_toplevel_messages(thread);
890  notmuch_messages_valid(msgs); notmuch_messages_move_to_next(msgs))
891  {
892  notmuch_message_t *nm = notmuch_messages_get(msgs);
893  append_message(h, m, nm, dedup);
894  append_replies(h, m, q, nm, dedup);
895  notmuch_message_destroy(nm);
896  }
897 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_messages()

static notmuch_messages_t* get_messages ( notmuch_query_t *  query)
static

Load messages for a query.

Parameters
queryNotmuch query
Return values
ptrMessages matching query
NULLError occurred

This helper method is to be the single point for retrieving messages. It handles version specific calls, which will make maintenance easier.

Definition at line 908 of file notmuch.c.

909 {
910  if (!query)
911  return NULL;
912 
913  notmuch_messages_t *msgs = NULL;
914 
915 #if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
916  if (notmuch_query_search_messages(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
917  return NULL;
918 #elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
919  if (notmuch_query_search_messages_st(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
920  return NULL;
921 #else
922  msgs = notmuch_query_search_messages(query);
923 #endif
924 
925  return msgs;
926 }
+ Here is the caller graph for this function:

◆ read_mesgs_query()

static bool read_mesgs_query ( struct Mailbox m,
notmuch_query_t *  q,
bool  dedup 
)
static

Search for matching messages.

Parameters
mMailbox
qNotmuch query
dedupDe-duplicate the results
Return values
trueSuccess
falseFailure

Definition at line 936 of file notmuch.c.

937 {
938  struct NmMboxData *mdata = nm_mdata_get(m);
939  if (!mdata)
940  return false;
941 
942  int limit = get_limit(mdata);
943 
944  notmuch_messages_t *msgs = get_messages(q);
945 
946  if (!msgs)
947  return false;
948 
949  struct HeaderCache *h = nm_hcache_open(m);
950 
951  for (; notmuch_messages_valid(msgs) && ((limit == 0) || (m->msg_count < limit));
952  notmuch_messages_move_to_next(msgs))
953  {
954  if (SigInt)
955  {
956  nm_hcache_close(h);
957  SigInt = false;
958  return false;
959  }
960  notmuch_message_t *nm = notmuch_messages_get(msgs);
961  append_message(h, m, nm, dedup);
962  notmuch_message_destroy(nm);
963  }
964 
965  nm_hcache_close(h);
966  return true;
967 }
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:71
static struct HeaderCache * nm_hcache_open(struct Mailbox *m)
Open a header cache.
Definition: notmuch.c:109
static void nm_hcache_close(struct HeaderCache *h)
Close the header cache.
Definition: notmuch.c:124
static int get_limit(struct NmMboxData *mdata)
Get the database limit.
Definition: notmuch.c:406
static notmuch_messages_t * get_messages(notmuch_query_t *query)
Load messages for a query.
Definition: notmuch.c:908
Header cache structure.
Definition: lib.h:87
+ Here is the call graph for this function:

◆ get_threads()

static notmuch_threads_t* get_threads ( notmuch_query_t *  query)
static

Load threads for a query.

Parameters
queryNotmuch query
Return values
ptrThreads matching query
NULLError occurred

This helper method is to be the single point for retrieving messages. It handles version specific calls, which will make maintenance easier.

Definition at line 978 of file notmuch.c.

979 {
980  if (!query)
981  return NULL;
982 
983  notmuch_threads_t *threads = NULL;
984 #if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
985  if (notmuch_query_search_threads(query, &threads) != NOTMUCH_STATUS_SUCCESS)
986  return false;
987 #elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
988  if (notmuch_query_search_threads_st(query, &threads) != NOTMUCH_STATUS_SUCCESS)
989  return false;
990 #else
991  threads = notmuch_query_search_threads(query);
992 #endif
993 
994  return threads;
995 }
+ Here is the caller graph for this function:

◆ read_threads_query()

static bool read_threads_query ( struct Mailbox m,
notmuch_query_t *  q,
bool  dedup,
int  limit 
)
static

Perform a query with threads.

Parameters
mMailbox
qQuery type
dedupShould the results be de-duped?
limitMaximum number of results
Return values
trueSuccess
falseFailure

Definition at line 1006 of file notmuch.c.

1007 {
1008  struct NmMboxData *mdata = nm_mdata_get(m);
1009  if (!mdata)
1010  return false;
1011 
1012  notmuch_threads_t *threads = get_threads(q);
1013  if (!threads)
1014  return false;
1015 
1016  struct HeaderCache *h = nm_hcache_open(m);
1017 
1018  for (; notmuch_threads_valid(threads) && ((limit == 0) || (m->msg_count < limit));
1019  notmuch_threads_move_to_next(threads))
1020  {
1021  if (SigInt)
1022  {
1023  nm_hcache_close(h);
1024  SigInt = false;
1025  return false;
1026  }
1027  notmuch_thread_t *thread = notmuch_threads_get(threads);
1028  append_thread(h, m, q, thread, dedup);
1029  notmuch_thread_destroy(thread);
1030  }
1031 
1032  nm_hcache_close(h);
1033  return true;
1034 }
static void append_thread(struct HeaderCache *h, struct Mailbox *m, notmuch_query_t *q, notmuch_thread_t *thread, bool dedup)
Add each top level reply in the thread.
Definition: notmuch.c:884
static notmuch_threads_t * get_threads(notmuch_query_t *query)
Load threads for a query.
Definition: notmuch.c:978
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_nm_message()

static notmuch_message_t* get_nm_message ( notmuch_database_t *  db,
struct Email e 
)
static

Find a Notmuch message.

Parameters
dbNotmuch database
eEmail
Return values
ptrHandle to the Notmuch message

Definition at line 1042 of file notmuch.c.

1043 {
1044  notmuch_message_t *msg = NULL;
1045  char *id = email_get_id(e);
1046 
1047  mutt_debug(LL_DEBUG2, "nm: find message (%s)\n", id);
1048 
1049  if (id && db)
1050  notmuch_database_find_message(db, id, &msg);
1051 
1052  return msg;
1053 }
static char * email_get_id(struct Email *e)
Get the unique Notmuch Id.
Definition: notmuch.c:210
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_message_has_tag()

static bool nm_message_has_tag ( notmuch_message_t *  msg,
char *  tag 
)
static

Does a message have this tag?

Parameters
msgNotmuch message
tagTag
Return values
trueIt does

Definition at line 1061 of file notmuch.c.

1062 {
1063  const char *possible_match_tag = NULL;
1064  notmuch_tags_t *tags = NULL;
1065 
1066  for (tags = notmuch_message_get_tags(msg); notmuch_tags_valid(tags);
1067  notmuch_tags_move_to_next(tags))
1068  {
1069  possible_match_tag = notmuch_tags_get(tags);
1070  if (mutt_str_equal(possible_match_tag, tag))
1071  {
1072  return true;
1073  }
1074  }
1075  return false;
1076 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sync_email_path_with_nm()

static void sync_email_path_with_nm ( struct Email e,
notmuch_message_t *  msg 
)
static

Synchronize Neomutt's Email path with notmuch.

Parameters
eEmail in Neomutt
msgEmail from notmuch

Definition at line 1083 of file notmuch.c.

1084 {
1085  const char *new_file = get_message_last_filename(msg);
1086  char old_file[PATH_MAX];
1087  email_get_fullpath(e, old_file, sizeof(old_file));
1088 
1089  if (!mutt_str_equal(old_file, new_file))
1090  update_message_path(e, new_file);
1091 }
static char * email_get_fullpath(struct Email *e, char *buf, size_t buflen)
Get the full path of an email.
Definition: notmuch.c:226
+ Here is the call graph for this function:

◆ update_tags()

static int update_tags ( notmuch_message_t *  msg,
const char *  tag_str 
)
static

Update the tags on a message.

Parameters
msgNotmuch message
tag_strString of tags (space separated)
Return values
0Success
-1Failure

Definition at line 1100 of file notmuch.c.

1101 {
1102  if (!tag_str)
1103  return -1;
1104 
1105  notmuch_message_freeze(msg);
1106 
1108  char **tag_elem = NULL;
1109  ARRAY_FOREACH(tag_elem, &tags.tags)
1110  {
1111  char *tag = *tag_elem;
1112 
1113  if (tag[0] == '-')
1114  {
1115  mutt_debug(LL_DEBUG1, "nm: remove tag: '%s'\n", tag + 1);
1116  notmuch_message_remove_tag(msg, tag + 1);
1117  }
1118  else if (tag[0] == '!')
1119  {
1120  mutt_debug(LL_DEBUG1, "nm: toggle tag: '%s'\n", tag + 1);
1121  if (nm_message_has_tag(msg, tag + 1))
1122  {
1123  notmuch_message_remove_tag(msg, tag + 1);
1124  }
1125  else
1126  {
1127  notmuch_message_add_tag(msg, tag + 1);
1128  }
1129  }
1130  else
1131  {
1132  mutt_debug(LL_DEBUG1, "nm: add tag: '%s'\n", (tag[0] == '+') ? tag + 1 : tag);
1133  notmuch_message_add_tag(msg, (tag[0] == '+') ? tag + 1 : tag);
1134  }
1135  }
1136 
1137  notmuch_message_thaw(msg);
1139 
1140  return 0;
1141 }
static bool nm_message_has_tag(notmuch_message_t *msg, char *tag)
Does a message have this tag?
Definition: notmuch.c:1061
char * tag_str
Source string.
Definition: tag.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_email_flags()

static int update_email_flags ( struct Mailbox m,
struct Email e,
const char *  tag_str 
)
static

Update the Email's flags.

Parameters
mMailbox
eEmail
tag_strString of tags (space separated)
Return values
0Success
-1Failure

TODO: join update_email_tags and update_email_flags, which are given an array of tags.

Definition at line 1154 of file notmuch.c.

1155 {
1156  if (!tag_str)
1157  return -1;
1158 
1159  const char *const c_nm_unread_tag =
1160  cs_subset_string(NeoMutt->sub, "nm_unread_tag");
1161  const char *const c_nm_replied_tag =
1162  cs_subset_string(NeoMutt->sub, "nm_replied_tag");
1163  const char *const c_nm_flagged_tag =
1164  cs_subset_string(NeoMutt->sub, "nm_flagged_tag");
1165 
1167  char **tag_elem = NULL;
1168  ARRAY_FOREACH(tag_elem, &tags.tags)
1169  {
1170  char *tag = *tag_elem;
1171 
1172  if (tag[0] == '-')
1173  {
1174  tag++;
1175  if (strcmp(tag, c_nm_unread_tag) == 0)
1176  mutt_set_flag(m, e, MUTT_READ, true);
1177  else if (strcmp(tag, c_nm_replied_tag) == 0)
1178  mutt_set_flag(m, e, MUTT_REPLIED, false);
1179  else if (strcmp(tag, c_nm_flagged_tag) == 0)
1180  mutt_set_flag(m, e, MUTT_FLAG, false);
1181  }
1182  else
1183  {
1184  tag = (tag[0] == '+') ? tag + 1 : tag;
1185  if (strcmp(tag, c_nm_unread_tag) == 0)
1186  mutt_set_flag(m, e, MUTT_READ, false);
1187  else if (strcmp(tag, c_nm_replied_tag) == 0)
1188  mutt_set_flag(m, e, MUTT_REPLIED, true);
1189  else if (strcmp(tag, c_nm_flagged_tag) == 0)
1190  mutt_set_flag(m, e, MUTT_FLAG, true);
1191  }
1192  }
1193 
1195 
1196  return 0;
1197 }
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:92
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:98
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:91
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:66
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rename_maildir_filename()

static int rename_maildir_filename ( const char *  old,
char *  buf,
size_t  buflen,
struct Email e 
)
static

Rename a Maildir file.

Parameters
oldOld path
bufBuffer for new path
buflenLength of buffer
eEmail
Return values
0Success, renamed
1Success, no change
-1Failure

Definition at line 1209 of file notmuch.c.

1210 {
1211  char filename[PATH_MAX];
1212  char suffix[PATH_MAX];
1213  char folder[PATH_MAX];
1214 
1215  mutt_str_copy(folder, old, sizeof(folder));
1216  char *p = strrchr(folder, '/');
1217  if (p)
1218  {
1219  *p = '\0';
1220  p++;
1221  }
1222  else
1223  p = folder;
1224 
1225  mutt_str_copy(filename, p, sizeof(filename));
1226 
1227  /* remove (new,cur,...) from folder path */
1228  p = strrchr(folder, '/');
1229  if (p)
1230  *p = '\0';
1231 
1232  /* remove old flags from filename */
1233  p = strchr(filename, ':');
1234  if (p)
1235  *p = '\0';
1236 
1237  /* compose new flags */
1238  maildir_gen_flags(suffix, sizeof(suffix), e);
1239 
1240  snprintf(buf, buflen, "%s/%s/%s%s", folder,
1241  (e->read || e->old) ? "cur" : "new", filename, suffix);
1242 
1243  if (strcmp(old, buf) == 0)
1244  return 1;
1245 
1246  if (rename(old, buf) != 0)
1247  {
1248  mutt_debug(LL_DEBUG1, "nm: rename(2) failed %s -> %s\n", old, buf);
1249  return -1;
1250  }
1251 
1252  return 0;
1253 }
void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
Generate the Maildir flags for an email.
Definition: maildir.c:186
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:560
bool read
Email is read.
Definition: email.h:48
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ remove_filename()

static int remove_filename ( struct Mailbox m,
const char *  path 
)
static

Delete a file.

Parameters
mMailbox
pathPath of file
Return values
0Success
-1Failure

Definition at line 1262 of file notmuch.c.

1263 {
1264  struct NmMboxData *mdata = nm_mdata_get(m);
1265  if (!mdata)
1266  return -1;
1267 
1268  mutt_debug(LL_DEBUG2, "nm: remove filename '%s'\n", path);
1269 
1270  notmuch_database_t *db = nm_db_get(m, true);
1271  if (!db)
1272  return -1;
1273 
1274  notmuch_message_t *msg = NULL;
1275  notmuch_status_t st = notmuch_database_find_message_by_filename(db, path, &msg);
1276  if (st || !msg)
1277  return -1;
1278 
1279  int trans = nm_db_trans_begin(m);
1280  if (trans < 0)
1281  return -1;
1282 
1283  /* note that unlink() is probably unnecessary here, it's already removed
1284  * by mh_sync_mailbox_message(), but for sure... */
1285  notmuch_filenames_t *ls = NULL;
1286  st = notmuch_database_remove_message(db, path);
1287  switch (st)
1288  {
1289  case NOTMUCH_STATUS_SUCCESS:
1290  mutt_debug(LL_DEBUG2, "nm: remove success, call unlink\n");
1291  unlink(path);
1292  break;
1293  case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
1294  mutt_debug(LL_DEBUG2, "nm: remove success (duplicate), call unlink\n");
1295  unlink(path);
1296  for (ls = notmuch_message_get_filenames(msg);
1297  ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
1298  {
1299  path = notmuch_filenames_get(ls);
1300 
1301  mutt_debug(LL_DEBUG2, "nm: remove duplicate: '%s'\n", path);
1302  unlink(path);
1303  notmuch_database_remove_message(db, path);
1304  }
1305  break;
1306  default:
1307  mutt_debug(LL_DEBUG1, "nm: failed to remove '%s' [st=%d]\n", path, (int) st);
1308  break;
1309  }
1310 
1311  notmuch_message_destroy(msg);
1312  if (trans)
1313  nm_db_trans_end(m);
1314  return 0;
1315 }
int nm_db_trans_begin(struct Mailbox *m)
Start a Notmuch database transaction.
Definition: db.c:231
int nm_db_trans_end(struct Mailbox *m)
End a database transaction.
Definition: db.c:253
+ Here is the call graph for this function:

◆ rename_filename()

static int rename_filename ( struct Mailbox m,
const char *  old_file,
const char *  new_file,
struct Email e 
)
static

Rename the file.

Parameters
mNotmuch Mailbox data
old_fileOld filename
new_fileNew filename
eEmail
Return values
0Success
-1Failure

Definition at line 1326 of file notmuch.c.

1328 {
1329  struct NmMboxData *mdata = nm_mdata_get(m);
1330  if (!mdata)
1331  return -1;
1332 
1333  notmuch_database_t *db = nm_db_get(m, true);
1334  if (!db || !new_file || !old_file || (access(new_file, F_OK) != 0))
1335  return -1;
1336 
1337  int rc = -1;
1338  notmuch_status_t st;
1339  notmuch_filenames_t *ls = NULL;
1340  notmuch_message_t *msg = NULL;
1341 
1342  mutt_debug(LL_DEBUG1, "nm: rename filename, %s -> %s\n", old_file, new_file);
1343  int trans = nm_db_trans_begin(m);
1344  if (trans < 0)
1345  return -1;
1346 
1347  mutt_debug(LL_DEBUG2, "nm: rename: add '%s'\n", new_file);
1348 #if LIBNOTMUCH_CHECK_VERSION(5, 1, 0)
1349  st = notmuch_database_index_file(db, new_file, NULL, &msg);
1350 #else
1351  st = notmuch_database_add_message(db, new_file, &msg);
1352 #endif
1353 
1354  if ((st != NOTMUCH_STATUS_SUCCESS) && (st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID))
1355  {
1356  mutt_debug(LL_DEBUG1, "nm: failed to add '%s' [st=%d]\n", new_file, (int) st);
1357  goto done;
1358  }
1359 
1360  mutt_debug(LL_DEBUG2, "nm: rename: rem '%s'\n", old_file);
1361  st = notmuch_database_remove_message(db, old_file);
1362  switch (st)
1363  {
1364  case NOTMUCH_STATUS_SUCCESS:
1365  break;
1366  case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
1367  mutt_debug(LL_DEBUG2, "nm: rename: syncing duplicate filename\n");
1368  notmuch_message_destroy(msg);
1369  msg = NULL;
1370  notmuch_database_find_message_by_filename(db, new_file, &msg);
1371 
1372  for (ls = notmuch_message_get_filenames(msg);
1373  msg && ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
1374  {
1375  const char *path = notmuch_filenames_get(ls);
1376  char newpath[PATH_MAX];
1377 
1378  if (strcmp(new_file, path) == 0)
1379  continue;
1380 
1381  mutt_debug(LL_DEBUG2, "nm: rename: syncing duplicate: %s\n", path);
1382 
1383  if (rename_maildir_filename(path, newpath, sizeof(newpath), e) == 0)
1384  {
1385  mutt_debug(LL_DEBUG2, "nm: rename dup %s -> %s\n", path, newpath);
1386  notmuch_database_remove_message(db, path);
1387 #if LIBNOTMUCH_CHECK_VERSION(5, 1, 0)
1388  notmuch_database_index_file(db, newpath, NULL, NULL);
1389 #else
1390  notmuch_database_add_message(db, newpath, NULL);
1391 #endif
1392  }
1393  }
1394  notmuch_message_destroy(msg);
1395  msg = NULL;
1396  notmuch_database_find_message_by_filename(db, new_file, &msg);
1397  st = NOTMUCH_STATUS_SUCCESS;
1398  break;
1399  default:
1400  mutt_debug(LL_DEBUG1, "nm: failed to remove '%s' [st=%d]\n", old_file, (int) st);
1401  break;
1402  }
1403 
1404  if ((st == NOTMUCH_STATUS_SUCCESS) && e && msg)
1405  {
1406  notmuch_message_maildir_flags_to_tags(msg);
1407  update_email_tags(e, msg);
1408 
1409  char *tags = driver_tags_get(&e->tags);
1410  update_tags(msg, tags);
1411  FREE(&tags);
1412  }
1413 
1414  rc = 0;
1415 done:
1416  if (msg)
1417  notmuch_message_destroy(msg);
1418  if (trans)
1419  nm_db_trans_end(m);
1420  return rc;
1421 }
static int rename_maildir_filename(const char *old, char *buf, size_t buflen, struct Email *e)
Rename a Maildir file.
Definition: notmuch.c:1209
static int update_tags(notmuch_message_t *msg, const char *tag_str)
Update the tags on a message.
Definition: notmuch.c:1100
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ count_query()

static unsigned int count_query ( notmuch_database_t *  db,
const char *  qstr,
int  limit 
)
static

Count the results of a query.

Parameters
dbNotmuch database
qstrQuery to execute
limitMaximum number of results
Return values
numNumber of results

Definition at line 1430 of file notmuch.c.

1431 {
1432  notmuch_query_t *q = notmuch_query_create(db, qstr);
1433  if (!q)
1434  return 0;
1435 
1436  unsigned int res = 0;
1437 
1438  apply_exclude_tags(q);
1439 #if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
1440  if (notmuch_query_count_messages(q, &res) != NOTMUCH_STATUS_SUCCESS)
1441  res = 0; /* may not be defined on error */
1442 #elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
1443  if (notmuch_query_count_messages_st(q, &res) != NOTMUCH_STATUS_SUCCESS)
1444  res = 0; /* may not be defined on error */
1445 #else
1446  res = notmuch_query_count_messages(q);
1447 #endif
1448  notmuch_query_destroy(q);
1449  mutt_debug(LL_DEBUG1, "nm: count '%s', result=%d\n", qstr, res);
1450 
1451  if ((limit > 0) && (res > limit))
1452  res = limit;
1453 
1454  return res;
1455 }
+ Here is the call graph for this function:

◆ nm_email_get_folder()

char* nm_email_get_folder ( struct Email e)

Get the folder for a Email.

Parameters
eEmail
Return values
ptrFolder containing email
NULLError

Definition at line 1463 of file notmuch.c.

1464 {
1465  struct NmEmailData *edata = nm_edata_get(e);
1466  if (!edata)
1467  return NULL;
1468 
1469  return edata->folder;
1470 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_email_get_folder_rel_db()

char* nm_email_get_folder_rel_db ( struct Mailbox m,
struct Email e 
)

Get the folder for a Email from the same level as the notmuch database.

Parameters
mMailbox containing Email
eEmail
Return values
ptrFolder containing email from the same level as the notmuch db
NULLError

Instead of returning a path like /var/mail/account/Inbox, this returns account/Inbox. If wanting the full path, use nm_email_get_folder().

Definition at line 1482 of file notmuch.c.

1483 {
1484  char *full_folder = nm_email_get_folder(e);
1485  if (!full_folder)
1486  return NULL;
1487 
1488  const char *db_path = nm_db_get_filename(m);
1489  if (!db_path)
1490  return NULL;
1491 
1492  return full_folder + strlen(db_path);
1493 }
const char * nm_db_get_filename(struct Mailbox *m)
Get the filename of the Notmuch database.
Definition: db.c:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_read_entire_thread()

int nm_read_entire_thread ( struct Mailbox m,
struct Email e 
)

Get the entire thread of an email.

Parameters
mMailbox
eEmail
Return values
0Success
-1Failure

Definition at line 1502 of file notmuch.c.

1503 {
1504  if (!m)
1505  return -1;
1506 
1507  struct NmMboxData *mdata = nm_mdata_get(m);
1508  if (!mdata)
1509  return -1;
1510 
1511  notmuch_query_t *q = NULL;
1512  notmuch_database_t *db = NULL;
1513  notmuch_message_t *msg = NULL;
1514  int rc = -1;
1515 
1516  if (!(db = nm_db_get(m, false)) || !(msg = get_nm_message(db, e)))
1517  goto done;
1518 
1519  mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages...[current count=%d]\n",
1520  m->msg_count);
1521 
1522  progress_setup(m);
1523  const char *id = notmuch_message_get_thread_id(msg);
1524  if (!id)
1525  goto done;
1526 
1527  char *qstr = NULL;
1528  mutt_str_append_item(&qstr, "thread:", '\0');
1529  mutt_str_append_item(&qstr, id, '\0');
1530 
1531  q = notmuch_query_create(db, qstr);
1532  FREE(&qstr);
1533  if (!q)
1534  goto done;
1535  apply_exclude_tags(q);
1536  notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
1537 
1538  read_threads_query(m, q, true, 0);
1539  m->mtime.tv_sec = mutt_date_epoch();
1540  m->mtime.tv_nsec = 0;
1541  rc = 0;
1542 
1543  if (m->msg_count > mdata->oldmsgcount)
1545 done:
1546  if (q)
1547  notmuch_query_destroy(q);
1548 
1549  nm_db_release(m);
1550 
1551  if (m->msg_count == mdata->oldmsgcount)
1552  mutt_message(_("No more messages in the thread"));
1553 
1554  mdata->oldmsgcount = 0;
1555  mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
1556  rc, m->msg_count);
1557  progress_free(&mdata->progress);
1558  return rc;
1559 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:211
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:180
static notmuch_message_t * get_nm_message(notmuch_database_t *db, struct Email *e)
Find a Notmuch message.
Definition: notmuch.c:1042
static bool read_threads_query(struct Mailbox *m, notmuch_query_t *q, bool dedup, int limit)
Perform a query with threads.
Definition: notmuch.c:1006
static void progress_setup(struct Mailbox *m)
Set up the Progress Bar.
Definition: notmuch.c:674
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:232
struct timespec mtime
Time Mailbox was last changed.
Definition: mailbox.h:107
long tv_nsec
Number of nanosecond, on top.
Definition: file.h:51
time_t tv_sec
Number of seconds since the epoch.
Definition: file.h:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_url_from_query()

char* nm_url_from_query ( struct Mailbox m,
char *  buf,
size_t  buflen 
)

Turn a query into a URL.

Parameters
mMailbox
bufBuffer for URL
buflenLength of buffer
Return values
ptrQuery as a URL
NULLError

Definition at line 1569 of file notmuch.c.

1570 {
1571  mutt_debug(LL_DEBUG2, "(%s)\n", buf);
1572  struct NmMboxData *mdata = nm_mdata_get(m);
1573  char url[PATH_MAX + 1024 + 32]; /* path to DB + query + URL "decoration" */
1574  int added;
1575  bool using_default_data = false;
1576 
1577  // No existing data. Try to get a default NmMboxData.
1578  if (!mdata)
1579  {
1581 
1582  // Failed to get default data.
1583  if (!mdata)
1584  return NULL;
1585 
1586  using_default_data = true;
1587  }
1588 
1589  enum NmQueryType c_nm_query_type =
1591  mdata->query_type = nm_parse_type_from_query(buf, c_nm_query_type);
1592 
1593  const short c_nm_db_limit = cs_subset_number(NeoMutt->sub, "nm_db_limit");
1594  if (get_limit(mdata) == c_nm_db_limit)
1595  {
1596  added = snprintf(url, sizeof(url), "%s%s?type=%s&query=", NmUrlProtocol,
1598  }
1599  else
1600  {
1601  added = snprintf(url, sizeof(url), "%s%s?type=%s&limit=%d&query=", NmUrlProtocol,
1602  nm_db_get_filename(m),
1603  nm_query_type_to_string(mdata->query_type), get_limit(mdata));
1604  }
1605 
1606  if (added >= sizeof(url))
1607  {
1608  // snprintf output was truncated, so can't create URL
1609  return NULL;
1610  }
1611 
1612  url_pct_encode(&url[added], sizeof(url) - added, buf);
1613 
1614  mutt_str_copy(buf, url, buflen);
1615  buf[buflen - 1] = '\0';
1616 
1617  if (using_default_data)
1618  nm_mdata_free((void **) &mdata);
1619 
1620  mutt_debug(LL_DEBUG1, "nm: url from query '%s'\n", buf);
1621  return buf;
1622 }
static struct NmMboxData * nm_get_default_data(void)
Create a Mailbox with default Notmuch settings.
Definition: notmuch.c:165
const char NmUrlProtocol[]
Definition: notmuch.c:93
const char * nm_query_type_to_string(enum NmQueryType query_type)
Turn a query type into a string.
Definition: query.c:96
enum NmQueryType nm_parse_type_from_query(char *buf, enum NmQueryType fallback)
Parse a query type out of a query.
Definition: query.c:49
NmQueryType
Notmuch Query Types.
Definition: query.h:35
void url_pct_encode(char *buf, size_t buflen, const char *src)
Percent-encode a string.
Definition: url.c:151
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_query_window_available()

bool nm_query_window_available ( void  )

Are windowed queries enabled for use?

Return values
trueWindowed queries in use

Definition at line 1628 of file notmuch.c.

1629 {
1630  const short c_nm_query_window_duration =
1631  cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
1632  const bool c_nm_query_window_enable =
1633  cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
1634 
1635  return c_nm_query_window_enable || (c_nm_query_window_duration > 0);
1636 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_query_window_forward()

void nm_query_window_forward ( void  )

Function to move the current search window forward in time.

Updates nm_query_window_current_position by decrementing it by 1, or does nothing if the current window already is set to 0.

The lower the value of nm_query_window_current_position is, the more recent the result will be.

Definition at line 1647 of file notmuch.c.

1648 {
1649  const short c_nm_query_window_current_position =
1650  cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1651  if (c_nm_query_window_current_position != 0)
1652  {
1653  cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1654  c_nm_query_window_current_position - 1, NULL);
1655  }
1656 
1657  mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position - 1);
1658 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_query_window_backward()

void nm_query_window_backward ( void  )

Function to move the current search window backward in time.

Updates nm_query_window_current_position by incrementing it by 1

The higher the value of nm_query_window_current_position is, the less recent the result will be.

Definition at line 1668 of file notmuch.c.

1669 {
1670  const short c_nm_query_window_current_position =
1671  cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1672  cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1673  c_nm_query_window_current_position + 1, NULL);
1674  mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position + 1);
1675 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_query_window_reset()

void nm_query_window_reset ( void  )

Resets the vfolder window position to the present.

Definition at line 1680 of file notmuch.c.

1681 {
1682  cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position", 0, NULL);
1683  mutt_debug(LL_DEBUG2, "Reset nm_query_window_current_position to 0\n");
1684 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_message_is_still_queried()

bool nm_message_is_still_queried ( struct Mailbox m,
struct Email e 
)

Is a message still visible in the query?

Parameters
mMailbox
eEmail
Return values
trueMessage is still in query

Definition at line 1692 of file notmuch.c.

1693 {
1694  struct NmMboxData *mdata = nm_mdata_get(m);
1695  notmuch_database_t *db = nm_db_get(m, false);
1696  char *orig_str = get_query_string(mdata, true);
1697 
1698  if (!db || !orig_str)
1699  return false;
1700 
1701  char *new_str = NULL;
1702  bool rc = false;
1703  if (mutt_str_asprintf(&new_str, "id:%s and (%s)", email_get_id(e), orig_str) < 0)
1704  return false;
1705 
1706  mutt_debug(LL_DEBUG2, "nm: checking if message is still queried: %s\n", new_str);
1707 
1708  notmuch_query_t *q = notmuch_query_create(db, new_str);
1709 
1710  switch (mdata->query_type)
1711  {
1712  case NM_QUERY_TYPE_UNKNOWN: // UNKNOWN should never occur, but MESGS is default
1713  case NM_QUERY_TYPE_MESGS:
1714  {
1715  notmuch_messages_t *messages = get_messages(q);
1716 
1717  if (!messages)
1718  return false;
1719 
1720  rc = notmuch_messages_valid(messages);
1721  notmuch_messages_destroy(messages);
1722  break;
1723  }
1724  case NM_QUERY_TYPE_THREADS:
1725  {
1726  notmuch_threads_t *threads = get_threads(q);
1727 
1728  if (!threads)
1729  return false;
1730 
1731  rc = notmuch_threads_valid(threads);
1732  notmuch_threads_destroy(threads);
1733  break;
1734  }
1735  }
1736 
1737  notmuch_query_destroy(q);
1738 
1739  mutt_debug(LL_DEBUG2, "nm: checking if message is still queried: %s = %s\n",
1740  new_str, rc ? "true" : "false");
1741 
1742  return rc;
1743 }
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:939
@ NM_QUERY_TYPE_UNKNOWN
Unknown query type. Error in notmuch query.
Definition: query.h:38
@ NM_QUERY_TYPE_THREADS
Whole threads.
Definition: query.h:37
@ NM_QUERY_TYPE_MESGS
Default: Messages only.
Definition: query.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_update_filename()

int nm_update_filename ( struct Mailbox m,
const char *  old_file,
const char *  new_file,
struct Email e 
)

Change the filename.

Parameters
mMailbox
old_fileOld filename
new_fileNew filename
eEmail
Return values
0Success
-1Failure

Definition at line 1754 of file notmuch.c.

1756 {
1757  char buf[PATH_MAX];
1758  struct NmMboxData *mdata = nm_mdata_get(m);
1759  if (!mdata || !new_file)
1760  return -1;
1761 
1762  if (!old_file && nm_edata_get(e))
1763  {
1764  email_get_fullpath(e, buf, sizeof(buf));
1765  old_file = buf;
1766  }
1767 
1768  int rc = rename_filename(m, old_file, new_file, e);
1769 
1770  nm_db_release(m);
1771  m->mtime.tv_sec = mutt_date_epoch();
1772  m->mtime.tv_nsec = 0;
1773  return rc;
1774 }
static int rename_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Rename the file.
Definition: notmuch.c:1326
+ Here is the caller graph for this function:

◆ get_default_mailbox()

static struct Mailbox* get_default_mailbox ( void  )
static

Get Mailbox for notmuch without any parameters.

Return values
ptrMailbox pointer

Definition at line 1865 of file notmuch.c.

1866 {
1867  // Create a new notmuch mailbox from scratch and add plumbing for DB access.
1868  char *default_url = nm_get_default_url();
1869  struct Mailbox *m = mx_path_resolve(default_url);
1870 
1871  FREE(&default_url);
1872 
1873  // These are no-ops for an initialized mailbox.
1874  init_mailbox(m);
1875  mx_mbox_ac_link(m);
1876 
1877  return m;
1878 }
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:267
static int init_mailbox(struct Mailbox *m)
Add Notmuch data to the Mailbox.
Definition: notmuch.c:188
A mailbox.
Definition: mailbox.h:82
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_record_message()

int nm_record_message ( struct Mailbox m,
char *  path,
struct Email e 
)

Add a message to the Notmuch database.

Parameters
mMailbox
pathPath of the email
eEmail
Return values
0Success
-1Failure

Definition at line 1888 of file notmuch.c.

1889 {
1890  notmuch_database_t *db = NULL;
1891  notmuch_status_t st;
1892  notmuch_message_t *msg = NULL;
1893  int rc = -1;
1894 
1895  struct NmMboxData *mdata = nm_mdata_get(m);
1896 
1897  // If no notmuch data, fall back to the default mailbox.
1898  //
1899  // IMPORTANT: DO NOT FREE THIS MAILBOX. Two reasons:
1900  // 1) If user has default mailbox in config, we'll be removing it. That's not
1901  // good program behavior!
1902  // 2) If not in user's config, keep mailbox around for future nm_record calls.
1903  // It saves NeoMutt from allocating/deallocating repeatedly.
1904  if (!mdata)
1905  {
1906  mutt_debug(LL_DEBUG1, "nm: non-nm mailbox. trying the default nm mailbox.");
1907  m = get_default_mailbox();
1908  mdata = nm_mdata_get(m);
1909  }
1910 
1911  if (!path || !mdata || (access(path, F_OK) != 0))
1912  return 0;
1913  db = nm_db_get(m, true);
1914  if (!db)
1915  return -1;
1916 
1917  mutt_debug(LL_DEBUG1, "nm: record message: %s\n", path);
1918  int trans = nm_db_trans_begin(m);
1919  if (trans < 0)
1920  goto done;
1921 
1922 #if LIBNOTMUCH_CHECK_VERSION(5, 1, 0)
1923  st = notmuch_database_index_file(db, path, NULL, &msg);
1924 #else
1925  st = notmuch_database_add_message(db, path, &msg);
1926 #endif
1927 
1928  if ((st != NOTMUCH_STATUS_SUCCESS) && (st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID))
1929  {
1930  mutt_debug(LL_DEBUG1, "nm: failed to add '%s' [st=%d]\n", path, (int) st);
1931  goto done;
1932  }
1933 
1934  if ((st == NOTMUCH_STATUS_SUCCESS) && msg)
1935  {
1936  notmuch_message_maildir_flags_to_tags(msg);
1937  if (e)
1938  {
1939  char *tags = driver_tags_get(&e->tags);
1940  update_tags(msg, tags);
1941  FREE(&tags);
1942  }
1943  const char *const c_nm_record_tags =
1944  cs_subset_string(NeoMutt->sub, "nm_record_tags");
1945  if (c_nm_record_tags)
1946  update_tags(msg, c_nm_record_tags);
1947  }
1948 
1949  rc = 0;
1950 done:
1951  if (msg)
1952  notmuch_message_destroy(msg);
1953  if (trans == 1)
1954  nm_db_trans_end(m);
1955 
1956  nm_db_release(m);
1957 
1958  return rc;
1959 }
static struct Mailbox * get_default_mailbox(void)
Get Mailbox for notmuch without any parameters.
Definition: notmuch.c:1865
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nm_get_all_tags()

int nm_get_all_tags ( struct Mailbox m,
char **  tag_list,
int *  tag_count 
)

Fill a list with all notmuch tags.

Parameters
[in]mMailbox
[out]tag_listList of tags
[out]tag_countNumber of tags
Return values
0Success
-1Failure

If tag_list is NULL, just count the tags.

Definition at line 1971 of file notmuch.c.

1972 {
1973  struct NmMboxData *mdata = nm_mdata_get(m);
1974  if (!mdata)
1975  return -1;
1976 
1977  notmuch_database_t *db = NULL;
1978  notmuch_tags_t *tags = NULL;
1979  const char *tag = NULL;
1980  int rc = -1;
1981 
1982  if (!(db = nm_db_get(m, false)) || !(tags = notmuch_database_get_all_tags(db)))
1983  goto done;
1984 
1985  *tag_count = 0;
1986  mutt_debug(LL_DEBUG1, "nm: get all tags\n");
1987 
1988  while (notmuch_tags_valid(tags))
1989  {
1990  tag = notmuch_tags_get(tags);
1991  /* Skip empty string */
1992  if (*tag)
1993  {
1994  if (tag_list)
1995  tag_list[*tag_count] = mutt_str_dup(tag);
1996  (*tag_count)++;
1997  }
1998  notmuch_tags_move_to_next(tags);
1999  }
2000 
2001  rc = 0;
2002 done:
2003  if (tags)
2004  notmuch_tags_destroy(tags);
2005 
2006  nm_db_release(m);
2007 
2008  mutt_debug(LL_DEBUG1, "nm: get all tags done [rc=%d tag_count=%u]\n", rc, *tag_count);
2009  return rc;
2010 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ nm_commands

const struct Command nm_commands[]
static
Initial value:
= {
{ "unvirtual-mailboxes", parse_unmailboxes, 0 },
{ "virtual-mailboxes", parse_mailboxes, MUTT_NAMED },
}
enum CommandResult parse_unmailboxes(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'unmailboxes' command - Implements Command::parse() -.
enum CommandResult parse_mailboxes(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'mailboxes' command - Implements Command::parse() -.
#define MUTT_NAMED
Definition: mutt_commands.h:44

Definition at line 1 of file notmuch.c.

◆ NmUrlProtocol

const char NmUrlProtocol[] = "notmuch://"

Definition at line 93 of file notmuch.c.

◆ NmUrlProtocolLen

const int NmUrlProtocolLen = sizeof(NmUrlProtocol) - 1

Definition at line 94 of file notmuch.c.