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

Variables

static const struct Command NmCommands []
 Notmuch Commands.
 
const char NmUrlProtocol [] = "notmuch://"
 Protocol string for Notmuch URLs.
 
const int NmUrlProtocolLen = sizeof(NmUrlProtocol) - 1
 Length of NmUrlProtocol string.
 
const struct MxOps MxNotmuchOps
 Notmuch Mailbox - Implements MxOps -.
 

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:38
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 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:169
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:495
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:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ 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 **  ptr)
static

Close the header cache.

Parameters
ptrHeader cache handle

Definition at line 124 of file notmuch.c.

125{
126#ifdef USE_HCACHE
127 hcache_close(ptr);
128#endif
129}
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition: hcache.c:564
+ 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:292
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:45
#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:68
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:35
+ 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}
void nm_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free() -.
Definition: mdata.c:45
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
void(* mdata_free)(void **ptr)
Definition: mailbox.h:142
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
void * mdata
Driver specific data.
Definition: mailbox.h:131
+ 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:1459
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:89
@ 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:304
+ 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:144
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
#define mutt_message(...)
Definition: logging2.h:91
#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:92
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:36
enum NmQueryType query_type
Messages or Threads.
Definition: mdata.h:39
int db_limit
Maximum number of results to return.
Definition: mdata.h:38
char * db_query
Previous query.
Definition: mdata.h:37
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:407
+ 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 NmTags 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 TagArray tags
Tags.
Definition: tag.h:38
void nm_tag_array_free(struct NmTags *tags)
Free all memory of a NmTags.
Definition: tag.c:39
struct NmTags 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:96
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 if (!id)
593 return NULL;
594
595 char *mid = NULL;
596 mutt_str_asprintf(&mid, "<%s>", id);
597 return mid;
598}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1022
+ 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 608 of file notmuch.c.

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

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

670{
671 if (!m->verbose)
672 return;
673
674 struct NmMboxData *mdata = nm_mdata_get(m);
675 if (!mdata)
676 return;
677
678 mdata->oldmsgcount = m->msg_count;
679 mdata->ignmsgcount = 0;
680 mdata->progress = progress_new(MUTT_PROGRESS_READ, mdata->oldmsgcount);
681 progress_set_message(mdata->progress, _("Reading messages..."));
682}
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:82
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:140
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
int msg_count
Total number of messages.
Definition: mailbox.h:88
bool verbose
Display status messages?
Definition: mailbox.h:116
+ 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 688 of file notmuch.c.

689{
690 struct NmMboxData *mdata = nm_mdata_get(m);
691
692 if (!m->verbose || !mdata || !mdata->progress)
693 return;
694
695 progress_update(mdata->progress, m->msg_count + mdata->ignmsgcount, -1);
696}
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:81
+ 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 705 of file notmuch.c.

706{
707 if (!m || !msg)
708 return NULL;
709
710 const char *id = notmuch_message_get_message_id(msg);
711 if (!id)
712 return NULL;
713
714 mutt_debug(LL_DEBUG2, "nm: neomutt email, id='%s'\n", id);
715
716 if (!m->id_hash)
717 {
718 mutt_debug(LL_DEBUG2, "nm: init hash\n");
720 if (!m->id_hash)
721 return NULL;
722 }
723
724 char *mid = nm2mutt_message_id(id);
725 mutt_debug(LL_DEBUG2, "nm: neomutt id='%s'\n", mid);
726
727 struct Email *e = mutt_hash_find(m->id_hash, mid);
728 FREE(&mid);
729 return e;
730}
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:1699
The envelope/body of an email.
Definition: email.h:37
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
Definition: mailbox.h:122
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ append_message()

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

Associate a message.

Parameters
hcHeader cache handle
mMailbox
msgNotmuch message
dedupDe-duplicate results

Definition at line 739 of file notmuch.c.

741{
742 struct NmMboxData *mdata = nm_mdata_get(m);
743 if (!mdata)
744 return;
745
746 char *newpath = NULL;
747 struct Email *e = NULL;
748
749 /* deduplicate */
750 if (dedup && get_mutt_email(m, msg))
751 {
752 mdata->ignmsgcount++;
754 mutt_debug(LL_DEBUG2, "nm: ignore id=%s, already in the m\n",
755 notmuch_message_get_message_id(msg));
756 return;
757 }
758
759 const char *path = get_message_last_filename(msg);
760 if (!path)
761 return;
762
763 mutt_debug(LL_DEBUG2, "nm: appending message, i=%d, id=%s, path=%s\n",
764 m->msg_count, notmuch_message_get_message_id(msg), path);
765
767
768#ifdef USE_HCACHE
770 if (!e)
771#endif
772 {
773 if (access(path, F_OK) == 0)
774 {
775 /* We pass is_old=false as argument here, but e->old will be updated later
776 * by update_message_path() (called by init_email() below). */
777 e = maildir_email_new();
778 if (!maildir_parse_message(path, false, e))
779 email_free(&e);
780 }
781 else
782 {
783 /* maybe moved try find it... */
784 char *folder = get_folder_from_path(path);
785
786 if (folder)
787 {
788 FILE *fp = maildir_open_find_message(folder, path, &newpath);
789 if (fp)
790 {
791 e = maildir_email_new();
792 if (!maildir_parse_stream(fp, newpath, false, e))
793 email_free(&e);
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 hcache_store(hc, 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:152
int hcache_store(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:687
struct HCacheEntry hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:584
@ 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:242
bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
Actually parse a maildir message.
Definition: maildir.c:1023
FILE * maildir_open_find_message(const char *folder, const char *msg, char **newname)
Find a message by name.
Definition: maildir.c:1091
struct Email * maildir_email_new(void)
Create a Maildir Email.
Definition: maildir.c:119
bool maildir_parse_stream(FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition: maildir.c:986
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:1211
static int init_email(struct Email *e, const char *path, notmuch_message_t *msg)
Set up an email's Notmuch data.
Definition: notmuch.c:608
static const char * get_message_last_filename(notmuch_message_t *msg)
Get a message's last filename.
Definition: notmuch.c:652
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:688
static struct Email * get_mutt_email(struct Mailbox *m, notmuch_message_t *msg)
Get the Email of a Notmuch message.
Definition: notmuch.c:705
bool active
Message is not to be removed.
Definition: email.h:74
int index
The absolute (unsorted) message number.
Definition: email.h:111
struct Email * email
Retrieved email.
Definition: lib.h:104
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
int ignmsgcount
Ignored messages.
Definition: mdata.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ append_replies()

static void append_replies ( struct HeaderCache hc,
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
hcHeader 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(hc, m, nm, dedup);
862 /* recurse through all the replies to this message too */
863 append_replies(hc, m, q, nm, dedup);
864 notmuch_message_destroy(nm);
865 }
866}
static void append_replies(struct HeaderCache *hc, 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 *hc, struct Mailbox *m, notmuch_message_t *msg, bool dedup)
Associate a message.
Definition: notmuch.c:739
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ append_thread()

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

Add each top level reply in the thread.

Parameters
hcHeader 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(hc, m, nm, dedup);
889 append_replies(hc, 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 *hc = 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 {
951 nm_hcache_close(&hc);
952 SigInt = false;
953 return false;
954 }
955 notmuch_message_t *nm = notmuch_messages_get(msgs);
956 append_message(hc, m, nm, dedup);
957 notmuch_message_destroy(nm);
958 }
959
960 nm_hcache_close(&hc);
961 return true;
962}
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.c:59
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 void nm_hcache_close(struct HeaderCache **ptr)
Close the header cache.
Definition: notmuch.c:124
static notmuch_messages_t * get_messages(notmuch_query_t *query)
Load messages for a query.
Definition: notmuch.c:903
Header Cache.
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 *hc = 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(&hc);
1019 SigInt = false;
1020 return false;
1021 }
1022 notmuch_thread_t *thread = notmuch_threads_get(threads);
1023 append_thread(hc, m, q, thread, dedup);
1024 notmuch_thread_destroy(thread);
1025 }
1026
1027 nm_hcache_close(&hc);
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 *hc, 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:53
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:72
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:78
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:71
+ 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 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
1229 p = strchr(filename, c_maildir_field_delimiter);
1230 if (p)
1231 *p = '\0';
1232
1233 /* compose new flags */
1234 maildir_gen_flags(suffix, sizeof(suffix), e);
1235
1236 snprintf(buf, buflen, "%s/%s/%s%s", folder,
1237 (e->read || e->old) ? "cur" : "new", filename, suffix);
1238
1239 if (mutt_str_equal(old, buf))
1240 return 1;
1241
1242 if (rename(old, buf) != 0)
1243 {
1244 mutt_debug(LL_DEBUG1, "nm: rename(2) failed %s -> %s\n", old, buf);
1245 return -1;
1246 }
1247
1248 return 0;
1249}
const char * cc_maildir_field_delimiter(void)
Get the cached value of $maildir_field_delimiter.
Definition: config_cache.c:130
void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
Generate the Maildir flags for an email.
Definition: maildir.c:240
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 1258 of file notmuch.c.

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

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

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

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

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

1499{
1500 if (!m)
1501 return -1;
1502
1503 struct NmMboxData *mdata = nm_mdata_get(m);
1504 if (!mdata)
1505 return -1;
1506
1507 notmuch_query_t *q = NULL;
1508 notmuch_database_t *db = NULL;
1509 notmuch_message_t *msg = NULL;
1510 int rc = -1;
1511
1512 if (!(db = nm_db_get(m, false)) || !(msg = get_nm_message(db, e)))
1513 goto done;
1514
1515 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages...[current count=%d]\n",
1516 m->msg_count);
1517
1518 progress_setup(m);
1519 const char *id = notmuch_message_get_thread_id(msg);
1520 if (!id)
1521 goto done;
1522
1523 char *qstr = NULL;
1524 mutt_str_append_item(&qstr, "thread:", '\0');
1525 mutt_str_append_item(&qstr, id, '\0');
1526
1527 q = notmuch_query_create(db, qstr);
1528 FREE(&qstr);
1529 if (!q)
1530 goto done;
1532 notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
1533
1534 read_threads_query(m, q, true, 0);
1535 mdata->mtime.tv_sec = mutt_date_now();
1536 mdata->mtime.tv_nsec = 0;
1537 rc = 0;
1538
1539 if (m->msg_count > mdata->oldmsgcount)
1541done:
1542 if (q)
1543 notmuch_query_destroy(q);
1544
1545 nm_db_release(m);
1546
1547 if (m->msg_count == mdata->oldmsgcount)
1548 mutt_message(_("No more messages in the thread"));
1549
1550 mdata->oldmsgcount = 0;
1551 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
1552 rc, m->msg_count);
1553 progress_free(&mdata->progress);
1554 return rc;
1555}
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:226
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:176
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:669
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:111
+ 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 1565 of file notmuch.c.

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

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

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

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

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

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

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

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

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

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

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.