NeoMutt  2025-12-11-435-g4ac674
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 "gui/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 "progress/lib.h"
#include "adata.h"
#include "edata.h"
#include "maildir/shared.h"
#include "mdata.h"
#include "mx.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

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 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, int depth)
 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, const 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?
 
static int nm_path_canon (struct Buffer *path)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
 

Variables

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
  • Kevin Velghe
  • Richard Russon
  • Bernard Pratz
  • Bryan Bennett
  • Julian Andres Klode
  • William Pettersson
  • Austin Ray
  • Pietro Cerutti
  • Federico Kircheis
  • Ian Zimmerman
  • Reto Brunner
  • Dennis Schön

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_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 111 of file notmuch.c.

112{
113#ifdef USE_HCACHE
114 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
115 return hcache_open(c_header_cache, mailbox_path(m), NULL, true);
116#else
117 return NULL;
118#endif
119}
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:213
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer, bool create)
Multiplexor for StoreOps::open.
Definition hcache.c:476
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ 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 125 of file notmuch.c.

126{
127#ifdef USE_HCACHE
128 hcache_close(ptr);
129#endif
130}
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition hcache.c:547
+ 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 137 of file notmuch.c.

138{
139 // path to DB + query + url "decoration"
140 size_t len = PATH_MAX + 1024 + 32;
141 char *url = MUTT_MEM_MALLOC(len, char);
142
143 // Try to use `$nm_default_url` or `$folder`.
144 // If neither are set, it is impossible to create a Notmuch URL.
145 const char *const c_nm_default_url = cs_subset_string(NeoMutt->sub, "nm_default_url");
146 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
147 if (c_nm_default_url)
148 {
149 snprintf(url, len, "%s", c_nm_default_url);
150 }
151 else if (c_folder)
152 {
153 snprintf(url, len, "notmuch://%s", c_folder);
154 }
155 else
156 {
157 FREE(&url);
158 return NULL;
159 }
160
161 return url;
162}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:53
#define PATH_MAX
Definition mutt.h:49
+ 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 169 of file notmuch.c.

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

193{
194 if (!m || (m->type != MUTT_NOTMUCH))
195 return -1;
196
197 if (m->mdata)
198 return 0;
199
201 if (!m->mdata)
202 return -1;
203
205 return 0;
206}
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
void nm_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free() -.
Definition mdata.c:45
void(* mdata_free)(void **ptr)
Definition mailbox.h:142
enum MailboxType type
Mailbox type.
Definition mailbox.h:101
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 214 of file notmuch.c.

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

231{
232 char *folder = nm_email_get_folder(e);
233 if (!folder)
234 {
235 *buf = '\0';
236 return buf;
237 }
238
239 snprintf(buf, buflen, "%s/%s", folder, e->path);
240 return buf;
241}
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition notmuch.c:1505
char * path
Path of Email (for local Mailboxes)
Definition email.h:70
+ 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 252 of file notmuch.c.

253{
254 mutt_debug(LL_DEBUG2, "entering\n");
255 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position", 0, NULL);
256}
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
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:303
+ 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 282 of file notmuch.c.

283{
284 mutt_debug(LL_DEBUG2, "nm: %s\n", query);
285
286 const bool c_nm_query_window_enable = cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
287 const short c_nm_query_window_duration = cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
288 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
289 const char *const c_nm_query_window_current_search = cs_subset_string(NeoMutt->sub, "nm_query_window_current_search");
290 const char *const c_nm_query_window_timebase = cs_subset_string(NeoMutt->sub, "nm_query_window_timebase");
291 const char *const c_nm_query_window_or_terms = cs_subset_string(NeoMutt->sub, "nm_query_window_or_terms");
292
293 /* if the query has changed, reset the window position */
294 if (!c_nm_query_window_current_search || !mutt_str_equal(query, c_nm_query_window_current_search))
295 {
297 }
298
300 buf, buflen, c_nm_query_window_enable, c_nm_query_window_duration,
301 c_nm_query_window_current_position, c_nm_query_window_current_search,
302 c_nm_query_window_timebase, c_nm_query_window_or_terms);
303
304 switch (rc)
305 {
307 {
308 mutt_debug(LL_DEBUG2, "nm: %s -> %s\n", query, buf);
309 break;
310 }
312 {
314 return false;
315 }
317 {
319 // L10N: The values 'hour', 'day', 'week', 'month', 'year' are literal.
320 // They should not be translated.
321 _("Invalid nm_query_window_timebase value (valid values are: hour, day, week, month, year)"));
322 mutt_debug(LL_DEBUG2, "Invalid nm_query_window_timebase value\n");
323 return false;
324 }
325 }
326
327 return true;
328}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
#define mutt_message(...)
Definition logging2.h:93
#define _(a)
Definition message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
static void query_window_reset(void)
Restore vfolder's search window to its original position.
Definition notmuch.c:252
enum NmWindowQueryRc nm_windowed_query_from_query(char *buf, size_t buflen, const bool force_enable, const short duration, const short cur_pos, const char *cur_search, const char *timebase, const char *or_terms)
Windows buf with notmuch date: search term.
Definition query.c:207
NmWindowQueryRc
Return codes for nm_windowed_query_from_query()
Definition query.h:45
@ NM_WINDOW_QUERY_SUCCESS
Query was successful.
Definition query.h:46
@ NM_WINDOW_QUERY_INVALID_DURATION
Invalid duration.
Definition query.h:48
@ NM_WINDOW_QUERY_INVALID_TIMEBASE
Invalid timebase.
Definition query.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_query_string()

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

Builds the notmuch vfolder search string.

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

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

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

Definition at line 346 of file notmuch.c.

347{
348 mutt_debug(LL_DEBUG2, "nm: %s\n", window ? "true" : "false");
349
350 if (!mdata)
351 return NULL;
352 if (mdata->db_query && !window)
353 return mdata->db_query;
354
355 const char *const c_nm_query_type = cs_subset_string(NeoMutt->sub, "nm_query_type");
356 mdata->query_type = nm_string_to_query_type(c_nm_query_type); /* user's default */
357
358 struct UrlQuery *item = NULL;
359 STAILQ_FOREACH(item, &mdata->db_url->query_strings, entries)
360 {
361 if (!item->value || !item->name)
362 continue;
363
364 if (mutt_str_equal(item->name, "limit"))
365 {
366 if (!mutt_str_atoi_full(item->value, &mdata->db_limit))
367 {
368 mutt_error(_("failed to parse notmuch limit: %s"), item->value);
369 }
370 }
371 else if (mutt_str_equal(item->name, "type"))
372 {
374 }
375 else if (mutt_str_equal(item->name, "query"))
376 {
377 mutt_str_replace(&mdata->db_query, item->value);
378 }
379 }
380
381 if (!mdata->db_query)
382 return NULL;
383
384 if (window)
385 {
386 char buf[1024] = { 0 };
387 cs_subset_str_string_set(NeoMutt->sub, "nm_query_window_current_search",
388 mdata->db_query, NULL);
389
390 /* if a date part is defined, do not apply windows (to avoid the risk of
391 * having a non-intersected date frame). A good improvement would be to
392 * accept if they intersect */
393 if (!strstr(mdata->db_query, "date:") &&
394 windowed_query_from_query(mdata->db_query, buf, sizeof(buf)))
395 {
396 mutt_str_replace(&mdata->db_query, buf);
397 }
398
399 mutt_debug(LL_DEBUG2, "nm: query (windowed) '%s'\n", mdata->db_query);
400 }
401 else
402 {
403 mutt_debug(LL_DEBUG2, "nm: query '%s'\n", mdata->db_query);
404 }
405
406 return mdata->db_query;
407}
#define mutt_error(...)
Definition logging2.h:94
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
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:282
enum NmQueryType nm_string_to_query_type(const char *str)
Lookup a query type.
Definition query.c:111
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
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:392
+ 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 414 of file notmuch.c.

415{
416 return mdata ? mdata->db_limit : 0;
417}
+ 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 423 of file notmuch.c.

424{
425 const char *const c_nm_exclude_tags = cs_subset_string(NeoMutt->sub, "nm_exclude_tags");
426 if (!c_nm_exclude_tags || !query)
427 return;
428
429 struct NmTags tags = nm_tag_str_to_tags(c_nm_exclude_tags);
430
431 const char **tag = NULL;
432 ARRAY_FOREACH(tag, &tags.tags)
433 {
434 mutt_debug(LL_DEBUG2, "nm: query exclude tag '%s'\n", *tag);
435 notmuch_query_add_tag_exclude(query, *tag);
436 }
437
438 notmuch_query_set_omit_excluded(query, 1);
440}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
Array of Notmuch tags.
Definition tag.h:36
struct StringArray tags
Tags.
Definition tag.h:37
void nm_tag_array_free(struct NmTags *tags)
Free all memory of a NmTags.
Definition tag.c:40
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:51
+ 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 449 of file notmuch.c.

450{
451 struct NmMboxData *mdata = nm_mdata_get(m);
452 if (!mdata)
453 return NULL;
454
455 notmuch_database_t *db = nm_db_get(m, writable);
456 const char *str = get_query_string(mdata, true);
457
458 if (!db || !str)
459 goto err;
460
461 notmuch_query_t *q = notmuch_query_create(db, str);
462 if (!q)
463 goto err;
464
466 notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
467 mutt_debug(LL_DEBUG2, "nm: query successfully initialized (%s)\n", str);
468 return q;
469err:
470 nm_db_release(m);
471 return NULL;
472}
notmuch_database_t * nm_db_get(struct Mailbox *m, bool writable)
Get the Notmuch database.
Definition db.c:209
int nm_db_release(struct Mailbox *m)
Close the Notmuch database.
Definition db.c:233
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:346
static void apply_exclude_tags(notmuch_query_t *query)
Exclude the configured tags.
Definition notmuch.c:423
+ 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 481 of file notmuch.c.

482{
483 struct NmEmailData *edata = nm_edata_get(e);
484 if (!edata)
485 return 1;
486
487 struct Buffer *new_tags = buf_pool_get();
488 struct Buffer *old_tags = buf_pool_get();
489
490 mutt_debug(LL_DEBUG2, "nm: tags update requested (%s)\n", edata->virtual_id);
491
492 for (notmuch_tags_t *tags = notmuch_message_get_tags(msg);
493 tags && notmuch_tags_valid(tags); notmuch_tags_move_to_next(tags))
494 {
495 const char *t = notmuch_tags_get(tags);
496 if (!t || (*t == '\0'))
497 continue;
498
499 buf_join_str(new_tags, t, ' ');
500 }
501
502 driver_tags_get(&e->tags, old_tags);
503
504 if (!buf_is_empty(new_tags) && !buf_is_empty(old_tags) &&
505 (buf_str_equal(old_tags, new_tags)))
506 {
507 buf_pool_release(&new_tags);
508 buf_pool_release(&old_tags);
509 mutt_debug(LL_DEBUG2, "nm: tags unchanged\n");
510 return 1;
511 }
512 buf_pool_release(&old_tags);
513
514 /* new version */
515 driver_tags_replace(&e->tags, buf_string(new_tags));
516 buf_reset(new_tags);
517
518 driver_tags_get_transformed(&e->tags, new_tags);
519 mutt_debug(LL_DEBUG2, "nm: new tags transformed: '%s'\n", buf_string(new_tags));
520 buf_reset(new_tags);
521
522 driver_tags_get(&e->tags, new_tags);
523 mutt_debug(LL_DEBUG2, "nm: new tag: '%s'\n", buf_string(new_tags));
524 buf_pool_release(&new_tags);
525
526 return 0;
527}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
void buf_join_str(struct Buffer *buf, const char *str, char sep)
Join a buffer with a string separated by sep.
Definition buffer.c:748
bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal.
Definition buffer.c:683
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
String manipulation buffer.
Definition buffer.h:36
struct TagList tags
For drivers that support server tagging.
Definition email.h:72
char * virtual_id
Unique Notmuch Id.
Definition edata.h:37
bool driver_tags_replace(struct TagList *tl, const char *tags)
Replace all tags.
Definition tags.c:202
void driver_tags_get(struct TagList *tl, struct Buffer *tags)
Get tags all tags separated by space.
Definition tags.c:165
void driver_tags_get_transformed(struct TagList *tl, struct Buffer *tags)
Get transformed tags separated by space.
Definition tags.c:153
+ 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 536 of file notmuch.c.

537{
538 struct NmEmailData *edata = nm_edata_get(e);
539 if (!edata)
540 return 1;
541
542 mutt_debug(LL_DEBUG2, "nm: path update requested path=%s, (%s)\n", path, edata->virtual_id);
543
544 char *p = strrchr(path, '/');
545 if (p && ((p - path) > 3) &&
546 (mutt_strn_equal(p - 3, "cur", 3) || mutt_strn_equal(p - 3, "new", 3) ||
547 mutt_strn_equal(p - 3, "tmp", 3)))
548 {
549 edata->type = MUTT_MAILDIR;
550
551 FREE(&e->path);
552 FREE(&edata->folder);
553
554 p -= 3; /* skip subfolder (e.g. "new") */
555 if (cs_subset_bool(NeoMutt->sub, "mark_old"))
556 {
557 e->old = mutt_str_startswith(p, "cur");
558 }
559 e->path = mutt_str_dup(p);
560
561 for (; (p > path) && (*(p - 1) == '/'); p--)
562 ; // do nothing
563
564 edata->folder = mutt_strn_dup(path, p - path);
565
566 mutt_debug(LL_DEBUG2, "nm: folder='%s', file='%s'\n", edata->folder, e->path);
567
568 // We _might_ be looking at a different file (with the same message-id)
569 // so reparse it from scratch.
570
571 // Preserve the message-id as it's used in the Email HashTable
572 mutt_debug(LL_DEBUG1, "nm: reparse the message\n");
573 char *message_id = e->env->message_id;
574 e->env->message_id = NULL;
575
576 mutt_body_free(&e->body);
577 mutt_env_free(&e->env);
578 if (!maildir_parse_message(path, e->old, e))
579 return 1;
580
581 ASSERT(e->body);
582 ASSERT(e->env);
583
584 FREE(&e->env->message_id);
585 e->env->message_id = message_id;
586 message_id = NULL;
587
588 return 0;
589 }
590
591 return 1;
592}
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition mailbox.h:47
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
Actually parse a maildir message.
Definition mailbox.c:195
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition string.c:384
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
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:429
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
#define ASSERT(COND)
Definition signal2.h:59
struct Envelope * env
Envelope information.
Definition email.h:68
struct Body * body
List of MIME parts.
Definition email.h:69
bool old
Email is seen, but unread.
Definition email.h:49
char * message_id
Message ID.
Definition envelope.h:73
+ 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 600 of file notmuch.c.

601{
602 char *p = strrchr(path, '/');
603
604 if (p && ((p - path) > 3) &&
605 (mutt_strn_equal(p - 3, "cur", 3) || mutt_strn_equal(p - 3, "new", 3) ||
606 mutt_strn_equal(p - 3, "tmp", 3)))
607 {
608 p -= 3;
609 for (; (p > path) && (*(p - 1) == '/'); p--)
610 ; // do nothing
611
612 return mutt_strn_dup(path, p - path);
613 }
614
615 return NULL;
616}
+ 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 625 of file notmuch.c.

626{
627 if (!id)
628 return NULL;
629
630 char *mid = NULL;
631 mutt_str_asprintf(&mid, "<%s>", id);
632 return mid;
633}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:805
+ 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 643 of file notmuch.c.

644{
645 if (nm_edata_get(e))
646 return 0;
647
648 struct NmEmailData *edata = nm_edata_new();
649 e->nm_edata = edata;
650
651 /* Notmuch ensures that message Id exists (if not notmuch Notmuch will
652 * generate an ID), so it's more safe than use neomutt Email->env->id */
653 const char *id = notmuch_message_get_message_id(msg);
654 edata->virtual_id = mutt_str_dup(id);
655
656 mutt_debug(LL_DEBUG2, "nm: [e=%p, edata=%p] (%s)\n", (void *) e, (void *) edata, id);
657
658 char *nm_msg_id = nm2mutt_message_id(id);
659 if (!e->env->message_id)
660 {
661 e->env->message_id = nm_msg_id;
662 }
663 else if (!mutt_str_equal(e->env->message_id, nm_msg_id))
664 {
665 FREE(&e->env->message_id);
666 e->env->message_id = nm_msg_id;
667 }
668 else
669 {
670 FREE(&nm_msg_id);
671 }
672
673 if (update_message_path(e, path) != 0)
674 return -1;
675
676 update_email_tags(e, msg);
677
678 return 0;
679}
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:536
static char * nm2mutt_message_id(const char *id)
Converts notmuch message Id to neomutt message Id.
Definition notmuch.c:625
static int update_email_tags(struct Email *e, notmuch_message_t *msg)
Update the Email's tags from Notmuch.
Definition notmuch.c:481
void * nm_edata
Notmuch private data.
Definition email.h:93
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_message_last_filename()

static char * get_message_last_filename ( notmuch_message_t * msg)
static

Get a message's last filename.

Parameters
msgNotmuch message
Return values
ptrFilename (strdup'd, caller must free)
NULLError

Definition at line 687 of file notmuch.c.

688{
689 const char *name = NULL;
690
691 for (notmuch_filenames_t *ls = notmuch_message_get_filenames(msg);
692 ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
693 {
694 name = notmuch_filenames_get(ls);
695 }
696
697 return mutt_str_dup(name);
698}
+ Here is the call graph for this function:
+ 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 704 of file notmuch.c.

705{
706 if (!m->verbose)
707 return;
708
709 struct NmMboxData *mdata = nm_mdata_get(m);
710 if (!mdata)
711 return;
712
713 mdata->oldmsgcount = m->msg_count;
714 mdata->ignmsgcount = 0;
715 mdata->progress = progress_new(MUTT_PROGRESS_READ, mdata->oldmsgcount);
716 progress_set_message(mdata->progress, _("Reading messages..."));
717}
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition lib.h:84
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition progress.c:139
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
int msg_count
Total number of messages.
Definition mailbox.h:87
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 723 of file notmuch.c.

724{
725 struct NmMboxData *mdata = nm_mdata_get(m);
726
727 if (!m->verbose || !mdata || !mdata->progress)
728 return;
729
730 progress_update(mdata->progress, m->msg_count + mdata->ignmsgcount, -1);
731}
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition progress.c:80
+ 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 740 of file notmuch.c.

741{
742 if (!m || !msg)
743 return NULL;
744
745 const char *id = notmuch_message_get_message_id(msg);
746 if (!id)
747 return NULL;
748
749 mutt_debug(LL_DEBUG2, "nm: neomutt email, id='%s'\n", id);
750
751 if (!m->id_hash)
752 {
753 mutt_debug(LL_DEBUG2, "nm: init hash\n");
755 if (!m->id_hash)
756 return NULL;
757 }
758
759 char *mid = nm2mutt_message_id(id);
760 mutt_debug(LL_DEBUG2, "nm: neomutt id='%s'\n", mid);
761
762 struct Email *e = mutt_hash_find(m->id_hash, mid);
763 FREE(&mid);
764 return e;
765}
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for message-ids.
Definition thread.c:1700
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:364
The envelope/body of an email.
Definition email.h:39
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 774 of file notmuch.c.

776{
777 struct NmMboxData *mdata = nm_mdata_get(m);
778 if (!mdata)
779 return;
780
781 char *newpath = NULL;
782 struct Email *e = NULL;
783
784 /* deduplicate */
785 if (dedup && get_mutt_email(m, msg))
786 {
787 mdata->ignmsgcount++;
789 mutt_debug(LL_DEBUG2, "nm: ignore id=%s, already in the m\n",
790 notmuch_message_get_message_id(msg));
791 return;
792 }
793
794 char *path = get_message_last_filename(msg);
795 if (!path)
796 return;
797
798 mutt_debug(LL_DEBUG2, "nm: appending message, i=%d, id=%s, path=%s\n",
799 m->msg_count, notmuch_message_get_message_id(msg), path);
800
802
803#ifdef USE_HCACHE
805 if (!e)
806#endif
807 {
808 if (access(path, F_OK) == 0)
809 {
810 /* We pass is_old=false as argument here, but e->old will be updated later
811 * by update_message_path() (called by init_email() below). */
812 e = maildir_email_new();
813 if (!maildir_parse_message(path, false, e))
814 email_free(&e);
815 }
816 else
817 {
818 /* maybe moved try find it... */
819 char *folder = get_folder_from_path(path);
820
821 if (folder)
822 {
823 FILE *fp = maildir_open_find_message(folder, path, &newpath);
824 if (fp)
825 {
826 e = maildir_email_new();
827 if (!maildir_parse_stream(fp, newpath, false, e))
828 email_free(&e);
829 mutt_file_fclose(&fp);
830
831 mutt_debug(LL_DEBUG1, "nm: not up-to-date: %s -> %s\n", path, newpath);
832 }
833 }
834 FREE(&folder);
835 }
836
837 if (!e)
838 {
839 mutt_debug(LL_DEBUG1, "nm: failed to parse message: %s\n", path);
840 goto done;
841 }
842
843#ifdef USE_HCACHE
844 hcache_store_email(hc, newpath ? newpath : path,
845 mutt_str_len(newpath ? newpath : path), e, 0);
846#endif
847 }
848
849 if (init_email(e, newpath ? newpath : path, msg) != 0)
850 {
851 email_free(&e);
852 mutt_debug(LL_DEBUG1, "nm: failed to append email!\n");
853 goto done;
854 }
855
856 e->active = true;
857 e->index = m->msg_count;
858 mailbox_size_add(m, e);
859 m->emails[m->msg_count] = e;
860 m->msg_count++;
861
862 if (newpath)
863 {
864 /* remember that file has been moved -- nm_mbox_sync() will update the DB */
865 struct NmEmailData *edata = nm_edata_get(e);
866 if (edata)
867 {
868 mutt_debug(LL_DEBUG1, "nm: remember obsolete path: %s\n", path);
869 edata->oldpath = mutt_str_dup(path);
870 }
871 }
873done:
874 FREE(&newpath);
875 FREE(&path);
876}
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:248
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
#define mutt_file_fclose(FP)
Definition file.h:139
struct HCacheEntry hcache_fetch_email(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition hcache.c:567
int hcache_store_email(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition hcache.c:675
struct Email * maildir_email_new(void)
Create a Maildir Email.
Definition mailbox.c:68
bool maildir_parse_stream(FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition mailbox.c:158
FILE * maildir_open_find_message(const char *folder, const char *msg, char **newname)
Find a message by name.
Definition message.c:168
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:500
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition mx.c:1208
static int init_email(struct Email *e, const char *path, notmuch_message_t *msg)
Set up an email's Notmuch data.
Definition notmuch.c:643
static char * get_message_last_filename(notmuch_message_t *msg)
Get a message's last filename.
Definition notmuch.c:687
static char * get_folder_from_path(const char *path)
Find an email's folder from its path.
Definition notmuch.c:600
static void nm_progress_update(struct Mailbox *m)
Update the progress counter.
Definition notmuch.c:723
static struct Email * get_mutt_email(struct Mailbox *m, notmuch_message_t *msg)
Get the Email of a Notmuch message.
Definition notmuch.c:740
bool active
Message is not to be removed.
Definition email.h:76
int index
The absolute (unsorted) message number.
Definition email.h:110
struct Email * email
Retrieved email.
Definition lib.h:103
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
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,
int depth )
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
depthCurrent recursion depth

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

Definition at line 889 of file notmuch.c.

891{
892 if (depth > 512)
893 {
894 mutt_debug(LL_DEBUG1, "nm: stripping thread replies stripping at depth %d\n", depth);
895 return;
896 }
897
898 notmuch_messages_t *msgs = NULL;
899
900 for (msgs = notmuch_message_get_replies(top); notmuch_messages_valid(msgs);
901 notmuch_messages_move_to_next(msgs))
902 {
903 notmuch_message_t *nm = notmuch_messages_get(msgs);
904 append_message(hc, m, nm, dedup);
905 /* recurse through all the replies to this message too */
906 append_replies(hc, m, q, nm, dedup, depth + 1);
907 notmuch_message_destroy(nm);
908 }
909}
static void append_replies(struct HeaderCache *hc, struct Mailbox *m, notmuch_query_t *q, notmuch_message_t *top, bool dedup, int depth)
Add all the replies to a given messages into the display.
Definition notmuch.c:889
static void append_message(struct HeaderCache *hc, struct Mailbox *m, notmuch_message_t *msg, bool dedup)
Associate a message.
Definition notmuch.c:774
+ 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 922 of file notmuch.c.

924{
925 notmuch_messages_t *msgs = NULL;
926
927 for (msgs = notmuch_thread_get_toplevel_messages(thread);
928 notmuch_messages_valid(msgs); notmuch_messages_move_to_next(msgs))
929 {
930 notmuch_message_t *nm = notmuch_messages_get(msgs);
931 append_message(hc, m, nm, dedup);
932 append_replies(hc, m, q, nm, dedup, 0);
933 notmuch_message_destroy(nm);
934 }
935}
+ 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 946 of file notmuch.c.

947{
948 if (!query)
949 return NULL;
950
951 notmuch_messages_t *msgs = NULL;
952
953#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
954 if (notmuch_query_search_messages(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
955 return NULL;
956#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
957 if (notmuch_query_search_messages_st(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
958 return NULL;
959#else
960 msgs = notmuch_query_search_messages(query);
961#endif
962
963 return msgs;
964}
+ 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 974 of file notmuch.c.

975{
976 struct NmMboxData *mdata = nm_mdata_get(m);
977 if (!mdata)
978 return false;
979
980 int limit = get_limit(mdata);
981
982 notmuch_messages_t *msgs = get_messages(q);
983
984 if (!msgs)
985 return false;
986
987 struct HeaderCache *hc = nm_hcache_open(m);
988
989 for (; notmuch_messages_valid(msgs) && ((limit == 0) || (m->msg_count < limit));
990 notmuch_messages_move_to_next(msgs))
991 {
992 if (SigInt)
993 {
994 nm_hcache_close(&hc);
995 SigInt = false;
996 return false;
997 }
998 notmuch_message_t *nm = notmuch_messages_get(msgs);
999 append_message(hc, m, nm, dedup);
1000 notmuch_message_destroy(nm);
1001 }
1002
1003 nm_hcache_close(&hc);
1004 return true;
1005}
static int get_limit(struct NmMboxData *mdata)
Get the database limit.
Definition notmuch.c:414
static struct HeaderCache * nm_hcache_open(struct Mailbox *m)
Open a header cache.
Definition notmuch.c:111
static void nm_hcache_close(struct HeaderCache **ptr)
Close the header cache.
Definition notmuch.c:125
static notmuch_messages_t * get_messages(notmuch_query_t *query)
Load messages for a query.
Definition notmuch.c:946
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition signal.c:68
Header Cache.
Definition lib.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_threads()

static notmuch_threads_t * get_threads ( notmuch_query_t * query)
static

Load threads for a query.

Parameters
queryNotmuch query
Return values
ptrThreads matching query
NULLError occurred

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

Definition at line 1016 of file notmuch.c.

1017{
1018 if (!query)
1019 return NULL;
1020
1021 notmuch_threads_t *threads = NULL;
1022#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
1023 if (notmuch_query_search_threads(query, &threads) != NOTMUCH_STATUS_SUCCESS)
1024 return NULL;
1025#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
1026 if (notmuch_query_search_threads_st(query, &threads) != NOTMUCH_STATUS_SUCCESS)
1027 return NULL;
1028#else
1029 threads = notmuch_query_search_threads(query);
1030#endif
1031
1032 return threads;
1033}
+ 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 1044 of file notmuch.c.

1045{
1046 struct NmMboxData *mdata = nm_mdata_get(m);
1047 if (!mdata)
1048 return false;
1049
1050 notmuch_threads_t *threads = get_threads(q);
1051 if (!threads)
1052 return false;
1053
1054 struct HeaderCache *hc = nm_hcache_open(m);
1055
1056 for (; notmuch_threads_valid(threads) && ((limit == 0) || (m->msg_count < limit));
1057 notmuch_threads_move_to_next(threads))
1058 {
1059 if (SigInt)
1060 {
1061 nm_hcache_close(&hc);
1062 SigInt = false;
1063 return false;
1064 }
1065 notmuch_thread_t *thread = notmuch_threads_get(threads);
1066 append_thread(hc, m, q, thread, dedup);
1067 notmuch_thread_destroy(thread);
1068 }
1069
1070 nm_hcache_close(&hc);
1071 return true;
1072}
static notmuch_threads_t * get_threads(notmuch_query_t *query)
Load threads for a query.
Definition notmuch.c:1016
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:922
+ 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 1081 of file notmuch.c.

1082{
1083 notmuch_message_t *msg = NULL;
1084 char *id = email_get_id(e);
1085
1086 mutt_debug(LL_DEBUG2, "nm: find message (%s)\n", id);
1087
1088 if (id && db)
1089 notmuch_database_find_message(db, id, &msg);
1090
1091 return msg;
1092}
static char * email_get_id(struct Email *e)
Get the unique Notmuch Id.
Definition notmuch.c:214
+ 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,
const char * tag )
static

Does a message have this tag?

Parameters
msgNotmuch message
tagTag
Return values
trueIt does

Definition at line 1100 of file notmuch.c.

1101{
1102 const char *possible_match_tag = NULL;
1103 notmuch_tags_t *tags = NULL;
1104
1105 for (tags = notmuch_message_get_tags(msg); notmuch_tags_valid(tags);
1106 notmuch_tags_move_to_next(tags))
1107 {
1108 possible_match_tag = notmuch_tags_get(tags);
1109 if (mutt_str_equal(possible_match_tag, tag))
1110 {
1111 return true;
1112 }
1113 }
1114 return false;
1115}
+ 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 1122 of file notmuch.c.

1123{
1124 char *new_file = get_message_last_filename(msg);
1125 char old_file[PATH_MAX] = { 0 };
1126 email_get_fullpath(e, old_file, sizeof(old_file));
1127
1128 if (!mutt_str_equal(old_file, new_file))
1129 update_message_path(e, new_file);
1130
1131 FREE(&new_file);
1132}
static char * email_get_fullpath(struct Email *e, char *buf, size_t buflen)
Get the full path of an email.
Definition notmuch.c:230
+ 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 1141 of file notmuch.c.

1142{
1143 if (!tag_str)
1144 return -1;
1145
1146 notmuch_message_freeze(msg);
1147
1149 const char **tag_elem = NULL;
1150 ARRAY_FOREACH(tag_elem, &tags.tags)
1151 {
1152 const char *tag = *tag_elem;
1153
1154 if (tag[0] == '-')
1155 {
1156 mutt_debug(LL_DEBUG1, "nm: remove tag: '%s'\n", tag + 1);
1157 notmuch_message_remove_tag(msg, tag + 1);
1158 }
1159 else if (tag[0] == '!')
1160 {
1161 mutt_debug(LL_DEBUG1, "nm: toggle tag: '%s'\n", tag + 1);
1162 if (nm_message_has_tag(msg, tag + 1))
1163 {
1164 notmuch_message_remove_tag(msg, tag + 1);
1165 }
1166 else
1167 {
1168 notmuch_message_add_tag(msg, tag + 1);
1169 }
1170 }
1171 else
1172 {
1173 mutt_debug(LL_DEBUG1, "nm: add tag: '%s'\n", (tag[0] == '+') ? tag + 1 : tag);
1174 notmuch_message_add_tag(msg, (tag[0] == '+') ? tag + 1 : tag);
1175 }
1176 }
1177
1178 notmuch_message_thaw(msg);
1180
1181 return 0;
1182}
static bool nm_message_has_tag(notmuch_message_t *msg, const char *tag)
Does a message have this tag?
Definition notmuch.c:1100
char * tag_str
Source string.
Definition tag.h:38
+ 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 1195 of file notmuch.c.

1196{
1197 if (!tag_str)
1198 return -1;
1199
1200 const char *const c_nm_unread_tag = cs_subset_string(NeoMutt->sub, "nm_unread_tag");
1201 const char *const c_nm_replied_tag = cs_subset_string(NeoMutt->sub, "nm_replied_tag");
1202 const char *const c_nm_flagged_tag = cs_subset_string(NeoMutt->sub, "nm_flagged_tag");
1203
1205 const char **tag_elem = NULL;
1206 ARRAY_FOREACH(tag_elem, &tags.tags)
1207 {
1208 const char *tag = *tag_elem;
1209
1210 if (tag[0] == '-')
1211 {
1212 tag++;
1213 if (mutt_str_equal(tag, c_nm_unread_tag))
1214 mutt_set_flag(m, e, MUTT_READ, true, true);
1215 else if (mutt_str_equal(tag, c_nm_replied_tag))
1216 mutt_set_flag(m, e, MUTT_REPLIED, false, true);
1217 else if (mutt_str_equal(tag, c_nm_flagged_tag))
1218 mutt_set_flag(m, e, MUTT_FLAG, false, true);
1219 }
1220 else
1221 {
1222 tag = (tag[0] == '+') ? tag + 1 : tag;
1223 if (mutt_str_equal(tag, c_nm_unread_tag))
1224 mutt_set_flag(m, e, MUTT_READ, false, true);
1225 else if (mutt_str_equal(tag, c_nm_replied_tag))
1226 mutt_set_flag(m, e, MUTT_REPLIED, true, true);
1227 else if (mutt_str_equal(tag, c_nm_flagged_tag))
1228 mutt_set_flag(m, e, MUTT_FLAG, true, true);
1229 }
1230 }
1231
1233
1234 return 0;
1235}
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:54
@ MUTT_READ
Messages that have been read.
Definition mutt.h:92
@ MUTT_FLAG
Flagged messages.
Definition mutt.h:98
@ MUTT_REPLIED
Messages that have been replied to.
Definition mutt.h:91
+ 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 1247 of file notmuch.c.

1248{
1249 char filename[PATH_MAX] = { 0 };
1250 char suffix[PATH_MAX] = { 0 };
1251 char folder[PATH_MAX] = { 0 };
1252
1253 mutt_str_copy(folder, old, sizeof(folder));
1254 char *p = strrchr(folder, '/');
1255 if (p)
1256 {
1257 *p = '\0';
1258 p++;
1259 }
1260 else
1261 {
1262 p = folder;
1263 }
1264
1265 mutt_str_copy(filename, p, sizeof(filename));
1266
1267 /* remove (new,cur,...) from folder path */
1268 p = strrchr(folder, '/');
1269 if (p)
1270 *p = '\0';
1271
1272 /* remove old flags from filename */
1273 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
1274 p = strchr(filename, c_maildir_field_delimiter);
1275 if (p)
1276 *p = '\0';
1277
1278 /* compose new flags */
1279 maildir_gen_flags(suffix, sizeof(suffix), e);
1280
1281 snprintf(buf, buflen, "%s/%s/%s%s", folder,
1282 (e->read || e->old) ? "cur" : "new", filename, suffix);
1283
1284 if (mutt_str_equal(old, buf))
1285 return 1;
1286
1287 if (rename(old, buf) != 0)
1288 {
1289 mutt_debug(LL_DEBUG1, "nm: rename(2) failed %s -> %s\n", old, buf);
1290 return -1;
1291 }
1292
1293 return 0;
1294}
const char * cc_maildir_field_delimiter(void)
Get the cached value of $maildir_field_delimiter.
void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
Generate the Maildir flags for an email.
Definition message.c:71
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:583
bool read
Email is read.
Definition email.h:50
+ 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 1303 of file notmuch.c.

1304{
1305 struct NmMboxData *mdata = nm_mdata_get(m);
1306 if (!mdata)
1307 return -1;
1308
1309 mutt_debug(LL_DEBUG2, "nm: remove filename '%s'\n", path);
1310
1311 notmuch_database_t *db = nm_db_get(m, true);
1312 if (!db)
1313 return -1;
1314
1315 notmuch_message_t *msg = NULL;
1316 notmuch_status_t st = notmuch_database_find_message_by_filename(db, path, &msg);
1317 if (st || !msg)
1318 return -1;
1319
1320 int trans = nm_db_trans_begin(m);
1321 if (trans < 0)
1322 return -1;
1323
1324 /* note that unlink() is probably unnecessary here, it's already removed
1325 * by mh_sync_mailbox_message(), but for sure... */
1326 notmuch_filenames_t *ls = NULL;
1327 st = notmuch_database_remove_message(db, path);
1328 switch (st)
1329 {
1330 case NOTMUCH_STATUS_SUCCESS:
1331 mutt_debug(LL_DEBUG2, "nm: remove success, call unlink\n");
1332 unlink(path);
1333 break;
1334 case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
1335 mutt_debug(LL_DEBUG2, "nm: remove success (duplicate), call unlink\n");
1336 unlink(path);
1337 for (ls = notmuch_message_get_filenames(msg);
1338 ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
1339 {
1340 path = notmuch_filenames_get(ls);
1341
1342 mutt_debug(LL_DEBUG2, "nm: remove duplicate: '%s'\n", path);
1343 unlink(path);
1344 notmuch_database_remove_message(db, path);
1345 }
1346 break;
1347 default:
1348 mutt_debug(LL_DEBUG1, "nm: failed to remove '%s' [st=%d]\n", path, (int) st);
1349 break;
1350 }
1351
1352 notmuch_message_destroy(msg);
1353 if (trans)
1354 nm_db_trans_end(m);
1355 return 0;
1356}
int nm_db_trans_begin(struct Mailbox *m)
Start a Notmuch database transaction.
Definition db.c:266
int nm_db_trans_end(struct Mailbox *m)
End a database transaction.
Definition db.c:288
+ 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 1367 of file notmuch.c.

1369{
1370 struct NmMboxData *mdata = nm_mdata_get(m);
1371 if (!mdata)
1372 return -1;
1373
1374 notmuch_database_t *db = nm_db_get(m, true);
1375 if (!db || !new_file || !old_file || (access(new_file, F_OK) != 0))
1376 return -1;
1377
1378 int rc = -1;
1379 notmuch_status_t st;
1380 notmuch_filenames_t *ls = NULL;
1381 notmuch_message_t *msg = NULL;
1382
1383 mutt_debug(LL_DEBUG1, "nm: rename filename, %s -> %s\n", old_file, new_file);
1384 int trans = nm_db_trans_begin(m);
1385 if (trans < 0)
1386 return -1;
1387
1388 mutt_debug(LL_DEBUG2, "nm: rename: add '%s'\n", new_file);
1389#if LIBNOTMUCH_CHECK_VERSION(5, 1, 0)
1390 st = notmuch_database_index_file(db, new_file, NULL, &msg);
1391#else
1392 st = notmuch_database_add_message(db, new_file, &msg);
1393#endif
1394
1395 if ((st != NOTMUCH_STATUS_SUCCESS) && (st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID))
1396 {
1397 mutt_debug(LL_DEBUG1, "nm: failed to add '%s' [st=%d]\n", new_file, (int) st);
1398 goto done;
1399 }
1400
1401 mutt_debug(LL_DEBUG2, "nm: rename: rem '%s'\n", old_file);
1402 st = notmuch_database_remove_message(db, old_file);
1403 switch (st)
1404 {
1405 case NOTMUCH_STATUS_SUCCESS:
1406 break;
1407 case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
1408 mutt_debug(LL_DEBUG2, "nm: rename: syncing duplicate filename\n");
1409 notmuch_message_destroy(msg);
1410 msg = NULL;
1411 notmuch_database_find_message_by_filename(db, new_file, &msg);
1412
1413 for (ls = notmuch_message_get_filenames(msg);
1414 msg && ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
1415 {
1416 const char *path = notmuch_filenames_get(ls);
1417 char newpath[PATH_MAX] = { 0 };
1418
1419 if (mutt_str_equal(new_file, path))
1420 continue;
1421
1422 mutt_debug(LL_DEBUG2, "nm: rename: syncing duplicate: %s\n", path);
1423
1424 if (rename_maildir_filename(path, newpath, sizeof(newpath), e) == 0)
1425 {
1426 mutt_debug(LL_DEBUG2, "nm: rename dup %s -> %s\n", path, newpath);
1427 notmuch_database_remove_message(db, path);
1428#if LIBNOTMUCH_CHECK_VERSION(5, 1, 0)
1429 notmuch_database_index_file(db, newpath, NULL, NULL);
1430#else
1431 notmuch_database_add_message(db, newpath, NULL);
1432#endif
1433 }
1434 }
1435 notmuch_message_destroy(msg);
1436 msg = NULL;
1437 notmuch_database_find_message_by_filename(db, new_file, &msg);
1438 st = NOTMUCH_STATUS_SUCCESS;
1439 break;
1440 default:
1441 mutt_debug(LL_DEBUG1, "nm: failed to remove '%s' [st=%d]\n", old_file, (int) st);
1442 break;
1443 }
1444
1445 if ((st == NOTMUCH_STATUS_SUCCESS) && e && msg)
1446 {
1447 notmuch_message_maildir_flags_to_tags(msg);
1448 update_email_tags(e, msg);
1449
1450 struct Buffer *tags = buf_pool_get();
1451 driver_tags_get(&e->tags, tags);
1452 update_tags(msg, buf_string(tags));
1453 buf_pool_release(&tags);
1454 }
1455
1456 rc = 0;
1457done:
1458 if (msg)
1459 notmuch_message_destroy(msg);
1460 if (trans)
1461 nm_db_trans_end(m);
1462 return rc;
1463}
static int rename_maildir_filename(const char *old, char *buf, size_t buflen, struct Email *e)
Rename a Maildir file.
Definition notmuch.c:1247
static int update_tags(notmuch_message_t *msg, const char *tag_str)
Update the tags on a message.
Definition notmuch.c:1141
+ 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 1472 of file notmuch.c.

1473{
1474 notmuch_query_t *q = notmuch_query_create(db, qstr);
1475 if (!q)
1476 return 0;
1477
1478 unsigned int res = 0;
1479
1481#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
1482 if (notmuch_query_count_messages(q, &res) != NOTMUCH_STATUS_SUCCESS)
1483 res = 0; /* may not be defined on error */
1484#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
1485 if (notmuch_query_count_messages_st(q, &res) != NOTMUCH_STATUS_SUCCESS)
1486 res = 0; /* may not be defined on error */
1487#else
1488 res = notmuch_query_count_messages(q);
1489#endif
1490 notmuch_query_destroy(q);
1491 mutt_debug(LL_DEBUG1, "nm: count '%s', result=%d\n", qstr, res);
1492
1493 if ((limit > 0) && (res > limit))
1494 res = limit;
1495
1496 return res;
1497}
+ 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 1505 of file notmuch.c.

1506{
1507 struct NmEmailData *edata = nm_edata_get(e);
1508 if (!edata)
1509 return NULL;
1510
1511 return edata->folder;
1512}
+ 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 1524 of file notmuch.c.

1525{
1526 char *full_folder = nm_email_get_folder(e);
1527 if (!full_folder)
1528 return NULL;
1529
1530 const char *db_path = nm_db_get_filename(m);
1531 if (!db_path)
1532 return NULL;
1533
1534 size_t prefix = mutt_str_startswith(full_folder, db_path);
1535
1536 char *path = full_folder + prefix;
1537 if (*path == '/')
1538 path++;
1539
1540 return path;
1541}
const char * nm_db_get_filename(struct Mailbox *m)
Get the filename of the Notmuch database.
Definition db.c:58
+ 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 1550 of file notmuch.c.

1551{
1552 if (!m)
1553 return -1;
1554
1555 struct NmMboxData *mdata = nm_mdata_get(m);
1556 if (!mdata)
1557 return -1;
1558
1559 notmuch_query_t *q = NULL;
1560 notmuch_database_t *db = NULL;
1561 notmuch_message_t *msg = NULL;
1562 int rc = -1;
1563
1564 if (!(db = nm_db_get(m, false)) || !(msg = get_nm_message(db, e)))
1565 goto done;
1566
1567 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages...[current count=%d]\n",
1568 m->msg_count);
1569
1570 progress_setup(m);
1571 const char *id = notmuch_message_get_thread_id(msg);
1572 if (!id)
1573 goto done;
1574
1575 struct Buffer *qstr = buf_pool_get();
1576 buf_printf(qstr, "thread:%s", id);
1577 q = notmuch_query_create(db, buf_string(qstr));
1578 buf_pool_release(&qstr);
1579 if (!q)
1580 goto done;
1582 notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
1583
1584 read_threads_query(m, q, true, 0);
1585 mdata->mtime.tv_sec = mutt_date_now();
1586 mdata->mtime.tv_nsec = 0;
1587 rc = 0;
1588
1589 if (m->msg_count > mdata->oldmsgcount)
1591done:
1592 if (q)
1593 notmuch_query_destroy(q);
1594
1595 nm_db_release(m);
1596
1597 if (m->msg_count == mdata->oldmsgcount)
1598 mutt_message(_("No more messages in the thread"));
1599
1600 mdata->oldmsgcount = 0;
1601 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
1602 rc, m->msg_count);
1603 progress_free(&mdata->progress);
1604 return rc;
1605}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition mailbox.c:232
@ NT_MAILBOX_INVALID
Email list was changed.
Definition mailbox.h:179
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
static notmuch_message_t * get_nm_message(notmuch_database_t *db, struct Email *e)
Find a Notmuch message.
Definition notmuch.c:1081
static bool read_threads_query(struct Mailbox *m, notmuch_query_t *q, bool dedup, int limit)
Perform a query with threads.
Definition notmuch.c:1044
static void progress_setup(struct Mailbox *m)
Set up the Progress Bar.
Definition notmuch.c:704
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition progress.c:110
int oldmsgcount
Old message count.
Definition mdata.h:42
struct Progress * progress
A progress bar.
Definition mdata.h:41
struct timespec mtime
Time Mailbox was last changed.
Definition mdata.h:44
+ 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 1615 of file notmuch.c.

1616{
1617 mutt_debug(LL_DEBUG2, "(%s)\n", buf);
1618 struct NmMboxData *mdata = nm_mdata_get(m);
1619 char url[PATH_MAX + 1024 + 32]; /* path to DB + query + URL "decoration" */
1620 int added;
1621 bool using_default_data = false;
1622
1623 // No existing data. Try to get a default NmMboxData.
1624 if (!mdata)
1625 {
1627
1628 // Failed to get default data.
1629 if (!mdata)
1630 return NULL;
1631
1632 using_default_data = true;
1633 }
1634
1636 cs_subset_string(NeoMutt->sub, "nm_query_type"));
1637 mdata->query_type = nm_parse_type_from_query(buf, query_type);
1638
1639 const short c_nm_db_limit = cs_subset_number(NeoMutt->sub, "nm_db_limit");
1640 if (get_limit(mdata) == c_nm_db_limit)
1641 {
1642 added = snprintf(url, sizeof(url), "%s%s?type=%s&query=", NmUrlProtocol,
1644 }
1645 else
1646 {
1647 added = snprintf(url, sizeof(url), "%s%s?type=%s&limit=%d&query=", NmUrlProtocol,
1650 }
1651
1652 if (added >= sizeof(url))
1653 {
1654 // snprintf output was truncated, so can't create URL
1655 return NULL;
1656 }
1657
1658 url_pct_encode(&url[added], sizeof(url) - added, buf);
1659
1660 mutt_str_copy(buf, url, buflen);
1661 buf[buflen - 1] = '\0';
1662
1663 if (using_default_data)
1664 nm_mdata_free((void **) &mdata);
1665
1666 mutt_debug(LL_DEBUG1, "nm: url from query '%s'\n", buf);
1667 return buf;
1668}
static struct NmMboxData * nm_get_default_data(void)
Create a Mailbox with default Notmuch settings.
Definition notmuch.c:169
const char NmUrlProtocol[]
Protocol string for Notmuch URLs.
Definition notmuch.c:102
enum NmQueryType nm_parse_type_from_query(char *buf, enum NmQueryType fallback)
Parse a query type out of a query.
Definition query.c:50
const char * nm_query_type_to_string(enum NmQueryType query_type)
Turn a query type into a string.
Definition query.c:97
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:152
+ 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 1674 of file notmuch.c.

1675{
1676 const short c_nm_query_window_duration = cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
1677 const bool c_nm_query_window_enable = cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
1678
1679 return c_nm_query_window_enable || (c_nm_query_window_duration > 0);
1680}
+ 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 1691 of file notmuch.c.

1692{
1693 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1694 if (c_nm_query_window_current_position != 0)
1695 {
1696 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1697 c_nm_query_window_current_position - 1, NULL);
1698 }
1699
1700 mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position - 1);
1701}
+ 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 1711 of file notmuch.c.

1712{
1713 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1714 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1715 c_nm_query_window_current_position + 1, NULL);
1716 mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position + 1);
1717}
+ 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 1722 of file notmuch.c.

1723{
1724 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position", 0, NULL);
1725 mutt_debug(LL_DEBUG2, "Reset nm_query_window_current_position to 0\n");
1726}
+ 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 1734 of file notmuch.c.

1735{
1736 struct NmMboxData *mdata = nm_mdata_get(m);
1737 if (!mdata)
1738 return false;
1739
1740 notmuch_database_t *db = nm_db_get(m, false);
1741 char *orig_str = get_query_string(mdata, true);
1742
1743 if (!db || !orig_str)
1744 {
1745 nm_db_release(m);
1746 return false;
1747 }
1748
1749 char *new_str = NULL;
1750 bool rc = false;
1751 if (mutt_str_asprintf(&new_str, "id:%s and (%s)", email_get_id(e), orig_str) < 0)
1752 {
1753 nm_db_release(m);
1754 return false;
1755 }
1756
1757 mutt_debug(LL_DEBUG2, "nm: checking if message is still queried: %s\n", new_str);
1758
1759 notmuch_query_t *q = notmuch_query_create(db, new_str);
1760
1761 switch (mdata->query_type)
1762 {
1763 case NM_QUERY_TYPE_UNKNOWN: // UNKNOWN should never occur, but MESGS is default
1765 {
1766 notmuch_messages_t *messages = get_messages(q);
1767
1768 if (!messages)
1769 goto done;
1770
1771 rc = notmuch_messages_valid(messages);
1772 notmuch_messages_destroy(messages);
1773 break;
1774 }
1776 {
1777 notmuch_threads_t *threads = get_threads(q);
1778
1779 if (!threads)
1780 goto done;
1781
1782 rc = notmuch_threads_valid(threads);
1783 notmuch_threads_destroy(threads);
1784 break;
1785 }
1786 }
1787
1788done:
1789 notmuch_query_destroy(q);
1790
1791 mutt_debug(LL_DEBUG2, "nm: checking if message is still queried: %s = %s\n",
1792 new_str, rc ? "true" : "false");
1793
1794 FREE(&new_str);
1795 nm_db_release(m);
1796 return rc;
1797}
@ 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 1808 of file notmuch.c.

1810{
1811 char buf[PATH_MAX] = { 0 };
1812 struct NmMboxData *mdata = nm_mdata_get(m);
1813 if (!mdata || !new_file)
1814 return -1;
1815
1816 if (!old_file && nm_edata_get(e))
1817 {
1818 email_get_fullpath(e, buf, sizeof(buf));
1819 old_file = buf;
1820 }
1821
1822 int rc = rename_filename(m, old_file, new_file, e);
1823
1824 nm_db_release(m);
1825 mdata->mtime.tv_sec = mutt_date_now();
1826 mdata->mtime.tv_nsec = 0;
1827 return rc;
1828}
static int rename_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Rename the file.
Definition notmuch.c:1367
+ 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 1918 of file notmuch.c.

1919{
1920 // Create a new notmuch mailbox from scratch and add plumbing for DB access.
1921 char *default_url = nm_get_default_url();
1922 struct Mailbox *m = mx_path_resolve(default_url);
1923
1924 FREE(&default_url);
1925
1926 // These are no-ops for an initialized mailbox.
1927 init_mailbox(m);
1928 mx_mbox_ac_link(m);
1929
1930 return m;
1931}
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition mx.c:248
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1647
static int init_mailbox(struct Mailbox *m)
Add Notmuch data to the Mailbox.
Definition notmuch.c:192
A mailbox.
Definition mailbox.h:78
+ 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 1941 of file notmuch.c.

1942{
1943 notmuch_database_t *db = NULL;
1944 notmuch_status_t st;
1945 notmuch_message_t *msg = NULL;
1946 int rc = -1;
1947
1948 struct NmMboxData *mdata = nm_mdata_get(m);
1949
1950 // If no notmuch data, fall back to the default mailbox.
1951 //
1952 // IMPORTANT: DO NOT FREE THIS MAILBOX. Two reasons:
1953 // 1) If user has default mailbox in config, we'll be removing it. That's not
1954 // good program behavior!
1955 // 2) If not in user's config, keep mailbox around for future nm_record calls.
1956 // It saves NeoMutt from allocating/deallocating repeatedly.
1957 if (!mdata)
1958 {
1959 mutt_debug(LL_DEBUG1, "nm: non-nm mailbox. trying the default nm mailbox.\n");
1960 m = get_default_mailbox();
1961 mdata = nm_mdata_get(m);
1962 }
1963
1964 if (!path || !mdata || (access(path, F_OK) != 0))
1965 return 0;
1966 db = nm_db_get(m, true);
1967 if (!db)
1968 return -1;
1969
1970 mutt_debug(LL_DEBUG1, "nm: record message: %s\n", path);
1971 int trans = nm_db_trans_begin(m);
1972 if (trans < 0)
1973 goto done;
1974
1975#if LIBNOTMUCH_CHECK_VERSION(5, 1, 0)
1976 st = notmuch_database_index_file(db, path, NULL, &msg);
1977#else
1978 st = notmuch_database_add_message(db, path, &msg);
1979#endif
1980
1981 if ((st != NOTMUCH_STATUS_SUCCESS) && (st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID))
1982 {
1983 mutt_debug(LL_DEBUG1, "nm: failed to add '%s' [st=%d]\n", path, (int) st);
1984 goto done;
1985 }
1986
1987 if ((st == NOTMUCH_STATUS_SUCCESS) && msg)
1988 {
1989 notmuch_message_maildir_flags_to_tags(msg);
1990 if (e)
1991 {
1992 struct Buffer *tags = buf_pool_get();
1993 driver_tags_get(&e->tags, tags);
1994 update_tags(msg, buf_string(tags));
1995 buf_pool_release(&tags);
1996 }
1997 const char *const c_nm_record_tags = cs_subset_string(NeoMutt->sub, "nm_record_tags");
1998 if (c_nm_record_tags)
1999 update_tags(msg, c_nm_record_tags);
2000 }
2001
2002 rc = 0;
2003done:
2004 if (msg)
2005 notmuch_message_destroy(msg);
2006 if (trans == 1)
2007 nm_db_trans_end(m);
2008
2009 nm_db_release(m);
2010
2011 return rc;
2012}
static struct Mailbox * get_default_mailbox(void)
Get Mailbox for notmuch without any parameters.
Definition notmuch.c:1918
+ 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 2024 of file notmuch.c.

2025{
2026 struct NmMboxData *mdata = nm_mdata_get(m);
2027 if (!mdata || !tag_count)
2028 return -1;
2029
2030 notmuch_database_t *db = NULL;
2031 notmuch_tags_t *tags = NULL;
2032 const char *tag = NULL;
2033 int rc = -1;
2034
2035 if (!(db = nm_db_get(m, false)) || !(tags = notmuch_database_get_all_tags(db)))
2036 goto done;
2037
2038 *tag_count = 0;
2039 mutt_debug(LL_DEBUG1, "nm: get all tags\n");
2040
2041 while (notmuch_tags_valid(tags))
2042 {
2043 tag = notmuch_tags_get(tags);
2044 /* Skip empty string */
2045 if (*tag)
2046 {
2047 if (tag_list)
2048 tag_list[*tag_count] = mutt_str_dup(tag);
2049 (*tag_count)++;
2050 }
2051 notmuch_tags_move_to_next(tags);
2052 }
2053
2054 rc = 0;
2055done:
2056 if (tags)
2057 notmuch_tags_destroy(tags);
2058
2059 nm_db_release(m);
2060
2061 mutt_debug(LL_DEBUG1, "nm: get all tags done [rc=%d tag_count=%u]\n", rc, *tag_count);
2062 return rc;
2063}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ NmCommands

const struct Command NmCommands[]
Initial value:
= {
{ "unvirtual-mailboxes", CMD_NONE, NULL, "unmailboxes", NULL, NULL, CF_SYNONYM },
{ "virtual-mailboxes", CMD_NONE, NULL, "named-mailboxes", NULL, NULL, CF_SYNONYM },
{ NULL, CMD_NONE, NULL, NULL, NULL, NULL, CF_NO_FLAGS },
}
#define CF_SYNONYM
Command is a synonym for another command.
Definition command.h:49
#define CF_NO_FLAGS
No flags are set.
Definition command.h:48
@ CMD_NONE
No Command.
Definition command.h:59

Notmuch Commands.

Definition at line 91 of file notmuch.c.

91 {
92 // clang-format off
93 // Deprecated
94 { "unvirtual-mailboxes", CMD_NONE, NULL, "unmailboxes", NULL, NULL, CF_SYNONYM },
95 { "virtual-mailboxes", CMD_NONE, NULL, "named-mailboxes", NULL, NULL, CF_SYNONYM },
96
97 { NULL, CMD_NONE, NULL, NULL, NULL, NULL, CF_NO_FLAGS },
98 // clang-format on
99};

◆ NmUrlProtocol

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

Protocol string for Notmuch URLs.

Definition at line 102 of file notmuch.c.

◆ NmUrlProtocolLen

const int NmUrlProtocolLen = sizeof(NmUrlProtocol) - 1

Length of NmUrlProtocol string.

Definition at line 104 of file notmuch.c.