NeoMutt  2022-04-29-249-gaae397
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 "mutt.h"
#include "lib.h"
#include "enter/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, const 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 = cs_subset_path(NeoMutt->sub, "header_cache");
113 return mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
114#else
115 return NULL;
116#endif
117}
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:332
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
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 123 of file notmuch.c.

124{
125#ifdef USE_HCACHE
127#endif
128}
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:442
+ 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 135 of file notmuch.c.

136{
137 // path to DB + query + url "decoration"
138 size_t len = PATH_MAX + 1024 + 32;
139 char *url = mutt_mem_malloc(len);
140
141 // Try to use `$nm_default_url` or `$folder`.
142 // If neither are set, it is impossible to create a Notmuch URL.
143 const char *const c_nm_default_url = cs_subset_string(NeoMutt->sub, "nm_default_url");
144 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
145 if (c_nm_default_url)
146 snprintf(url, len, "%s", c_nm_default_url);
147 else if (c_folder)
148 snprintf(url, len, "notmuch://%s", c_folder);
149 else
150 {
151 FREE(&url);
152 return NULL;
153 }
154
155 return url;
156}
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:43
#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 163 of file notmuch.c.

164{
165 // path to DB + query + url "decoration"
166 char *url = nm_get_default_url();
167 if (!url)
168 return NULL;
169
170 struct NmMboxData *default_data = nm_mdata_new(url);
171 FREE(&url);
172
173 return default_data;
174}
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:135
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 186 of file notmuch.c.

187{
188 if (!m || (m->type != MUTT_NOTMUCH))
189 return -1;
190
191 if (m->mdata)
192 return 0;
193
195 if (!m->mdata)
196 return -1;
197
199 return 0;
200}
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
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:142
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
void * mdata
Driver specific data.
Definition: mailbox.h:132
+ 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 208 of file notmuch.c.

209{
210 struct NmEmailData *edata = nm_edata_get(e);
211 if (!edata)
212 return NULL;
213
214 return edata->virtual_id;
215}
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 224 of file notmuch.c.

225{
226 snprintf(buf, buflen, "%s/%s", nm_email_get_folder(e), e->path);
227 return buf;
228}
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1450
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 239 of file notmuch.c.

240{
241 mutt_debug(LL_DEBUG2, "entering\n");
242 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position", 0, NULL);
243}
#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 269 of file notmuch.c.

270{
271 mutt_debug(LL_DEBUG2, "nm: %s\n", query);
272
273 const bool c_nm_query_window_enable = cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
274 const short c_nm_query_window_duration = cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
275 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
276 const char *const c_nm_query_window_current_search = cs_subset_string(NeoMutt->sub, "nm_query_window_current_search");
277 const char *const c_nm_query_window_timebase = cs_subset_string(NeoMutt->sub, "nm_query_window_timebase");
278 const char *const c_nm_query_window_or_terms = cs_subset_string(NeoMutt->sub, "nm_query_window_or_terms");
279
280 /* if the query has changed, reset the window position */
281 if (!c_nm_query_window_current_search ||
282 (strcmp(query, c_nm_query_window_current_search) != 0))
283 {
285 }
286
288 buf, buflen, c_nm_query_window_enable, c_nm_query_window_duration,
289 c_nm_query_window_current_position, c_nm_query_window_current_search,
290 c_nm_query_window_timebase, c_nm_query_window_or_terms);
291
292 switch (rc)
293 {
295 {
296 mutt_debug(LL_DEBUG2, "nm: %s -> %s\n", query, buf);
297 break;
298 }
300 {
302 return false;
303 }
305 {
307 // L10N: The values 'hour', 'day', 'week', 'month', 'year' are literal.
308 // They should not be translated.
309 _("Invalid nm_query_window_timebase value (valid values are: hour, day, week, month, year)"));
310 mutt_debug(LL_DEBUG2, "Invalid nm_query_window_timebase value\n");
311 return false;
312 }
313 }
314
315 return true;
316}
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 mutt_message(...)
Definition: logging.h:86
#define _(a)
Definition: message.h:28
static void query_window_reset(void)
Restore vfolder's search window to its original position.
Definition: notmuch.c:239
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 334 of file notmuch.c.

335{
336 mutt_debug(LL_DEBUG2, "nm: %s\n", window ? "true" : "false");
337
338 if (!mdata)
339 return NULL;
340 if (mdata->db_query && !window)
341 return mdata->db_query;
342
343 const char *const c_nm_query_type = cs_subset_string(NeoMutt->sub, "nm_query_type");
344 mdata->query_type = nm_string_to_query_type(c_nm_query_type); /* user's default */
345
346 struct UrlQuery *item = NULL;
347 STAILQ_FOREACH(item, &mdata->db_url->query_strings, entries)
348 {
349 if (!item->value || !item->name)
350 continue;
351
352 if (strcmp(item->name, "limit") == 0)
353 {
354 if (!mutt_str_atoi_full(item->value, &mdata->db_limit))
355 {
356 mutt_error(_("failed to parse notmuch limit: %s"), item->value);
357 }
358 }
359 else if (strcmp(item->name, "type") == 0)
361 else if (strcmp(item->name, "query") == 0)
362 mutt_str_replace(&mdata->db_query, item->value);
363 }
364
365 if (!mdata->db_query)
366 return NULL;
367
368 if (window)
369 {
370 char buf[1024] = { 0 };
371 cs_subset_str_string_set(NeoMutt->sub, "nm_query_window_current_search",
372 mdata->db_query, NULL);
373
374 /* if a date part is defined, do not apply windows (to avoid the risk of
375 * having a non-intersected date frame). A good improvement would be to
376 * accept if they intersect */
377 if (!strstr(mdata->db_query, "date:") &&
378 windowed_query_from_query(mdata->db_query, buf, sizeof(buf)))
379 {
380 mutt_str_replace(&mdata->db_query, buf);
381 }
382
383 mutt_debug(LL_DEBUG2, "nm: query (windowed) '%s'\n", mdata->db_query);
384 }
385 else
386 mutt_debug(LL_DEBUG2, "nm: query '%s'\n", mdata->db_query);
387
388 return mdata->db_query;
389}
#define mutt_error(...)
Definition: logging.h:87
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
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:269
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 396 of file notmuch.c.

397{
398 return mdata ? mdata->db_limit : 0;
399}
+ 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 405 of file notmuch.c.

406{
407 const char *const c_nm_exclude_tags = cs_subset_string(NeoMutt->sub, "nm_exclude_tags");
408 if (!c_nm_exclude_tags || !query)
409 return;
410
411 struct TagArray tags = nm_tag_str_to_tags(c_nm_exclude_tags);
412
413 char **tag = NULL;
414 ARRAY_FOREACH(tag, &tags.tags)
415 {
416 mutt_debug(LL_DEBUG2, "nm: query exclude tag '%s'\n", *tag);
417 notmuch_query_add_tag_exclude(query, *tag);
418 }
419
420 notmuch_query_set_omit_excluded(query, 1);
422}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
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 431 of file notmuch.c.

432{
433 struct NmMboxData *mdata = nm_mdata_get(m);
434 if (!mdata)
435 return NULL;
436
437 notmuch_database_t *db = nm_db_get(m, writable);
438 const char *str = get_query_string(mdata, true);
439
440 if (!db || !str)
441 goto err;
442
443 notmuch_query_t *q = notmuch_query_create(db, str);
444 if (!q)
445 goto err;
446
448 notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
449 mutt_debug(LL_DEBUG2, "nm: query successfully initialized (%s)\n", str);
450 return q;
451err:
452 nm_db_release(m);
453 return NULL;
454}
notmuch_database_t * nm_db_get(struct Mailbox *m, bool writable)
Get the Notmuch database.
Definition: db.c:198
int nm_db_release(struct Mailbox *m)
Close the Notmuch database.
Definition: db.c:222
struct NmMboxData * nm_mdata_get(struct Mailbox *m)
Get the Notmuch Mailbox data.
Definition: mdata.c:97
static char * get_query_string(struct NmMboxData *mdata, bool window)
Builds the notmuch vfolder search string.
Definition: notmuch.c:334
static void apply_exclude_tags(notmuch_query_t *query)
Exclude the configured tags.
Definition: notmuch.c:405
+ Here is the call graph for this function:
+ Here is the caller 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 463 of file notmuch.c.

464{
465 struct NmEmailData *edata = nm_edata_get(e);
466 char *new_tags = NULL;
467 char *old_tags = NULL;
468
469 mutt_debug(LL_DEBUG2, "nm: tags update requested (%s)\n", edata->virtual_id);
470
471 for (notmuch_tags_t *tags = notmuch_message_get_tags(msg);
472 tags && notmuch_tags_valid(tags); notmuch_tags_move_to_next(tags))
473 {
474 const char *t = notmuch_tags_get(tags);
475 if (!t || (*t == '\0'))
476 continue;
477
478 mutt_str_append_item(&new_tags, t, ' ');
479 }
480
481 old_tags = driver_tags_get(&e->tags);
482
483 if (new_tags && old_tags && (strcmp(old_tags, new_tags) == 0))
484 {
485 FREE(&old_tags);
486 FREE(&new_tags);
487 mutt_debug(LL_DEBUG2, "nm: tags unchanged\n");
488 return 1;
489 }
490 FREE(&old_tags);
491
492 /* new version */
493 driver_tags_replace(&e->tags, new_tags);
494 FREE(&new_tags);
495
496 new_tags = driver_tags_get_transformed(&e->tags);
497 mutt_debug(LL_DEBUG2, "nm: new tags: '%s'\n", new_tags);
498 FREE(&new_tags);
499
500 new_tags = driver_tags_get(&e->tags);
501 mutt_debug(LL_DEBUG2, "nm: new tag transforms: '%s'\n", new_tags);
502 FREE(&new_tags);
503
504 return 0;
505}
void mutt_str_append_item(char **str, const char *item, char sep)
Add string to another separated by sep.
Definition: string.c:346
struct TagList tags
For drivers that support server tagging.
Definition: email.h:70
char * driver_tags_get_transformed(struct TagList *list)
Get transformed tags.
Definition: tags.c:133
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:145
bool driver_tags_replace(struct TagList *head, const char *tags)
Replace all tags.
Definition: tags.c:186
+ 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 514 of file notmuch.c.

515{
516 struct NmEmailData *edata = nm_edata_get(e);
517
518 mutt_debug(LL_DEBUG2, "nm: path update requested path=%s, (%s)\n", path, edata->virtual_id);
519
520 char *p = strrchr(path, '/');
521 if (p && ((p - path) > 3) &&
522 (mutt_strn_equal(p - 3, "cur", 3) || mutt_strn_equal(p - 3, "new", 3) ||
523 mutt_strn_equal(p - 3, "tmp", 3)))
524 {
525 edata->type = MUTT_MAILDIR;
526
527 FREE(&e->path);
528 FREE(&edata->folder);
529
530 p -= 3; /* skip subfolder (e.g. "new") */
531 if (cs_subset_bool(NeoMutt->sub, "mark_old"))
532 {
533 e->old = mutt_str_startswith(p, "cur");
534 }
535 e->path = mutt_str_dup(p);
536
537 for (; (p > path) && (*(p - 1) == '/'); p--)
538 ; // do nothing
539
540 edata->folder = mutt_strn_dup(path, p - path);
541
542 mutt_debug(LL_DEBUG2, "nm: folder='%s', file='%s'\n", edata->folder, e->path);
543 return 0;
544 }
545
546 return 1;
547}
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:451
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
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:496
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
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 555 of file notmuch.c.

556{
557 char *p = strrchr(path, '/');
558
559 if (p && ((p - path) > 3) &&
560 (mutt_strn_equal(p - 3, "cur", 3) || mutt_strn_equal(p - 3, "new", 3) ||
561 mutt_strn_equal(p - 3, "tmp", 3)))
562 {
563 p -= 3;
564 for (; (p > path) && (*(p - 1) == '/'); p--)
565 ; // do nothing
566
567 return mutt_strn_dup(path, p - path);
568 }
569
570 return NULL;
571}
+ 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 580 of file notmuch.c.

581{
582 size_t sz;
583 char *mid = NULL;
584
585 if (!id)
586 return NULL;
587 sz = strlen(id) + 3;
588 mid = mutt_mem_malloc(sz);
589
590 snprintf(mid, sz, "<%s>", id);
591 return mid;
592}
+ 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 602 of file notmuch.c.

603{
604 if (nm_edata_get(e))
605 return 0;
606
607 struct NmEmailData *edata = nm_edata_new();
608 e->nm_edata = edata;
609
610 /* Notmuch ensures that message Id exists (if not notmuch Notmuch will
611 * generate an ID), so it's more safe than use neomutt Email->env->id */
612 const char *id = notmuch_message_get_message_id(msg);
613 edata->virtual_id = mutt_str_dup(id);
614
615 mutt_debug(LL_DEBUG2, "nm: [e=%p, edata=%p] (%s)\n", (void *) e, (void *) edata, id);
616
617 char *nm_msg_id = nm2mutt_message_id(id);
618 if (!e->env->message_id)
619 {
620 e->env->message_id = nm_msg_id;
621 }
622 else if (!mutt_str_equal(e->env->message_id, nm_msg_id))
623 {
624 FREE(&e->env->message_id);
625 e->env->message_id = nm_msg_id;
626 }
627 else
628 {
629 FREE(&nm_msg_id);
630 }
631
632 if (update_message_path(e, path) != 0)
633 return -1;
634
635 update_email_tags(e, msg);
636
637 return 0;
638}
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
struct NmEmailData * nm_edata_new(void)
Create a new NmEmailData for an email.
Definition: edata.c:61
static int update_message_path(struct Email *e, const char *path)
Set the path for a message.
Definition: notmuch.c:514
static char * nm2mutt_message_id(const char *id)
Converts notmuch message Id to neomutt message Id.
Definition: notmuch.c:580
static int update_email_tags(struct Email *e, notmuch_message_t *msg)
Update the Email's tags from Notmuch.
Definition: notmuch.c:463
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 646 of file notmuch.c.

647{
648 const char *name = NULL;
649
650 for (notmuch_filenames_t *ls = notmuch_message_get_filenames(msg);
651 ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
652 {
653 name = notmuch_filenames_get(ls);
654 }
655
656 return name;
657}
+ 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 663 of file notmuch.c.

664{
665 if (!m->verbose)
666 return;
667
668 struct NmMboxData *mdata = nm_mdata_get(m);
669 if (!mdata)
670 return;
671
672 mdata->oldmsgcount = m->msg_count;
673 mdata->ignmsgcount = 0;
674 mdata->progress = progress_new(_("Reading messages..."), MUTT_PROGRESS_READ,
675 mdata->oldmsgcount);
676}
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:49
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:118
int msg_count
Total number of messages.
Definition: mailbox.h:88
bool verbose
Display status messages?
Definition: mailbox.h:114
+ 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 682 of file notmuch.c.

683{
684 struct NmMboxData *mdata = nm_mdata_get(m);
685
686 if (!m->verbose || !mdata || !mdata->progress)
687 return;
688
689 progress_update(mdata->progress, m->msg_count + mdata->ignmsgcount, -1);
690}
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
+ 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 699 of file notmuch.c.

700{
701 if (!m || !msg)
702 return NULL;
703
704 const char *id = notmuch_message_get_message_id(msg);
705 if (!id)
706 return NULL;
707
708 mutt_debug(LL_DEBUG2, "nm: neomutt email, id='%s'\n", id);
709
710 if (!m->id_hash)
711 {
712 mutt_debug(LL_DEBUG2, "nm: init hash\n");
714 if (!m->id_hash)
715 return NULL;
716 }
717
718 char *mid = nm2mutt_message_id(id);
719 mutt_debug(LL_DEBUG2, "nm: neomutt id='%s'\n", mid);
720
721 struct Email *e = mutt_hash_find(m->id_hash, mid);
722 FREE(&mid);
723 return e;
724}
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:1651
The envelope/body of an email.
Definition: email.h:37
struct HashTable * id_hash
Hash Table by msg id.
Definition: mailbox.h:123
+ 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 733 of file notmuch.c.

735{
736 struct NmMboxData *mdata = nm_mdata_get(m);
737 if (!mdata)
738 return;
739
740 char *newpath = NULL;
741 struct Email *e = NULL;
742
743 /* deduplicate */
744 if (dedup && get_mutt_email(m, msg))
745 {
746 mdata->ignmsgcount++;
748 mutt_debug(LL_DEBUG2, "nm: ignore id=%s, already in the m\n",
749 notmuch_message_get_message_id(msg));
750 return;
751 }
752
753 const char *path = get_message_last_filename(msg);
754 if (!path)
755 return;
756
757 mutt_debug(LL_DEBUG2, "nm: appending message, i=%d, id=%s, path=%s\n",
758 m->msg_count, notmuch_message_get_message_id(msg), path);
759
760 if (m->msg_count >= m->email_max)
761 {
762 mutt_debug(LL_DEBUG2, "nm: allocate mx memory\n");
764 }
765
766#ifdef USE_HCACHE
768 if (!e)
769#endif
770 {
771 if (access(path, F_OK) == 0)
772 {
773 /* We pass is_old=false as argument here, but e->old will be updated later
774 * by update_message_path() (called by init_email() below). */
775 e = maildir_parse_message(MUTT_MAILDIR, path, false, NULL);
776 }
777 else
778 {
779 /* maybe moved try find it... */
780 char *folder = get_folder_from_path(path);
781
782 if (folder)
783 {
784 FILE *fp = maildir_open_find_message(folder, path, &newpath);
785 if (fp)
786 {
787 e = maildir_parse_stream(MUTT_MAILDIR, fp, newpath, false, NULL);
788 mutt_file_fclose(&fp);
789
790 mutt_debug(LL_DEBUG1, "nm: not up-to-date: %s -> %s\n", path, newpath);
791 }
792 }
793 FREE(&folder);
794 }
795
796 if (!e)
797 {
798 mutt_debug(LL_DEBUG1, "nm: failed to parse message: %s\n", path);
799 goto done;
800 }
801
802#ifdef USE_HCACHE
803 mutt_hcache_store(h, newpath ? newpath : path,
804 mutt_str_len(newpath ? newpath : path), e, 0);
805#endif
806 }
807
808 if (init_email(e, newpath ? newpath : path, msg) != 0)
809 {
810 email_free(&e);
811 mutt_debug(LL_DEBUG1, "nm: failed to append email!\n");
812 goto done;
813 }
814
815 e->active = true;
816 e->index = m->msg_count;
817 mailbox_size_add(m, e);
818 m->emails[m->msg_count] = e;
819 m->msg_count++;
820
821 if (newpath)
822 {
823 /* remember that file has been moved -- nm_mbox_sync() will update the DB */
824 struct NmEmailData *edata = nm_edata_get(e);
825 if (edata)
826 {
827 mutt_debug(LL_DEBUG1, "nm: remember obsolete path: %s\n", path);
828 edata->oldpath = mutt_str_dup(path);
829 }
830 }
832done:
833 FREE(&newpath);
834}
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:152
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:562
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:466
@ 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:237
FILE * maildir_open_find_message(const char *folder, const char *msg, char **newname)
Find a new.
Definition: maildir.c:994
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:927
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:880
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1219
static int init_email(struct Email *e, const char *path, notmuch_message_t *msg)
Set up an email's Notmuch data.
Definition: notmuch.c:602
static const char * get_message_last_filename(notmuch_message_t *msg)
Get a message's last filename.
Definition: notmuch.c:646
static char * get_folder_from_path(const char *path)
Find an email's folder from its path.
Definition: notmuch.c:555
static void nm_progress_update(struct Mailbox *m)
Update the progress counter.
Definition: notmuch.c:682
static struct Email * get_mutt_email(struct Mailbox *m, notmuch_message_t *msg)
Get the Email of a Notmuch message.
Definition: notmuch.c:699
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:97
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
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 846 of file notmuch.c.

848{
849 notmuch_messages_t *msgs = NULL;
850
851 for (msgs = notmuch_message_get_replies(top); notmuch_messages_valid(msgs);
852 notmuch_messages_move_to_next(msgs))
853 {
854 notmuch_message_t *nm = notmuch_messages_get(msgs);
855 append_message(h, m, nm, dedup);
856 /* recurse through all the replies to this message too */
857 append_replies(h, m, q, nm, dedup);
858 notmuch_message_destroy(nm);
859 }
860}
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:846
static void append_message(struct HeaderCache *h, struct Mailbox *m, notmuch_message_t *msg, bool dedup)
Associate a message.
Definition: notmuch.c:733
+ 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 873 of file notmuch.c.

875{
876 notmuch_messages_t *msgs = NULL;
877
878 for (msgs = notmuch_thread_get_toplevel_messages(thread);
879 notmuch_messages_valid(msgs); notmuch_messages_move_to_next(msgs))
880 {
881 notmuch_message_t *nm = notmuch_messages_get(msgs);
882 append_message(h, m, nm, dedup);
883 append_replies(h, m, q, nm, dedup);
884 notmuch_message_destroy(nm);
885 }
886}
+ 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 897 of file notmuch.c.

898{
899 if (!query)
900 return NULL;
901
902 notmuch_messages_t *msgs = NULL;
903
904#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
905 if (notmuch_query_search_messages(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
906 return NULL;
907#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
908 if (notmuch_query_search_messages_st(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
909 return NULL;
910#else
911 msgs = notmuch_query_search_messages(query);
912#endif
913
914 return msgs;
915}
+ 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 925 of file notmuch.c.

926{
927 struct NmMboxData *mdata = nm_mdata_get(m);
928 if (!mdata)
929 return false;
930
931 int limit = get_limit(mdata);
932
933 notmuch_messages_t *msgs = get_messages(q);
934
935 if (!msgs)
936 return false;
937
938 struct HeaderCache *h = nm_hcache_open(m);
939
940 for (; notmuch_messages_valid(msgs) && ((limit == 0) || (m->msg_count < limit));
941 notmuch_messages_move_to_next(msgs))
942 {
943 if (SigInt)
944 {
946 SigInt = false;
947 return false;
948 }
949 notmuch_message_t *nm = notmuch_messages_get(msgs);
950 append_message(h, m, nm, dedup);
951 notmuch_message_destroy(nm);
952 }
953
955 return true;
956}
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:69
static void nm_hcache_close(struct HeaderCache *h)
Close the header cache.
Definition: notmuch.c:123
static int get_limit(struct NmMboxData *mdata)
Get the database limit.
Definition: notmuch.c:396
static struct HeaderCache * nm_hcache_open(struct Mailbox *m)
Open a header cache.
Definition: notmuch.c:109
static notmuch_messages_t * get_messages(notmuch_query_t *query)
Load messages for a query.
Definition: notmuch.c:897
Header cache structure.
Definition: lib.h:87
+ Here is the call graph for this function:
+ Here is the caller 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 967 of file notmuch.c.

968{
969 if (!query)
970 return NULL;
971
972 notmuch_threads_t *threads = NULL;
973#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
974 if (notmuch_query_search_threads(query, &threads) != NOTMUCH_STATUS_SUCCESS)
975 return false;
976#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
977 if (notmuch_query_search_threads_st(query, &threads) != NOTMUCH_STATUS_SUCCESS)
978 return false;
979#else
980 threads = notmuch_query_search_threads(query);
981#endif
982
983 return threads;
984}
+ 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 995 of file notmuch.c.

996{
997 struct NmMboxData *mdata = nm_mdata_get(m);
998 if (!mdata)
999 return false;
1000
1001 notmuch_threads_t *threads = get_threads(q);
1002 if (!threads)
1003 return false;
1004
1005 struct HeaderCache *h = nm_hcache_open(m);
1006
1007 for (; notmuch_threads_valid(threads) && ((limit == 0) || (m->msg_count < limit));
1008 notmuch_threads_move_to_next(threads))
1009 {
1010 if (SigInt)
1011 {
1012 nm_hcache_close(h);
1013 SigInt = false;
1014 return false;
1015 }
1016 notmuch_thread_t *thread = notmuch_threads_get(threads);
1017 append_thread(h, m, q, thread, dedup);
1018 notmuch_thread_destroy(thread);
1019 }
1020
1021 nm_hcache_close(h);
1022 return true;
1023}
static notmuch_threads_t * get_threads(notmuch_query_t *query)
Load threads for a query.
Definition: notmuch.c:967
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:873
+ 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
NULLError occurred

Definition at line 1032 of file notmuch.c.

1033{
1034 notmuch_message_t *msg = NULL;
1035 char *id = email_get_id(e);
1036
1037 mutt_debug(LL_DEBUG2, "nm: find message (%s)\n", id);
1038
1039 if (id && db)
1040 notmuch_database_find_message(db, id, &msg);
1041
1042 return msg;
1043}
static char * email_get_id(struct Email *e)
Get the unique Notmuch Id.
Definition: notmuch.c:208
+ 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 1051 of file notmuch.c.

1052{
1053 const char *possible_match_tag = NULL;
1054 notmuch_tags_t *tags = NULL;
1055
1056 for (tags = notmuch_message_get_tags(msg); notmuch_tags_valid(tags);
1057 notmuch_tags_move_to_next(tags))
1058 {
1059 possible_match_tag = notmuch_tags_get(tags);
1060 if (mutt_str_equal(possible_match_tag, tag))
1061 {
1062 return true;
1063 }
1064 }
1065 return false;
1066}
+ 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 1073 of file notmuch.c.

1074{
1075 const char *new_file = get_message_last_filename(msg);
1076 char old_file[PATH_MAX] = { 0 };
1077 email_get_fullpath(e, old_file, sizeof(old_file));
1078
1079 if (!mutt_str_equal(old_file, new_file))
1080 update_message_path(e, new_file);
1081}
static char * email_get_fullpath(struct Email *e, char *buf, size_t buflen)
Get the full path of an email.
Definition: notmuch.c:224
+ Here is the call graph for this function:
+ Here is the caller 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 1090 of file notmuch.c.

1091{
1092 if (!tag_str)
1093 return -1;
1094
1095 notmuch_message_freeze(msg);
1096
1098 char **tag_elem = NULL;
1099 ARRAY_FOREACH(tag_elem, &tags.tags)
1100 {
1101 char *tag = *tag_elem;
1102
1103 if (tag[0] == '-')
1104 {
1105 mutt_debug(LL_DEBUG1, "nm: remove tag: '%s'\n", tag + 1);
1106 notmuch_message_remove_tag(msg, tag + 1);
1107 }
1108 else if (tag[0] == '!')
1109 {
1110 mutt_debug(LL_DEBUG1, "nm: toggle tag: '%s'\n", tag + 1);
1111 if (nm_message_has_tag(msg, tag + 1))
1112 {
1113 notmuch_message_remove_tag(msg, tag + 1);
1114 }
1115 else
1116 {
1117 notmuch_message_add_tag(msg, tag + 1);
1118 }
1119 }
1120 else
1121 {
1122 mutt_debug(LL_DEBUG1, "nm: add tag: '%s'\n", (tag[0] == '+') ? tag + 1 : tag);
1123 notmuch_message_add_tag(msg, (tag[0] == '+') ? tag + 1 : tag);
1124 }
1125 }
1126
1127 notmuch_message_thaw(msg);
1129
1130 return 0;
1131}
static bool nm_message_has_tag(notmuch_message_t *msg, char *tag)
Does a message have this tag?
Definition: notmuch.c:1051
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 1144 of file notmuch.c.

1145{
1146 if (!tag_str)
1147 return -1;
1148
1149 const char *const c_nm_unread_tag = cs_subset_string(NeoMutt->sub, "nm_unread_tag");
1150 const char *const c_nm_replied_tag = cs_subset_string(NeoMutt->sub, "nm_replied_tag");
1151 const char *const c_nm_flagged_tag = cs_subset_string(NeoMutt->sub, "nm_flagged_tag");
1152
1154 char **tag_elem = NULL;
1155 ARRAY_FOREACH(tag_elem, &tags.tags)
1156 {
1157 char *tag = *tag_elem;
1158
1159 if (tag[0] == '-')
1160 {
1161 tag++;
1162 if (strcmp(tag, c_nm_unread_tag) == 0)
1163 mutt_set_flag(m, e, MUTT_READ, true);
1164 else if (strcmp(tag, c_nm_replied_tag) == 0)
1165 mutt_set_flag(m, e, MUTT_REPLIED, false);
1166 else if (strcmp(tag, c_nm_flagged_tag) == 0)
1167 mutt_set_flag(m, e, MUTT_FLAG, false);
1168 }
1169 else
1170 {
1171 tag = (tag[0] == '+') ? tag + 1 : tag;
1172 if (strcmp(tag, c_nm_unread_tag) == 0)
1173 mutt_set_flag(m, e, MUTT_READ, false);
1174 else if (strcmp(tag, c_nm_replied_tag) == 0)
1175 mutt_set_flag(m, e, MUTT_REPLIED, true);
1176 else if (strcmp(tag, c_nm_flagged_tag) == 0)
1177 mutt_set_flag(m, e, MUTT_FLAG, true);
1178 }
1179 }
1180
1182
1183 return 0;
1184}
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:93
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:99
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:92
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:63
+ 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 1196 of file notmuch.c.

1197{
1198 char filename[PATH_MAX] = { 0 };
1199 char suffix[PATH_MAX] = { 0 };
1200 char folder[PATH_MAX] = { 0 };
1201
1202 mutt_str_copy(folder, old, sizeof(folder));
1203 char *p = strrchr(folder, '/');
1204 if (p)
1205 {
1206 *p = '\0';
1207 p++;
1208 }
1209 else
1210 p = folder;
1211
1212 mutt_str_copy(filename, p, sizeof(filename));
1213
1214 /* remove (new,cur,...) from folder path */
1215 p = strrchr(folder, '/');
1216 if (p)
1217 *p = '\0';
1218
1219 /* remove old flags from filename */
1220 p = strchr(filename, ':');
1221 if (p)
1222 *p = '\0';
1223
1224 /* compose new flags */
1225 maildir_gen_flags(suffix, sizeof(suffix), e);
1226
1227 snprintf(buf, buflen, "%s/%s/%s%s", folder,
1228 (e->read || e->old) ? "cur" : "new", filename, suffix);
1229
1230 if (strcmp(old, buf) == 0)
1231 return 1;
1232
1233 if (rename(old, buf) != 0)
1234 {
1235 mutt_debug(LL_DEBUG1, "nm: rename(2) failed %s -> %s\n", old, buf);
1236 return -1;
1237 }
1238
1239 return 0;
1240}
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:652
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 1249 of file notmuch.c.

1250{
1251 struct NmMboxData *mdata = nm_mdata_get(m);
1252 if (!mdata)
1253 return -1;
1254
1255 mutt_debug(LL_DEBUG2, "nm: remove filename '%s'\n", path);
1256
1257 notmuch_database_t *db = nm_db_get(m, true);
1258 if (!db)
1259 return -1;
1260
1261 notmuch_message_t *msg = NULL;
1262 notmuch_status_t st = notmuch_database_find_message_by_filename(db, path, &msg);
1263 if (st || !msg)
1264 return -1;
1265
1266 int trans = nm_db_trans_begin(m);
1267 if (trans < 0)
1268 return -1;
1269
1270 /* note that unlink() is probably unnecessary here, it's already removed
1271 * by mh_sync_mailbox_message(), but for sure... */
1272 notmuch_filenames_t *ls = NULL;
1273 st = notmuch_database_remove_message(db, path);
1274 switch (st)
1275 {
1276 case NOTMUCH_STATUS_SUCCESS:
1277 mutt_debug(LL_DEBUG2, "nm: remove success, call unlink\n");
1278 unlink(path);
1279 break;
1280 case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
1281 mutt_debug(LL_DEBUG2, "nm: remove success (duplicate), call unlink\n");
1282 unlink(path);
1283 for (ls = notmuch_message_get_filenames(msg);
1284 ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
1285 {
1286 path = notmuch_filenames_get(ls);
1287
1288 mutt_debug(LL_DEBUG2, "nm: remove duplicate: '%s'\n", path);
1289 unlink(path);
1290 notmuch_database_remove_message(db, path);
1291 }
1292 break;
1293 default:
1294 mutt_debug(LL_DEBUG1, "nm: failed to remove '%s' [st=%d]\n", path, (int) st);
1295 break;
1296 }
1297
1298 notmuch_message_destroy(msg);
1299 if (trans)
1300 nm_db_trans_end(m);
1301 return 0;
1302}
int nm_db_trans_begin(struct Mailbox *m)
Start a Notmuch database transaction.
Definition: db.c:255
int nm_db_trans_end(struct Mailbox *m)
End a database transaction.
Definition: db.c:277
+ Here is the call graph for this function:
+ Here is the caller 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 1313 of file notmuch.c.

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

1418{
1419 notmuch_query_t *q = notmuch_query_create(db, qstr);
1420 if (!q)
1421 return 0;
1422
1423 unsigned int res = 0;
1424
1426#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
1427 if (notmuch_query_count_messages(q, &res) != NOTMUCH_STATUS_SUCCESS)
1428 res = 0; /* may not be defined on error */
1429#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
1430 if (notmuch_query_count_messages_st(q, &res) != NOTMUCH_STATUS_SUCCESS)
1431 res = 0; /* may not be defined on error */
1432#else
1433 res = notmuch_query_count_messages(q);
1434#endif
1435 notmuch_query_destroy(q);
1436 mutt_debug(LL_DEBUG1, "nm: count '%s', result=%d\n", qstr, res);
1437
1438 if ((limit > 0) && (res > limit))
1439 res = limit;
1440
1441 return res;
1442}
+ Here is the call graph for this function:
+ Here is the caller 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 1450 of file notmuch.c.

1451{
1452 struct NmEmailData *edata = nm_edata_get(e);
1453 if (!edata)
1454 return NULL;
1455
1456 return edata->folder;
1457}
+ 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 1469 of file notmuch.c.

1470{
1471 char *full_folder = nm_email_get_folder(e);
1472 if (!full_folder)
1473 return NULL;
1474
1475 const char *db_path = nm_db_get_filename(m);
1476 if (!db_path)
1477 return NULL;
1478
1479 return full_folder + strlen(db_path);
1480}
const char * nm_db_get_filename(struct Mailbox *m)
Get the filename of the Notmuch database.
Definition: db.c:54
+ 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 1489 of file notmuch.c.

1490{
1491 if (!m)
1492 return -1;
1493
1494 struct NmMboxData *mdata = nm_mdata_get(m);
1495 if (!mdata)
1496 return -1;
1497
1498 notmuch_query_t *q = NULL;
1499 notmuch_database_t *db = NULL;
1500 notmuch_message_t *msg = NULL;
1501 int rc = -1;
1502
1503 if (!(db = nm_db_get(m, false)) || !(msg = get_nm_message(db, e)))
1504 goto done;
1505
1506 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages...[current count=%d]\n",
1507 m->msg_count);
1508
1509 progress_setup(m);
1510 const char *id = notmuch_message_get_thread_id(msg);
1511 if (!id)
1512 goto done;
1513
1514 char *qstr = NULL;
1515 mutt_str_append_item(&qstr, "thread:", '\0');
1516 mutt_str_append_item(&qstr, id, '\0');
1517
1518 q = notmuch_query_create(db, qstr);
1519 FREE(&qstr);
1520 if (!q)
1521 goto done;
1523 notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
1524
1525 read_threads_query(m, q, true, 0);
1527 m->mtime.tv_nsec = 0;
1528 rc = 0;
1529
1530 if (m->msg_count > mdata->oldmsgcount)
1532done:
1533 if (q)
1534 notmuch_query_destroy(q);
1535
1536 nm_db_release(m);
1537
1538 if (m->msg_count == mdata->oldmsgcount)
1539 mutt_message(_("No more messages in the thread"));
1540
1541 mdata->oldmsgcount = 0;
1542 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
1543 rc, m->msg_count);
1544 progress_free(&mdata->progress);
1545 return rc;
1546}
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:222
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:176
static notmuch_message_t * get_nm_message(notmuch_database_t *db, struct Email *e)
Find a Notmuch message.
Definition: notmuch.c:1032
static bool read_threads_query(struct Mailbox *m, notmuch_query_t *q, bool dedup, int limit)
Perform a query with threads.
Definition: notmuch.c:995
static void progress_setup(struct Mailbox *m)
Set up the Progress Bar.
Definition: notmuch.c:663
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:86
struct timespec mtime
Time Mailbox was last changed.
Definition: mailbox.h:104
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 1556 of file notmuch.c.

1557{
1558 mutt_debug(LL_DEBUG2, "(%s)\n", buf);
1559 struct NmMboxData *mdata = nm_mdata_get(m);
1560 char url[PATH_MAX + 1024 + 32]; /* path to DB + query + URL "decoration" */
1561 int added;
1562 bool using_default_data = false;
1563
1564 // No existing data. Try to get a default NmMboxData.
1565 if (!mdata)
1566 {
1568
1569 // Failed to get default data.
1570 if (!mdata)
1571 return NULL;
1572
1573 using_default_data = true;
1574 }
1575
1576 enum NmQueryType c_nm_query_type = nm_string_to_query_type(
1577 cs_subset_string(NeoMutt->sub, "nm_query_type"));
1578 mdata->query_type = nm_parse_type_from_query(buf, c_nm_query_type);
1579
1580 const short c_nm_db_limit = cs_subset_number(NeoMutt->sub, "nm_db_limit");
1581 if (get_limit(mdata) == c_nm_db_limit)
1582 {
1583 added = snprintf(url, sizeof(url), "%s%s?type=%s&query=", NmUrlProtocol,
1585 }
1586 else
1587 {
1588 added = snprintf(url, sizeof(url), "%s%s?type=%s&limit=%d&query=", NmUrlProtocol,
1591 }
1592
1593 if (added >= sizeof(url))
1594 {
1595 // snprintf output was truncated, so can't create URL
1596 return NULL;
1597 }
1598
1599 url_pct_encode(&url[added], sizeof(url) - added, buf);
1600
1601 mutt_str_copy(buf, url, buflen);
1602 buf[buflen - 1] = '\0';
1603
1604 if (using_default_data)
1605 nm_mdata_free((void **) &mdata);
1606
1607 mutt_debug(LL_DEBUG1, "nm: url from query '%s'\n", buf);
1608 return buf;
1609}
static struct NmMboxData * nm_get_default_data(void)
Create a Mailbox with default Notmuch settings.
Definition: notmuch.c:163
const char NmUrlProtocol[]
Definition: notmuch.c:93
enum NmQueryType nm_parse_type_from_query(char *buf, enum NmQueryType fallback)
Parse a query type out of a query.
Definition: query.c:49
const char * nm_query_type_to_string(enum NmQueryType query_type)
Turn a query type into a string.
Definition: query.c:96
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 1615 of file notmuch.c.

1616{
1617 const short c_nm_query_window_duration = cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
1618 const bool c_nm_query_window_enable = cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
1619
1620 return c_nm_query_window_enable || (c_nm_query_window_duration > 0);
1621}
+ 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 1632 of file notmuch.c.

1633{
1634 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1635 if (c_nm_query_window_current_position != 0)
1636 {
1637 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1638 c_nm_query_window_current_position - 1, NULL);
1639 }
1640
1641 mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position - 1);
1642}
+ 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 1652 of file notmuch.c.

1653{
1654 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1655 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1656 c_nm_query_window_current_position + 1, NULL);
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_reset()

void nm_query_window_reset ( void  )

Resets the vfolder window position to the present.

Definition at line 1663 of file notmuch.c.

1664{
1665 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position", 0, NULL);
1666 mutt_debug(LL_DEBUG2, "Reset nm_query_window_current_position to 0\n");
1667}
+ 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 1675 of file notmuch.c.

1676{
1677 struct NmMboxData *mdata = nm_mdata_get(m);
1678 notmuch_database_t *db = nm_db_get(m, false);
1679 char *orig_str = get_query_string(mdata, true);
1680
1681 if (!db || !orig_str)
1682 return false;
1683
1684 char *new_str = NULL;
1685 bool rc = false;
1686 if (mutt_str_asprintf(&new_str, "id:%s and (%s)", email_get_id(e), orig_str) < 0)
1687 return false;
1688
1689 mutt_debug(LL_DEBUG2, "nm: checking if message is still queried: %s\n", new_str);
1690
1691 notmuch_query_t *q = notmuch_query_create(db, new_str);
1692
1693 switch (mdata->query_type)
1694 {
1695 case NM_QUERY_TYPE_UNKNOWN: // UNKNOWN should never occur, but MESGS is default
1697 {
1698 notmuch_messages_t *messages = get_messages(q);
1699
1700 if (!messages)
1701 return false;
1702
1703 rc = notmuch_messages_valid(messages);
1704 notmuch_messages_destroy(messages);
1705 break;
1706 }
1708 {
1709 notmuch_threads_t *threads = get_threads(q);
1710
1711 if (!threads)
1712 return false;
1713
1714 rc = notmuch_threads_valid(threads);
1715 notmuch_threads_destroy(threads);
1716 break;
1717 }
1718 }
1719
1720 notmuch_query_destroy(q);
1721
1722 mutt_debug(LL_DEBUG2, "nm: checking if message is still queried: %s = %s\n",
1723 new_str, rc ? "true" : "false");
1724
1725 return rc;
1726}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1031
@ 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 1737 of file notmuch.c.

1739{
1740 char buf[PATH_MAX] = { 0 };
1741 struct NmMboxData *mdata = nm_mdata_get(m);
1742 if (!mdata || !new_file)
1743 return -1;
1744
1745 if (!old_file && nm_edata_get(e))
1746 {
1747 email_get_fullpath(e, buf, sizeof(buf));
1748 old_file = buf;
1749 }
1750
1751 int rc = rename_filename(m, old_file, new_file, e);
1752
1753 nm_db_release(m);
1755 m->mtime.tv_nsec = 0;
1756 return rc;
1757}
static int rename_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Rename the file.
Definition: notmuch.c:1313
+ Here is the call graph for this function:
+ 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 1846 of file notmuch.c.

1847{
1848 // Create a new notmuch mailbox from scratch and add plumbing for DB access.
1849 char *default_url = nm_get_default_url();
1850 struct Mailbox *m = mx_path_resolve(default_url);
1851
1852 FREE(&default_url);
1853
1854 // These are no-ops for an initialized mailbox.
1855 init_mailbox(m);
1856 mx_mbox_ac_link(m);
1857
1858 return m;
1859}
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:267
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
static int init_mailbox(struct Mailbox *m)
Add Notmuch data to the Mailbox.
Definition: notmuch.c:186
A mailbox.
Definition: mailbox.h:79
+ 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 1869 of file notmuch.c.

1870{
1871 notmuch_database_t *db = NULL;
1872 notmuch_status_t st;
1873 notmuch_message_t *msg = NULL;
1874 int rc = -1;
1875
1876 struct NmMboxData *mdata = nm_mdata_get(m);
1877
1878 // If no notmuch data, fall back to the default mailbox.
1879 //
1880 // IMPORTANT: DO NOT FREE THIS MAILBOX. Two reasons:
1881 // 1) If user has default mailbox in config, we'll be removing it. That's not
1882 // good program behavior!
1883 // 2) If not in user's config, keep mailbox around for future nm_record calls.
1884 // It saves NeoMutt from allocating/deallocating repeatedly.
1885 if (!mdata)
1886 {
1887 mutt_debug(LL_DEBUG1, "nm: non-nm mailbox. trying the default nm mailbox.");
1888 m = get_default_mailbox();
1889 mdata = nm_mdata_get(m);
1890 }
1891
1892 if (!path || !mdata || (access(path, F_OK) != 0))
1893 return 0;
1894 db = nm_db_get(m, true);
1895 if (!db)
1896 return -1;
1897
1898 mutt_debug(LL_DEBUG1, "nm: record message: %s\n", path);
1899 int trans = nm_db_trans_begin(m);
1900 if (trans < 0)
1901 goto done;
1902
1903#if LIBNOTMUCH_CHECK_VERSION(5, 1, 0)
1904 st = notmuch_database_index_file(db, path, NULL, &msg);
1905#else
1906 st = notmuch_database_add_message(db, path, &msg);
1907#endif
1908
1909 if ((st != NOTMUCH_STATUS_SUCCESS) && (st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID))
1910 {
1911 mutt_debug(LL_DEBUG1, "nm: failed to add '%s' [st=%d]\n", path, (int) st);
1912 goto done;
1913 }
1914
1915 if ((st == NOTMUCH_STATUS_SUCCESS) && msg)
1916 {
1917 notmuch_message_maildir_flags_to_tags(msg);
1918 if (e)
1919 {
1920 char *tags = driver_tags_get(&e->tags);
1921 update_tags(msg, tags);
1922 FREE(&tags);
1923 }
1924 const char *const c_nm_record_tags = cs_subset_string(NeoMutt->sub, "nm_record_tags");
1925 if (c_nm_record_tags)
1926 update_tags(msg, c_nm_record_tags);
1927 }
1928
1929 rc = 0;
1930done:
1931 if (msg)
1932 notmuch_message_destroy(msg);
1933 if (trans == 1)
1934 nm_db_trans_end(m);
1935
1936 nm_db_release(m);
1937
1938 return rc;
1939}
static struct Mailbox * get_default_mailbox(void)
Get Mailbox for notmuch without any parameters.
Definition: notmuch.c:1846
+ 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,
const 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 1951 of file notmuch.c.

1952{
1953 struct NmMboxData *mdata = nm_mdata_get(m);
1954 if (!mdata)
1955 return -1;
1956
1957 notmuch_database_t *db = NULL;
1958 notmuch_tags_t *tags = NULL;
1959 const char *tag = NULL;
1960 int rc = -1;
1961
1962 if (!(db = nm_db_get(m, false)) || !(tags = notmuch_database_get_all_tags(db)))
1963 goto done;
1964
1965 *tag_count = 0;
1966 mutt_debug(LL_DEBUG1, "nm: get all tags\n");
1967
1968 while (notmuch_tags_valid(tags))
1969 {
1970 tag = notmuch_tags_get(tags);
1971 /* Skip empty string */
1972 if (*tag)
1973 {
1974 if (tag_list)
1975 tag_list[*tag_count] = mutt_str_dup(tag);
1976 (*tag_count)++;
1977 }
1978 notmuch_tags_move_to_next(tags);
1979 }
1980
1981 rc = 0;
1982done:
1983 if (tags)
1984 notmuch_tags_destroy(tags);
1985
1986 nm_db_release(m);
1987
1988 mutt_debug(LL_DEBUG1, "nm: get all tags done [rc=%d tag_count=%u]\n", rc, *tag_count);
1989 return rc;
1990}
+ 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 86 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.