NeoMutt  2023-05-17-56-ga67199
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 "commands.h"
#include "edata.h"
#include "globals.h"
#include "maildir/edata.h"
#include "mdata.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, struct Email *e)
 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 NmCommands []
 Notmuch Commands. More...
 
const char NmUrlProtocol [] = "notmuch://"
 Protocol string for Notmuch URLs. More...
 
const int NmUrlProtocolLen = sizeof(NmUrlProtocol) - 1
 Length of NmUrlProtocol string. More...
 
const 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 100 of file notmuch.c.

101{
103}
void commands_register(const struct Command *cmds, const size_t num_cmds)
Add commands to Commands array.
Definition: command.c:53
#define mutt_array_size(x)
Definition: memory.h:36
static const struct Command NmCommands[]
Notmuch Commands.
Definition: notmuch.c:85
+ Here is the call graph for this function:
+ 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 110 of file notmuch.c.

111{
112#ifdef USE_HCACHE
113 const char *const c_header_cache = 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}
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:379
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:209
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:489
+ 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 = cs_subset_string(NeoMutt->sub, "nm_default_url");
145 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
146 if (c_nm_default_url)
147 {
148 snprintf(url, len, "%s", c_nm_default_url);
149 }
150 else if (c_folder)
151 {
152 snprintf(url, len, "notmuch://%s", c_folder);
153 }
154 else
155 {
156 FREE(&url);
157 return NULL;
158 }
159
160 return url;
161}
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:41
+ 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 168 of file notmuch.c.

169{
170 // path to DB + query + url "decoration"
171 char *url = nm_get_default_url();
172 if (!url)
173 return NULL;
174
175 struct NmMboxData *default_data = nm_mdata_new(url);
176 FREE(&url);
177
178 return default_data;
179}
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 191 of file notmuch.c.

192{
193 if (!m || (m->type != MUTT_NOTMUCH))
194 return -1;
195
196 if (m->mdata)
197 return 0;
198
200 if (!m->mdata)
201 return -1;
202
204 return 0;
205}
@ 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:141
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 213 of file notmuch.c.

214{
215 struct NmEmailData *edata = nm_edata_get(e);
216 if (!edata)
217 return NULL;
218
219 return edata->virtual_id;
220}
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 229 of file notmuch.c.

230{
231 snprintf(buf, buflen, "%s/%s", nm_email_get_folder(e), e->path);
232 return buf;
233}
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1458
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 244 of file notmuch.c.

245{
246 mutt_debug(LL_DEBUG2, "entering\n");
247 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position", 0, NULL);
248}
#define mutt_debug(LEVEL,...)
Definition: logging2.h:87
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
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:310
+ 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 274 of file notmuch.c.

275{
276 mutt_debug(LL_DEBUG2, "nm: %s\n", query);
277
278 const bool c_nm_query_window_enable = cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
279 const short c_nm_query_window_duration = cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
280 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
281 const char *const c_nm_query_window_current_search = cs_subset_string(NeoMutt->sub, "nm_query_window_current_search");
282 const char *const c_nm_query_window_timebase = cs_subset_string(NeoMutt->sub, "nm_query_window_timebase");
283 const char *const c_nm_query_window_or_terms = cs_subset_string(NeoMutt->sub, "nm_query_window_or_terms");
284
285 /* if the query has changed, reset the window position */
286 if (!c_nm_query_window_current_search || !mutt_str_equal(query, c_nm_query_window_current_search))
287 {
289 }
290
292 buf, buflen, c_nm_query_window_enable, c_nm_query_window_duration,
293 c_nm_query_window_current_position, c_nm_query_window_current_search,
294 c_nm_query_window_timebase, c_nm_query_window_or_terms);
295
296 switch (rc)
297 {
299 {
300 mutt_debug(LL_DEBUG2, "nm: %s -> %s\n", query, buf);
301 break;
302 }
304 {
306 return false;
307 }
309 {
311 // L10N: The values 'hour', 'day', 'week', 'month', 'year' are literal.
312 // They should not be translated.
313 _("Invalid nm_query_window_timebase value (valid values are: hour, day, week, month, year)"));
314 mutt_debug(LL_DEBUG2, "Invalid nm_query_window_timebase value\n");
315 return false;
316 }
317 }
318
319 return true;
320}
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: logging2.h:89
#define _(a)
Definition: message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
static void query_window_reset(void)
Restore vfolder's search window to its original position.
Definition: notmuch.c:244
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:205
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 338 of file notmuch.c.

339{
340 mutt_debug(LL_DEBUG2, "nm: %s\n", window ? "true" : "false");
341
342 if (!mdata)
343 return NULL;
344 if (mdata->db_query && !window)
345 return mdata->db_query;
346
347 const char *const c_nm_query_type = cs_subset_string(NeoMutt->sub, "nm_query_type");
348 mdata->query_type = nm_string_to_query_type(c_nm_query_type); /* user's default */
349
350 struct UrlQuery *item = NULL;
351 STAILQ_FOREACH(item, &mdata->db_url->query_strings, entries)
352 {
353 if (!item->value || !item->name)
354 continue;
355
356 if (mutt_str_equal(item->name, "limit"))
357 {
358 if (!mutt_str_atoi_full(item->value, &mdata->db_limit))
359 {
360 mutt_error(_("failed to parse notmuch limit: %s"), item->value);
361 }
362 }
363 else if (mutt_str_equal(item->name, "type"))
364 {
366 }
367 else if (mutt_str_equal(item->name, "query"))
368 {
369 mutt_str_replace(&mdata->db_query, item->value);
370 }
371 }
372
373 if (!mdata->db_query)
374 return NULL;
375
376 if (window)
377 {
378 char buf[1024] = { 0 };
379 cs_subset_str_string_set(NeoMutt->sub, "nm_query_window_current_search",
380 mdata->db_query, NULL);
381
382 /* if a date part is defined, do not apply windows (to avoid the risk of
383 * having a non-intersected date frame). A good improvement would be to
384 * accept if they intersect */
385 if (!strstr(mdata->db_query, "date:") &&
386 windowed_query_from_query(mdata->db_query, buf, sizeof(buf)))
387 {
388 mutt_str_replace(&mdata->db_query, buf);
389 }
390
391 mutt_debug(LL_DEBUG2, "nm: query (windowed) '%s'\n", mdata->db_query);
392 }
393 else
394 {
395 mutt_debug(LL_DEBUG2, "nm: query '%s'\n", mdata->db_query);
396 }
397
398 return mdata->db_query;
399}
#define mutt_error(...)
Definition: logging2.h:90
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
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:274
enum NmQueryType nm_string_to_query_type(const char *str)
Lookup a query type.
Definition: query.c:109
#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:413
+ 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 = cs_subset_string(NeoMutt->sub, "nm_exclude_tags");
418 if (!c_nm_exclude_tags || !query)
419 return;
420
421 struct TagArray tags = nm_tag_str_to_tags(c_nm_exclude_tags);
422
423 char **tag = NULL;
424 ARRAY_FOREACH(tag, &tags.tags)
425 {
426 mutt_debug(LL_DEBUG2, "nm: query exclude tag '%s'\n", *tag);
427 notmuch_query_add_tag_exclude(query, *tag);
428 }
429
430 notmuch_query_set_omit_excluded(query, 1);
432}
#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 441 of file notmuch.c.

442{
443 struct NmMboxData *mdata = nm_mdata_get(m);
444 if (!mdata)
445 return NULL;
446
447 notmuch_database_t *db = nm_db_get(m, writable);
448 const char *str = get_query_string(mdata, true);
449
450 if (!db || !str)
451 goto err;
452
453 notmuch_query_t *q = notmuch_query_create(db, str);
454 if (!q)
455 goto err;
456
458 notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
459 mutt_debug(LL_DEBUG2, "nm: query successfully initialized (%s)\n", str);
460 return q;
461err:
462 nm_db_release(m);
463 return NULL;
464}
notmuch_database_t * nm_db_get(struct Mailbox *m, bool writable)
Get the Notmuch database.
Definition: db.c:200
int nm_db_release(struct Mailbox *m)
Close the Notmuch database.
Definition: db.c:224
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:338
static void apply_exclude_tags(notmuch_query_t *query)
Exclude the configured tags.
Definition: notmuch.c:415
+ 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 473 of file notmuch.c.

474{
475 struct NmEmailData *edata = nm_edata_get(e);
476 char *new_tags = NULL;
477 char *old_tags = NULL;
478
479 mutt_debug(LL_DEBUG2, "nm: tags update requested (%s)\n", edata->virtual_id);
480
481 for (notmuch_tags_t *tags = notmuch_message_get_tags(msg);
482 tags && notmuch_tags_valid(tags); notmuch_tags_move_to_next(tags))
483 {
484 const char *t = notmuch_tags_get(tags);
485 if (!t || (*t == '\0'))
486 continue;
487
488 mutt_str_append_item(&new_tags, t, ' ');
489 }
490
491 old_tags = driver_tags_get(&e->tags);
492
493 if (new_tags && old_tags && (mutt_str_equal(old_tags, new_tags)))
494 {
495 FREE(&old_tags);
496 FREE(&new_tags);
497 mutt_debug(LL_DEBUG2, "nm: tags unchanged\n");
498 return 1;
499 }
500 FREE(&old_tags);
501
502 /* new version */
503 driver_tags_replace(&e->tags, new_tags);
504 FREE(&new_tags);
505
506 new_tags = driver_tags_get_transformed(&e->tags);
507 mutt_debug(LL_DEBUG2, "nm: new tags: '%s'\n", new_tags);
508 FREE(&new_tags);
509
510 new_tags = driver_tags_get(&e->tags);
511 mutt_debug(LL_DEBUG2, "nm: new tag transforms: '%s'\n", new_tags);
512 FREE(&new_tags);
513
514 return 0;
515}
void mutt_str_append_item(char **str, const char *item, char sep)
Add string to another separated by sep.
Definition: string.c:347
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 524 of file notmuch.c.

525{
526 struct NmEmailData *edata = nm_edata_get(e);
527
528 mutt_debug(LL_DEBUG2, "nm: path update requested path=%s, (%s)\n", path, edata->virtual_id);
529
530 char *p = strrchr(path, '/');
531 if (p && ((p - path) > 3) &&
532 (mutt_strn_equal(p - 3, "cur", 3) || mutt_strn_equal(p - 3, "new", 3) ||
533 mutt_strn_equal(p - 3, "tmp", 3)))
534 {
535 edata->type = MUTT_MAILDIR;
536
537 FREE(&e->path);
538 FREE(&edata->folder);
539
540 p -= 3; /* skip subfolder (e.g. "new") */
541 if (cs_subset_bool(NeoMutt->sub, "mark_old"))
542 {
543 e->old = mutt_str_startswith(p, "cur");
544 }
545 e->path = mutt_str_dup(p);
546
547 for (; (p > path) && (*(p - 1) == '/'); p--)
548 ; // do nothing
549
550 edata->folder = mutt_strn_dup(path, p - path);
551
552 mutt_debug(LL_DEBUG2, "nm: folder='%s', file='%s'\n", edata->folder, e->path);
553 return 0;
554 }
555
556 return 1;
557}
@ 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:452
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
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:497
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:228
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 565 of file notmuch.c.

566{
567 char *p = strrchr(path, '/');
568
569 if (p && ((p - path) > 3) &&
570 (mutt_strn_equal(p - 3, "cur", 3) || mutt_strn_equal(p - 3, "new", 3) ||
571 mutt_strn_equal(p - 3, "tmp", 3)))
572 {
573 p -= 3;
574 for (; (p > path) && (*(p - 1) == '/'); p--)
575 ; // do nothing
576
577 return mutt_strn_dup(path, p - path);
578 }
579
580 return NULL;
581}
+ 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 590 of file notmuch.c.

591{
592 size_t sz;
593 char *mid = NULL;
594
595 if (!id)
596 return NULL;
597 sz = strlen(id) + 3;
598 mid = mutt_mem_malloc(sz);
599
600 snprintf(mid, sz, "<%s>", id);
601 return mid;
602}
+ 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 612 of file notmuch.c.

613{
614 if (nm_edata_get(e))
615 return 0;
616
617 struct NmEmailData *edata = nm_edata_new();
618 e->nm_edata = edata;
619
620 /* Notmuch ensures that message Id exists (if not notmuch Notmuch will
621 * generate an ID), so it's more safe than use neomutt Email->env->id */
622 const char *id = notmuch_message_get_message_id(msg);
623 edata->virtual_id = mutt_str_dup(id);
624
625 mutt_debug(LL_DEBUG2, "nm: [e=%p, edata=%p] (%s)\n", (void *) e, (void *) edata, id);
626
627 char *nm_msg_id = nm2mutt_message_id(id);
628 if (!e->env->message_id)
629 {
630 e->env->message_id = nm_msg_id;
631 }
632 else if (!mutt_str_equal(e->env->message_id, nm_msg_id))
633 {
634 FREE(&e->env->message_id);
635 e->env->message_id = nm_msg_id;
636 }
637 else
638 {
639 FREE(&nm_msg_id);
640 }
641
642 if (update_message_path(e, path) != 0)
643 return -1;
644
645 update_email_tags(e, msg);
646
647 return 0;
648}
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:524
static char * nm2mutt_message_id(const char *id)
Converts notmuch message Id to neomutt message Id.
Definition: notmuch.c:590
static int update_email_tags(struct Email *e, notmuch_message_t *msg)
Update the Email's tags from Notmuch.
Definition: notmuch.c:473
void * nm_edata
Notmuch private data.
Definition: email.h:92
+ 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 656 of file notmuch.c.

657{
658 const char *name = NULL;
659
660 for (notmuch_filenames_t *ls = notmuch_message_get_filenames(msg);
661 ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
662 {
663 name = notmuch_filenames_get(ls);
664 }
665
666 return name;
667}
+ 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 673 of file notmuch.c.

674{
675 if (!m->verbose)
676 return;
677
678 struct NmMboxData *mdata = nm_mdata_get(m);
679 if (!mdata)
680 return;
681
682 mdata->oldmsgcount = m->msg_count;
683 mdata->ignmsgcount = 0;
684 mdata->progress = progress_new(_("Reading messages..."), MUTT_PROGRESS_READ,
685 mdata->oldmsgcount);
686}
@ 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:121
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 692 of file notmuch.c.

693{
694 struct NmMboxData *mdata = nm_mdata_get(m);
695
696 if (!m->verbose || !mdata || !mdata->progress)
697 return;
698
699 progress_update(mdata->progress, m->msg_count + mdata->ignmsgcount, -1);
700}
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 709 of file notmuch.c.

710{
711 if (!m || !msg)
712 return NULL;
713
714 const char *id = notmuch_message_get_message_id(msg);
715 if (!id)
716 return NULL;
717
718 mutt_debug(LL_DEBUG2, "nm: neomutt email, id='%s'\n", id);
719
720 if (!m->id_hash)
721 {
722 mutt_debug(LL_DEBUG2, "nm: init hash\n");
724 if (!m->id_hash)
725 return NULL;
726 }
727
728 char *mid = nm2mutt_message_id(id);
729 mutt_debug(LL_DEBUG2, "nm: neomutt id='%s'\n", mid);
730
731 struct Email *e = mutt_hash_find(m->id_hash, mid);
732 FREE(&mid);
733 return e;
734}
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:1696
The envelope/body of an email.
Definition: email.h:37
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
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 743 of file notmuch.c.

745{
746 struct NmMboxData *mdata = nm_mdata_get(m);
747 if (!mdata)
748 return;
749
750 char *newpath = NULL;
751 struct Email *e = NULL;
752
753 /* deduplicate */
754 if (dedup && get_mutt_email(m, msg))
755 {
756 mdata->ignmsgcount++;
758 mutt_debug(LL_DEBUG2, "nm: ignore id=%s, already in the m\n",
759 notmuch_message_get_message_id(msg));
760 return;
761 }
762
763 const char *path = get_message_last_filename(msg);
764 if (!path)
765 return;
766
767 mutt_debug(LL_DEBUG2, "nm: appending message, i=%d, id=%s, path=%s\n",
768 m->msg_count, notmuch_message_get_message_id(msg), path);
769
771
772#ifdef USE_HCACHE
774 if (!e)
775#endif
776 {
777 if (access(path, F_OK) == 0)
778 {
779 /* We pass is_old=false as argument here, but e->old will be updated later
780 * by update_message_path() (called by init_email() below). */
781 e = maildir_parse_message(MUTT_MAILDIR, path, false, NULL);
782 }
783 else
784 {
785 /* maybe moved try find it... */
786 char *folder = get_folder_from_path(path);
787
788 if (folder)
789 {
790 FILE *fp = maildir_open_find_message(folder, path, &newpath);
791 if (fp)
792 {
793 e = maildir_parse_stream(MUTT_MAILDIR, fp, newpath, false, NULL);
794 mutt_file_fclose(&fp);
795
796 mutt_debug(LL_DEBUG1, "nm: not up-to-date: %s -> %s\n", path, newpath);
797 }
798 }
799 FREE(&folder);
800 }
801
802 if (!e)
803 {
804 mutt_debug(LL_DEBUG1, "nm: failed to parse message: %s\n", path);
805 goto done;
806 }
807
808#ifdef USE_HCACHE
809 mutt_hcache_store(h, newpath ? newpath : path,
810 mutt_str_len(newpath ? newpath : path), e, 0);
811#endif
812 }
813
814 if (init_email(e, newpath ? newpath : path, msg) != 0)
815 {
816 email_free(&e);
817 mutt_debug(LL_DEBUG1, "nm: failed to append email!\n");
818 goto done;
819 }
820
821 e->active = true;
822 e->index = m->msg_count;
823 mailbox_size_add(m, e);
824 m->emails[m->msg_count] = e;
825 m->msg_count++;
826
827 if (newpath)
828 {
829 /* remember that file has been moved -- nm_mbox_sync() will update the DB */
830 struct NmEmailData *edata = nm_edata_get(e);
831 if (edata)
832 {
833 mutt_debug(LL_DEBUG1, "nm: remember obsolete path: %s\n", path);
834 edata->oldpath = mutt_str_dup(path);
835 }
836 }
838done:
839 FREE(&newpath);
840}
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:150
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:616
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:513
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
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:238
FILE * maildir_open_find_message(const char *folder, const char *msg, char **newname)
Find a message by name.
Definition: maildir.c:997
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
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
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition: mx.c:1237
static int init_email(struct Email *e, const char *path, notmuch_message_t *msg)
Set up an email's Notmuch data.
Definition: notmuch.c:612
static const char * get_message_last_filename(notmuch_message_t *msg)
Get a message's last filename.
Definition: notmuch.c:656
static char * get_folder_from_path(const char *path)
Find an email's folder from its path.
Definition: notmuch.c:565
static void nm_progress_update(struct Mailbox *m)
Update the progress counter.
Definition: notmuch.c:692
static struct Email * get_mutt_email(struct Mailbox *m, notmuch_message_t *msg)
Get the Email of a Notmuch message.
Definition: notmuch.c:709
bool active
Message is not to be removed.
Definition: email.h:74
int index
The absolute (unsorted) message number.
Definition: email.h:109
struct Email * email
Retrieved email.
Definition: lib.h:102
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 852 of file notmuch.c.

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

881{
882 notmuch_messages_t *msgs = NULL;
883
884 for (msgs = notmuch_thread_get_toplevel_messages(thread);
885 notmuch_messages_valid(msgs); notmuch_messages_move_to_next(msgs))
886 {
887 notmuch_message_t *nm = notmuch_messages_get(msgs);
888 append_message(h, m, nm, dedup);
889 append_replies(h, m, q, nm, dedup);
890 notmuch_message_destroy(nm);
891 }
892}
+ 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 903 of file notmuch.c.

904{
905 if (!query)
906 return NULL;
907
908 notmuch_messages_t *msgs = NULL;
909
910#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
911 if (notmuch_query_search_messages(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
912 return NULL;
913#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
914 if (notmuch_query_search_messages_st(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
915 return NULL;
916#else
917 msgs = notmuch_query_search_messages(query);
918#endif
919
920 return msgs;
921}
+ 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 931 of file notmuch.c.

932{
933 struct NmMboxData *mdata = nm_mdata_get(m);
934 if (!mdata)
935 return false;
936
937 int limit = get_limit(mdata);
938
939 notmuch_messages_t *msgs = get_messages(q);
940
941 if (!msgs)
942 return false;
943
944 struct HeaderCache *h = nm_hcache_open(m);
945
946 for (; notmuch_messages_valid(msgs) && ((limit == 0) || (m->msg_count < limit));
947 notmuch_messages_move_to_next(msgs))
948 {
949 if (SigInt)
950 {
952 SigInt = false;
953 return false;
954 }
955 notmuch_message_t *nm = notmuch_messages_get(msgs);
956 append_message(h, m, nm, dedup);
957 notmuch_message_destroy(nm);
958 }
959
961 return true;
962}
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.c:59
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 struct HeaderCache * nm_hcache_open(struct Mailbox *m)
Open a header cache.
Definition: notmuch.c:110
static notmuch_messages_t * get_messages(notmuch_query_t *query)
Load messages for a query.
Definition: notmuch.c:903
Header cache structure.
Definition: lib.h:88
+ 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 973 of file notmuch.c.

974{
975 if (!query)
976 return NULL;
977
978 notmuch_threads_t *threads = NULL;
979#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
980 if (notmuch_query_search_threads(query, &threads) != NOTMUCH_STATUS_SUCCESS)
981 return false;
982#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
983 if (notmuch_query_search_threads_st(query, &threads) != NOTMUCH_STATUS_SUCCESS)
984 return false;
985#else
986 threads = notmuch_query_search_threads(query);
987#endif
988
989 return threads;
990}
+ 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 1001 of file notmuch.c.

1002{
1003 struct NmMboxData *mdata = nm_mdata_get(m);
1004 if (!mdata)
1005 return false;
1006
1007 notmuch_threads_t *threads = get_threads(q);
1008 if (!threads)
1009 return false;
1010
1011 struct HeaderCache *h = nm_hcache_open(m);
1012
1013 for (; notmuch_threads_valid(threads) && ((limit == 0) || (m->msg_count < limit));
1014 notmuch_threads_move_to_next(threads))
1015 {
1016 if (SigInt)
1017 {
1018 nm_hcache_close(h);
1019 SigInt = false;
1020 return false;
1021 }
1022 notmuch_thread_t *thread = notmuch_threads_get(threads);
1023 append_thread(h, m, q, thread, dedup);
1024 notmuch_thread_destroy(thread);
1025 }
1026
1027 nm_hcache_close(h);
1028 return true;
1029}
static notmuch_threads_t * get_threads(notmuch_query_t *query)
Load threads for a query.
Definition: notmuch.c:973
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:879
+ 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 1038 of file notmuch.c.

1039{
1040 notmuch_message_t *msg = NULL;
1041 char *id = email_get_id(e);
1042
1043 mutt_debug(LL_DEBUG2, "nm: find message (%s)\n", id);
1044
1045 if (id && db)
1046 notmuch_database_find_message(db, id, &msg);
1047
1048 return msg;
1049}
static char * email_get_id(struct Email *e)
Get the unique Notmuch Id.
Definition: notmuch.c:213
+ 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 1057 of file notmuch.c.

1058{
1059 const char *possible_match_tag = NULL;
1060 notmuch_tags_t *tags = NULL;
1061
1062 for (tags = notmuch_message_get_tags(msg); notmuch_tags_valid(tags);
1063 notmuch_tags_move_to_next(tags))
1064 {
1065 possible_match_tag = notmuch_tags_get(tags);
1066 if (mutt_str_equal(possible_match_tag, tag))
1067 {
1068 return true;
1069 }
1070 }
1071 return false;
1072}
+ 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 1079 of file notmuch.c.

1080{
1081 const char *new_file = get_message_last_filename(msg);
1082 char old_file[PATH_MAX] = { 0 };
1083 email_get_fullpath(e, old_file, sizeof(old_file));
1084
1085 if (!mutt_str_equal(old_file, new_file))
1086 update_message_path(e, new_file);
1087}
static char * email_get_fullpath(struct Email *e, char *buf, size_t buflen)
Get the full path of an email.
Definition: notmuch.c:229
+ 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 1096 of file notmuch.c.

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

1151{
1152 if (!tag_str)
1153 return -1;
1154
1155 const char *const c_nm_unread_tag = cs_subset_string(NeoMutt->sub, "nm_unread_tag");
1156 const char *const c_nm_replied_tag = cs_subset_string(NeoMutt->sub, "nm_replied_tag");
1157 const char *const c_nm_flagged_tag = cs_subset_string(NeoMutt->sub, "nm_flagged_tag");
1158
1160 char **tag_elem = NULL;
1161 ARRAY_FOREACH(tag_elem, &tags.tags)
1162 {
1163 char *tag = *tag_elem;
1164
1165 if (tag[0] == '-')
1166 {
1167 tag++;
1168 if (mutt_str_equal(tag, c_nm_unread_tag))
1169 mutt_set_flag(m, e, MUTT_READ, true, true);
1170 else if (mutt_str_equal(tag, c_nm_replied_tag))
1171 mutt_set_flag(m, e, MUTT_REPLIED, false, true);
1172 else if (mutt_str_equal(tag, c_nm_flagged_tag))
1173 mutt_set_flag(m, e, MUTT_FLAG, false, true);
1174 }
1175 else
1176 {
1177 tag = (tag[0] == '+') ? tag + 1 : tag;
1178 if (mutt_str_equal(tag, c_nm_unread_tag))
1179 mutt_set_flag(m, e, MUTT_READ, false, true);
1180 else if (mutt_str_equal(tag, c_nm_replied_tag))
1181 mutt_set_flag(m, e, MUTT_REPLIED, true, true);
1182 else if (mutt_str_equal(tag, c_nm_flagged_tag))
1183 mutt_set_flag(m, e, MUTT_FLAG, true, true);
1184 }
1185 }
1186
1188
1189 return 0;
1190}
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition: flags.c:52
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:81
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:87
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:80
+ 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 1202 of file notmuch.c.

1203{
1204 char filename[PATH_MAX] = { 0 };
1205 char suffix[PATH_MAX] = { 0 };
1206 char folder[PATH_MAX] = { 0 };
1207
1208 mutt_str_copy(folder, old, sizeof(folder));
1209 char *p = strrchr(folder, '/');
1210 if (p)
1211 {
1212 *p = '\0';
1213 p++;
1214 }
1215 else
1216 {
1217 p = folder;
1218 }
1219
1220 mutt_str_copy(filename, p, sizeof(filename));
1221
1222 /* remove (new,cur,...) from folder path */
1223 p = strrchr(folder, '/');
1224 if (p)
1225 *p = '\0';
1226
1227 /* remove old flags from filename */
1228 p = strchr(filename, ':');
1229 if (p)
1230 *p = '\0';
1231
1232 /* compose new flags */
1233 maildir_gen_flags(suffix, sizeof(suffix), e);
1234
1235 snprintf(buf, buflen, "%s/%s/%s%s", folder,
1236 (e->read || e->old) ? "cur" : "new", filename, suffix);
1237
1238 if (mutt_str_equal(old, buf))
1239 return 1;
1240
1241 if (rename(old, buf) != 0)
1242 {
1243 mutt_debug(LL_DEBUG1, "nm: rename(2) failed %s -> %s\n", old, buf);
1244 return -1;
1245 }
1246
1247 return 0;
1248}
void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
Generate the Maildir flags for an email.
Definition: maildir.c:190
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:653
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 1257 of file notmuch.c.

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

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

1426{
1427 notmuch_query_t *q = notmuch_query_create(db, qstr);
1428 if (!q)
1429 return 0;
1430
1431 unsigned int res = 0;
1432
1434#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
1435 if (notmuch_query_count_messages(q, &res) != NOTMUCH_STATUS_SUCCESS)
1436 res = 0; /* may not be defined on error */
1437#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
1438 if (notmuch_query_count_messages_st(q, &res) != NOTMUCH_STATUS_SUCCESS)
1439 res = 0; /* may not be defined on error */
1440#else
1441 res = notmuch_query_count_messages(q);
1442#endif
1443 notmuch_query_destroy(q);
1444 mutt_debug(LL_DEBUG1, "nm: count '%s', result=%d\n", qstr, res);
1445
1446 if ((limit > 0) && (res > limit))
1447 res = limit;
1448
1449 return res;
1450}
+ 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 1458 of file notmuch.c.

1459{
1460 struct NmEmailData *edata = nm_edata_get(e);
1461 if (!edata)
1462 return NULL;
1463
1464 return edata->folder;
1465}
+ 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 1477 of file notmuch.c.

1478{
1479 char *full_folder = nm_email_get_folder(e);
1480 if (!full_folder)
1481 return NULL;
1482
1483 const char *db_path = nm_db_get_filename(m);
1484 if (!db_path)
1485 return NULL;
1486
1487 return full_folder + strlen(db_path);
1488}
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 1497 of file notmuch.c.

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

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

1624{
1625 const short c_nm_query_window_duration = cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
1626 const bool c_nm_query_window_enable = cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
1627
1628 return c_nm_query_window_enable || (c_nm_query_window_duration > 0);
1629}
+ 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 1640 of file notmuch.c.

1641{
1642 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1643 if (c_nm_query_window_current_position != 0)
1644 {
1645 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1646 c_nm_query_window_current_position - 1, NULL);
1647 }
1648
1649 mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position - 1);
1650}
+ 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 1660 of file notmuch.c.

1661{
1662 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1663 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1664 c_nm_query_window_current_position + 1, NULL);
1665 mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position + 1);
1666}
+ 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 1671 of file notmuch.c.

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

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

1750{
1751 char buf[PATH_MAX] = { 0 };
1752 struct NmMboxData *mdata = nm_mdata_get(m);
1753 if (!mdata || !new_file)
1754 return -1;
1755
1756 if (!old_file && nm_edata_get(e))
1757 {
1758 email_get_fullpath(e, buf, sizeof(buf));
1759 old_file = buf;
1760 }
1761
1762 int rc = rename_filename(m, old_file, new_file, e);
1763
1764 nm_db_release(m);
1765 m->mtime.tv_sec = mutt_date_now();
1766 m->mtime.tv_nsec = 0;
1767 return rc;
1768}
static int rename_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Rename the file.
Definition: notmuch.c:1321
+ 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 1858 of file notmuch.c.

1859{
1860 // Create a new notmuch mailbox from scratch and add plumbing for DB access.
1861 char *default_url = nm_get_default_url();
1862 struct Mailbox *m = mx_path_resolve(default_url);
1863
1864 FREE(&default_url);
1865
1866 // These are no-ops for an initialized mailbox.
1867 init_mailbox(m);
1868 mx_mbox_ac_link(m);
1869
1870 return m;
1871}
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:270
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1698
static int init_mailbox(struct Mailbox *m)
Add Notmuch data to the Mailbox.
Definition: notmuch.c:191
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 1881 of file notmuch.c.

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

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

Variable Documentation

◆ NmCommands

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

Notmuch Commands.

Definition at line 85 of file notmuch.c.

◆ NmUrlProtocol

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

Protocol string for Notmuch URLs.

Definition at line 93 of file notmuch.c.

◆ NmUrlProtocolLen

const int NmUrlProtocolLen = sizeof(NmUrlProtocol) - 1

Length of NmUrlProtocol string.

Definition at line 95 of file notmuch.c.