NeoMutt  2025-04-04-8-g381e07
Teaching an old dog new tricks
DOXYGEN
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 "progress/lib.h"
#include "adata.h"
#include "commands.h"
#include "edata.h"
#include "maildir/shared.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() -.
 

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
  • 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_init()

void nm_init ( void  )

Setup feature commands.

Definition at line 109 of file notmuch.c.

110{
112}
bool commands_register(struct CommandArray *ca, const struct Command *cmds)
Add commands to Commands array.
Definition: command.c:51
static const struct Command NmCommands[]
Notmuch Commands.
Definition: notmuch.c:93
Container for Accounts, Notifications.
Definition: neomutt.h:43
struct CommandArray commands
NeoMutt commands.
Definition: neomutt.h:51
+ 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 119 of file notmuch.c.

120{
121#ifdef USE_HCACHE
122 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
123 return hcache_open(c_header_cache, mailbox_path(m), NULL, true);
124#else
125 return NULL;
126#endif
127}
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:223
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer, bool create)
Multiplexor for StoreOps::open.
Definition: hcache.c:471
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:47
+ 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 133 of file notmuch.c.

134{
135#ifdef USE_HCACHE
136 hcache_close(ptr);
137#endif
138}
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition: hcache.c:542
+ 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 145 of file notmuch.c.

146{
147 // path to DB + query + url "decoration"
148 size_t len = PATH_MAX + 1024 + 32;
149 char *url = MUTT_MEM_MALLOC(len, char);
150
151 // Try to use `$nm_default_url` or `$folder`.
152 // If neither are set, it is impossible to create a Notmuch URL.
153 const char *const c_nm_default_url = cs_subset_string(NeoMutt->sub, "nm_default_url");
154 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
155 if (c_nm_default_url)
156 {
157 snprintf(url, len, "%s", c_nm_default_url);
158 }
159 else if (c_folder)
160 {
161 snprintf(url, len, "notmuch://%s", c_folder);
162 }
163 else
164 {
165 FREE(&url);
166 return NULL;
167 }
168
169 return url;
170}
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)
Definition: memory.h:55
#define MUTT_MEM_MALLOC(n, type)
Definition: memory.h:41
#define PATH_MAX
Definition: mutt.h:42
+ 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 177 of file notmuch.c.

178{
179 // path to DB + query + url "decoration"
180 char *url = nm_get_default_url();
181 if (!url)
182 return NULL;
183
184 struct NmMboxData *default_data = nm_mdata_new(url);
185 FREE(&url);
186
187 return default_data;
188}
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:145
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 200 of file notmuch.c.

201{
202 if (!m || (m->type != MUTT_NOTMUCH))
203 return -1;
204
205 if (m->mdata)
206 return 0;
207
209 if (!m->mdata)
210 return -1;
211
213 return 0;
214}
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
void nm_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free() -.
Definition: mdata.c:45
void(* mdata_free)(void **ptr)
Definition: mailbox.h:143
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
void * mdata
Driver specific data.
Definition: mailbox.h:132
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ email_get_id()

static char * email_get_id ( struct Email e)
static

Get the unique Notmuch Id.

Parameters
eEmail
Return values
ptrID string
NULLError

Definition at line 222 of file notmuch.c.

223{
224 struct NmEmailData *edata = nm_edata_get(e);
225 if (!edata)
226 return NULL;
227
228 return edata->virtual_id;
229}
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 238 of file notmuch.c.

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

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

284{
285 mutt_debug(LL_DEBUG2, "nm: %s\n", query);
286
287 const bool c_nm_query_window_enable = cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
288 const short c_nm_query_window_duration = cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
289 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
290 const char *const c_nm_query_window_current_search = cs_subset_string(NeoMutt->sub, "nm_query_window_current_search");
291 const char *const c_nm_query_window_timebase = cs_subset_string(NeoMutt->sub, "nm_query_window_timebase");
292 const char *const c_nm_query_window_or_terms = cs_subset_string(NeoMutt->sub, "nm_query_window_or_terms");
293
294 /* if the query has changed, reset the window position */
295 if (!c_nm_query_window_current_search || !mutt_str_equal(query, c_nm_query_window_current_search))
296 {
298 }
299
301 buf, buflen, c_nm_query_window_enable, c_nm_query_window_duration,
302 c_nm_query_window_current_position, c_nm_query_window_current_search,
303 c_nm_query_window_timebase, c_nm_query_window_or_terms);
304
305 switch (rc)
306 {
308 {
309 mutt_debug(LL_DEBUG2, "nm: %s -> %s\n", query, buf);
310 break;
311 }
313 {
315 return false;
316 }
318 {
320 // L10N: The values 'hour', 'day', 'week', 'month', 'year' are literal.
321 // They should not be translated.
322 _("Invalid nm_query_window_timebase value (valid values are: hour, day, week, month, year)"));
323 mutt_debug(LL_DEBUG2, "Invalid nm_query_window_timebase value\n");
324 return false;
325 }
326 }
327
328 return true;
329}
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:92
#define _(a)
Definition: message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:661
static void query_window_reset(void)
Restore vfolder's search window to its original position.
Definition: notmuch.c:253
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:206
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 347 of file notmuch.c.

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

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

425{
426 const char *const c_nm_exclude_tags = cs_subset_string(NeoMutt->sub, "nm_exclude_tags");
427 if (!c_nm_exclude_tags || !query)
428 return;
429
430 struct NmTags tags = nm_tag_str_to_tags(c_nm_exclude_tags);
431
432 char **tag = NULL;
433 ARRAY_FOREACH(tag, &tags.tags)
434 {
435 mutt_debug(LL_DEBUG2, "nm: query exclude tag '%s'\n", *tag);
436 notmuch_query_add_tag_exclude(query, *tag);
437 }
438
439 notmuch_query_set_omit_excluded(query, 1);
441}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:214
Array of Notmuch tags.
Definition: tag.h:38
struct TagArray tags
Tags.
Definition: tag.h:39
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 450 of file notmuch.c.

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

483{
484 struct NmEmailData *edata = nm_edata_get(e);
485 struct Buffer *new_tags = buf_pool_get();
486 struct Buffer *old_tags = buf_pool_get();
487
488 mutt_debug(LL_DEBUG2, "nm: tags update requested (%s)\n", edata->virtual_id);
489
490 for (notmuch_tags_t *tags = notmuch_message_get_tags(msg);
491 tags && notmuch_tags_valid(tags); notmuch_tags_move_to_next(tags))
492 {
493 const char *t = notmuch_tags_get(tags);
494 if (!t || (*t == '\0'))
495 continue;
496
497 buf_join_str(new_tags, t, ' ');
498 }
499
500 driver_tags_get(&e->tags, old_tags);
501
502 if (!buf_is_empty(new_tags) && !buf_is_empty(old_tags) &&
503 (buf_str_equal(old_tags, new_tags)))
504 {
505 buf_pool_release(&new_tags);
506 buf_pool_release(&old_tags);
507 mutt_debug(LL_DEBUG2, "nm: tags unchanged\n");
508 return 1;
509 }
510 buf_pool_release(&old_tags);
511
512 /* new version */
513 driver_tags_replace(&e->tags, buf_string(new_tags));
514 buf_reset(new_tags);
515
516 driver_tags_get_transformed(&e->tags, new_tags);
517 mutt_debug(LL_DEBUG2, "nm: new tags transformed: '%s'\n", buf_string(new_tags));
518 buf_reset(new_tags);
519
520 driver_tags_get(&e->tags, new_tags);
521 mutt_debug(LL_DEBUG2, "nm: new tag: '%s'\n", buf_string(new_tags));
522 buf_pool_release(&new_tags);
523
524 return 0;
525}
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:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
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:201
void driver_tags_get(struct TagList *tl, struct Buffer *tags)
Get tags all tags separated by space.
Definition: tags.c:164
void driver_tags_get_transformed(struct TagList *tl, struct Buffer *tags)
Get transformed tags separated by space.
Definition: tags.c:152
+ 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 534 of file notmuch.c.

535{
536 struct NmEmailData *edata = nm_edata_get(e);
537
538 mutt_debug(LL_DEBUG2, "nm: path update requested path=%s, (%s)\n", path, edata->virtual_id);
539
540 char *p = strrchr(path, '/');
541 if (p && ((p - path) > 3) &&
542 (mutt_strn_equal(p - 3, "cur", 3) || mutt_strn_equal(p - 3, "new", 3) ||
543 mutt_strn_equal(p - 3, "tmp", 3)))
544 {
545 edata->type = MUTT_MAILDIR;
546
547 FREE(&e->path);
548 FREE(&edata->folder);
549
550 p -= 3; /* skip subfolder (e.g. "new") */
551 if (cs_subset_bool(NeoMutt->sub, "mark_old"))
552 {
553 e->old = mutt_str_startswith(p, "cur");
554 }
555 e->path = mutt_str_dup(p);
556
557 for (; (p > path) && (*(p - 1) == '/'); p--)
558 ; // do nothing
559
560 edata->folder = mutt_strn_dup(path, p - path);
561
562 mutt_debug(LL_DEBUG2, "nm: folder='%s', file='%s'\n", edata->folder, e->path);
563
564 // We _might_ be looking at a different file (with the same message-id)
565 // so reparse it from scratch.
566
567 // Preserve the message-id as it's used in the Email HashTable
568 mutt_debug(LL_DEBUG1, "nm: reparse the message\n");
569 char *message_id = e->env->message_id;
570 e->env->message_id = NULL;
571
572 mutt_body_free(&e->body);
573 mutt_env_free(&e->env);
574 if (!maildir_parse_message(path, e->old, e))
575 return 1;
576
577 ASSERT(e->body);
578 ASSERT(e->env);
579
580 FREE(&e->env->message_id);
581 e->env->message_id = message_id;
582 message_id = NULL;
583
584 return 0;
585 }
586
587 return 1;
588}
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
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:126
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:44
bool maildir_parse_message(const char *fname, bool is_old, struct Email *e)
Actually parse a maildir message.
Definition: mailbox.c:194
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:381
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:254
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:426
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:231
#define ASSERT(COND)
Definition: signal2.h:60
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 596 of file notmuch.c.

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

622{
623 if (!id)
624 return NULL;
625
626 char *mid = NULL;
627 mutt_str_asprintf(&mid, "<%s>", id);
628 return mid;
629}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:804
+ 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 639 of file notmuch.c.

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

◆ get_message_last_filename()

static const char * get_message_last_filename ( notmuch_message_t *  msg)
static

Get a message's last filename.

Parameters
msgNotmuch message
Return values
ptrFilename
NULLError

Definition at line 683 of file notmuch.c.

684{
685 const char *name = NULL;
686
687 for (notmuch_filenames_t *ls = notmuch_message_get_filenames(msg);
688 ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
689 {
690 name = notmuch_filenames_get(ls);
691 }
692
693 return name;
694}
+ 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 700 of file notmuch.c.

701{
702 if (!m->verbose)
703 return;
704
705 struct NmMboxData *mdata = nm_mdata_get(m);
706 if (!mdata)
707 return;
708
709 mdata->oldmsgcount = m->msg_count;
710 mdata->ignmsgcount = 0;
711 mdata->progress = progress_new(MUTT_PROGRESS_READ, mdata->oldmsgcount);
712 progress_set_message(mdata->progress, _("Reading messages..."));
713}
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:83
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:88
bool verbose
Display status messages?
Definition: mailbox.h:117
+ 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 719 of file notmuch.c.

720{
721 struct NmMboxData *mdata = nm_mdata_get(m);
722
723 if (!m->verbose || !mdata || !mdata->progress)
724 return;
725
726 progress_update(mdata->progress, m->msg_count + mdata->ignmsgcount, -1);
727}
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 736 of file notmuch.c.

737{
738 if (!m || !msg)
739 return NULL;
740
741 const char *id = notmuch_message_get_message_id(msg);
742 if (!id)
743 return NULL;
744
745 mutt_debug(LL_DEBUG2, "nm: neomutt email, id='%s'\n", id);
746
747 if (!m->id_hash)
748 {
749 mutt_debug(LL_DEBUG2, "nm: init hash\n");
751 if (!m->id_hash)
752 return NULL;
753 }
754
755 char *mid = nm2mutt_message_id(id);
756 mutt_debug(LL_DEBUG2, "nm: neomutt id='%s'\n", mid);
757
758 struct Email *e = mutt_hash_find(m->id_hash, mid);
759 FREE(&mid);
760 return e;
761}
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:1702
The envelope/body of an email.
Definition: email.h:39
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
Definition: mailbox.h:123
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ append_message()

static void append_message ( struct HeaderCache 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 770 of file notmuch.c.

772{
773 struct NmMboxData *mdata = nm_mdata_get(m);
774 if (!mdata)
775 return;
776
777 char *newpath = NULL;
778 struct Email *e = NULL;
779
780 /* deduplicate */
781 if (dedup && get_mutt_email(m, msg))
782 {
783 mdata->ignmsgcount++;
785 mutt_debug(LL_DEBUG2, "nm: ignore id=%s, already in the m\n",
786 notmuch_message_get_message_id(msg));
787 return;
788 }
789
790 const char *path = get_message_last_filename(msg);
791 if (!path)
792 return;
793
794 mutt_debug(LL_DEBUG2, "nm: appending message, i=%d, id=%s, path=%s\n",
795 m->msg_count, notmuch_message_get_message_id(msg), path);
796
798
799#ifdef USE_HCACHE
801 if (!e)
802#endif
803 {
804 if (access(path, F_OK) == 0)
805 {
806 /* We pass is_old=false as argument here, but e->old will be updated later
807 * by update_message_path() (called by init_email() below). */
808 e = maildir_email_new();
809 if (!maildir_parse_message(path, false, e))
810 email_free(&e);
811 }
812 else
813 {
814 /* maybe moved try find it... */
815 char *folder = get_folder_from_path(path);
816
817 if (folder)
818 {
819 FILE *fp = maildir_open_find_message(folder, path, &newpath);
820 if (fp)
821 {
822 e = maildir_email_new();
823 if (!maildir_parse_stream(fp, newpath, false, e))
824 email_free(&e);
825 mutt_file_fclose(&fp);
826
827 mutt_debug(LL_DEBUG1, "nm: not up-to-date: %s -> %s\n", path, newpath);
828 }
829 }
830 FREE(&folder);
831 }
832
833 if (!e)
834 {
835 mutt_debug(LL_DEBUG1, "nm: failed to parse message: %s\n", path);
836 goto done;
837 }
838
839#ifdef USE_HCACHE
840 hcache_store_email(hc, newpath ? newpath : path,
841 mutt_str_len(newpath ? newpath : path), e, 0);
842#endif
843 }
844
845 if (init_email(e, newpath ? newpath : path, msg) != 0)
846 {
847 email_free(&e);
848 mutt_debug(LL_DEBUG1, "nm: failed to append email!\n");
849 goto done;
850 }
851
852 e->active = true;
853 e->index = m->msg_count;
854 mailbox_size_add(m, e);
855 m->emails[m->msg_count] = e;
856 m->msg_count++;
857
858 if (newpath)
859 {
860 /* remember that file has been moved -- nm_mbox_sync() will update the DB */
861 struct NmEmailData *edata = nm_edata_get(e);
862 if (edata)
863 {
864 mutt_debug(LL_DEBUG1, "nm: remember obsolete path: %s\n", path);
865 edata->oldpath = mutt_str_dup(path);
866 }
867 }
869done:
870 FREE(&newpath);
871}
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:249
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:562
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:670
struct Email * maildir_email_new(void)
Create a Maildir Email.
Definition: mailbox.c:67
bool maildir_parse_stream(FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition: mailbox.c:157
FILE * maildir_open_find_message(const char *folder, const char *msg, char **newname)
Find a message by name.
Definition: message.c:169
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:497
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:639
static const char * get_message_last_filename(notmuch_message_t *msg)
Get a message's last filename.
Definition: notmuch.c:683
static char * get_folder_from_path(const char *path)
Find an email's folder from its path.
Definition: notmuch.c:596
static void nm_progress_update(struct Mailbox *m)
Update the progress counter.
Definition: notmuch.c:719
static struct Email * get_mutt_email(struct Mailbox *m, notmuch_message_t *msg)
Get the Email of a Notmuch message.
Definition: notmuch.c:736
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:102
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 883 of file notmuch.c.

885{
886 notmuch_messages_t *msgs = NULL;
887
888 for (msgs = notmuch_message_get_replies(top); notmuch_messages_valid(msgs);
889 notmuch_messages_move_to_next(msgs))
890 {
891 notmuch_message_t *nm = notmuch_messages_get(msgs);
892 append_message(hc, m, nm, dedup);
893 /* recurse through all the replies to this message too */
894 append_replies(hc, m, q, nm, dedup);
895 notmuch_message_destroy(nm);
896 }
897}
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:883
static void append_message(struct HeaderCache *hc, struct Mailbox *m, notmuch_message_t *msg, bool dedup)
Associate a message.
Definition: notmuch.c:770
+ 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 910 of file notmuch.c.

912{
913 notmuch_messages_t *msgs = NULL;
914
915 for (msgs = notmuch_thread_get_toplevel_messages(thread);
916 notmuch_messages_valid(msgs); notmuch_messages_move_to_next(msgs))
917 {
918 notmuch_message_t *nm = notmuch_messages_get(msgs);
919 append_message(hc, m, nm, dedup);
920 append_replies(hc, m, q, nm, dedup);
921 notmuch_message_destroy(nm);
922 }
923}
+ 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 934 of file notmuch.c.

935{
936 if (!query)
937 return NULL;
938
939 notmuch_messages_t *msgs = NULL;
940
941#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
942 if (notmuch_query_search_messages(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
943 return NULL;
944#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
945 if (notmuch_query_search_messages_st(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
946 return NULL;
947#else
948 msgs = notmuch_query_search_messages(query);
949#endif
950
951 return msgs;
952}
+ 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 962 of file notmuch.c.

963{
964 struct NmMboxData *mdata = nm_mdata_get(m);
965 if (!mdata)
966 return false;
967
968 int limit = get_limit(mdata);
969
970 notmuch_messages_t *msgs = get_messages(q);
971
972 if (!msgs)
973 return false;
974
975 struct HeaderCache *hc = nm_hcache_open(m);
976
977 for (; notmuch_messages_valid(msgs) && ((limit == 0) || (m->msg_count < limit));
978 notmuch_messages_move_to_next(msgs))
979 {
980 if (SigInt)
981 {
982 nm_hcache_close(&hc);
983 SigInt = false;
984 return false;
985 }
986 notmuch_message_t *nm = notmuch_messages_get(msgs);
987 append_message(hc, m, nm, dedup);
988 notmuch_message_destroy(nm);
989 }
990
991 nm_hcache_close(&hc);
992 return true;
993}
static int get_limit(struct NmMboxData *mdata)
Get the database limit.
Definition: notmuch.c:415
static struct HeaderCache * nm_hcache_open(struct Mailbox *m)
Open a header cache.
Definition: notmuch.c:119
static void nm_hcache_close(struct HeaderCache **ptr)
Close the header cache.
Definition: notmuch.c:133
static notmuch_messages_t * get_messages(notmuch_query_t *query)
Load messages for a query.
Definition: notmuch.c:934
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition: signal.c:69
Header Cache.
Definition: lib.h:86
+ 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 1004 of file notmuch.c.

1005{
1006 if (!query)
1007 return NULL;
1008
1009 notmuch_threads_t *threads = NULL;
1010#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
1011 if (notmuch_query_search_threads(query, &threads) != NOTMUCH_STATUS_SUCCESS)
1012 return NULL;
1013#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
1014 if (notmuch_query_search_threads_st(query, &threads) != NOTMUCH_STATUS_SUCCESS)
1015 return NULL;
1016#else
1017 threads = notmuch_query_search_threads(query);
1018#endif
1019
1020 return threads;
1021}
+ 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 1032 of file notmuch.c.

1033{
1034 struct NmMboxData *mdata = nm_mdata_get(m);
1035 if (!mdata)
1036 return false;
1037
1038 notmuch_threads_t *threads = get_threads(q);
1039 if (!threads)
1040 return false;
1041
1042 struct HeaderCache *hc = nm_hcache_open(m);
1043
1044 for (; notmuch_threads_valid(threads) && ((limit == 0) || (m->msg_count < limit));
1045 notmuch_threads_move_to_next(threads))
1046 {
1047 if (SigInt)
1048 {
1049 nm_hcache_close(&hc);
1050 SigInt = false;
1051 return false;
1052 }
1053 notmuch_thread_t *thread = notmuch_threads_get(threads);
1054 append_thread(hc, m, q, thread, dedup);
1055 notmuch_thread_destroy(thread);
1056 }
1057
1058 nm_hcache_close(&hc);
1059 return true;
1060}
static notmuch_threads_t * get_threads(notmuch_query_t *query)
Load threads for a query.
Definition: notmuch.c:1004
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:910
+ 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 1069 of file notmuch.c.

1070{
1071 notmuch_message_t *msg = NULL;
1072 char *id = email_get_id(e);
1073
1074 mutt_debug(LL_DEBUG2, "nm: find message (%s)\n", id);
1075
1076 if (id && db)
1077 notmuch_database_find_message(db, id, &msg);
1078
1079 return msg;
1080}
static char * email_get_id(struct Email *e)
Get the unique Notmuch Id.
Definition: notmuch.c:222
+ 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 1088 of file notmuch.c.

1089{
1090 const char *possible_match_tag = NULL;
1091 notmuch_tags_t *tags = NULL;
1092
1093 for (tags = notmuch_message_get_tags(msg); notmuch_tags_valid(tags);
1094 notmuch_tags_move_to_next(tags))
1095 {
1096 possible_match_tag = notmuch_tags_get(tags);
1097 if (mutt_str_equal(possible_match_tag, tag))
1098 {
1099 return true;
1100 }
1101 }
1102 return false;
1103}
+ 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 1110 of file notmuch.c.

1111{
1112 const char *new_file = get_message_last_filename(msg);
1113 char old_file[PATH_MAX] = { 0 };
1114 email_get_fullpath(e, old_file, sizeof(old_file));
1115
1116 if (!mutt_str_equal(old_file, new_file))
1117 update_message_path(e, new_file);
1118}
static char * email_get_fullpath(struct Email *e, char *buf, size_t buflen)
Get the full path of an email.
Definition: notmuch.c:238
+ 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 1127 of file notmuch.c.

1128{
1129 if (!tag_str)
1130 return -1;
1131
1132 notmuch_message_freeze(msg);
1133
1135 char **tag_elem = NULL;
1136 ARRAY_FOREACH(tag_elem, &tags.tags)
1137 {
1138 char *tag = *tag_elem;
1139
1140 if (tag[0] == '-')
1141 {
1142 mutt_debug(LL_DEBUG1, "nm: remove tag: '%s'\n", tag + 1);
1143 notmuch_message_remove_tag(msg, tag + 1);
1144 }
1145 else if (tag[0] == '!')
1146 {
1147 mutt_debug(LL_DEBUG1, "nm: toggle tag: '%s'\n", tag + 1);
1148 if (nm_message_has_tag(msg, tag + 1))
1149 {
1150 notmuch_message_remove_tag(msg, tag + 1);
1151 }
1152 else
1153 {
1154 notmuch_message_add_tag(msg, tag + 1);
1155 }
1156 }
1157 else
1158 {
1159 mutt_debug(LL_DEBUG1, "nm: add tag: '%s'\n", (tag[0] == '+') ? tag + 1 : tag);
1160 notmuch_message_add_tag(msg, (tag[0] == '+') ? tag + 1 : tag);
1161 }
1162 }
1163
1164 notmuch_message_thaw(msg);
1166
1167 return 0;
1168}
static bool nm_message_has_tag(notmuch_message_t *msg, char *tag)
Does a message have this tag?
Definition: notmuch.c:1088
char * tag_str
Source string.
Definition: tag.h:40
+ 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 1181 of file notmuch.c.

1182{
1183 if (!tag_str)
1184 return -1;
1185
1186 const char *const c_nm_unread_tag = cs_subset_string(NeoMutt->sub, "nm_unread_tag");
1187 const char *const c_nm_replied_tag = cs_subset_string(NeoMutt->sub, "nm_replied_tag");
1188 const char *const c_nm_flagged_tag = cs_subset_string(NeoMutt->sub, "nm_flagged_tag");
1189
1191 char **tag_elem = NULL;
1192 ARRAY_FOREACH(tag_elem, &tags.tags)
1193 {
1194 char *tag = *tag_elem;
1195
1196 if (tag[0] == '-')
1197 {
1198 tag++;
1199 if (mutt_str_equal(tag, c_nm_unread_tag))
1200 mutt_set_flag(m, e, MUTT_READ, true, true);
1201 else if (mutt_str_equal(tag, c_nm_replied_tag))
1202 mutt_set_flag(m, e, MUTT_REPLIED, false, true);
1203 else if (mutt_str_equal(tag, c_nm_flagged_tag))
1204 mutt_set_flag(m, e, MUTT_FLAG, false, true);
1205 }
1206 else
1207 {
1208 tag = (tag[0] == '+') ? tag + 1 : tag;
1209 if (mutt_str_equal(tag, c_nm_unread_tag))
1210 mutt_set_flag(m, e, MUTT_READ, false, true);
1211 else if (mutt_str_equal(tag, c_nm_replied_tag))
1212 mutt_set_flag(m, e, MUTT_REPLIED, true, true);
1213 else if (mutt_str_equal(tag, c_nm_flagged_tag))
1214 mutt_set_flag(m, e, MUTT_FLAG, true, true);
1215 }
1216 }
1217
1219
1220 return 0;
1221}
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:57
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:73
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:79
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:72
+ 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 1233 of file notmuch.c.

1234{
1235 char filename[PATH_MAX] = { 0 };
1236 char suffix[PATH_MAX] = { 0 };
1237 char folder[PATH_MAX] = { 0 };
1238
1239 mutt_str_copy(folder, old, sizeof(folder));
1240 char *p = strrchr(folder, '/');
1241 if (p)
1242 {
1243 *p = '\0';
1244 p++;
1245 }
1246 else
1247 {
1248 p = folder;
1249 }
1250
1251 mutt_str_copy(filename, p, sizeof(filename));
1252
1253 /* remove (new,cur,...) from folder path */
1254 p = strrchr(folder, '/');
1255 if (p)
1256 *p = '\0';
1257
1258 /* remove old flags from filename */
1259 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
1260 p = strchr(filename, c_maildir_field_delimiter);
1261 if (p)
1262 *p = '\0';
1263
1264 /* compose new flags */
1265 maildir_gen_flags(suffix, sizeof(suffix), e);
1266
1267 snprintf(buf, buflen, "%s/%s/%s%s", folder,
1268 (e->read || e->old) ? "cur" : "new", filename, suffix);
1269
1270 if (mutt_str_equal(old, buf))
1271 return 1;
1272
1273 if (rename(old, buf) != 0)
1274 {
1275 mutt_debug(LL_DEBUG1, "nm: rename(2) failed %s -> %s\n", old, buf);
1276 return -1;
1277 }
1278
1279 return 0;
1280}
const char * cc_maildir_field_delimiter(void)
Get the cached value of $maildir_field_delimiter.
Definition: config_cache.c:131
void maildir_gen_flags(char *dest, size_t destlen, struct Email *e)
Generate the Maildir flags for an email.
Definition: message.c:72
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:582
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 1289 of file notmuch.c.

1290{
1291 struct NmMboxData *mdata = nm_mdata_get(m);
1292 if (!mdata)
1293 return -1;
1294
1295 mutt_debug(LL_DEBUG2, "nm: remove filename '%s'\n", path);
1296
1297 notmuch_database_t *db = nm_db_get(m, true);
1298 if (!db)
1299 return -1;
1300
1301 notmuch_message_t *msg = NULL;
1302 notmuch_status_t st = notmuch_database_find_message_by_filename(db, path, &msg);
1303 if (st || !msg)
1304 return -1;
1305
1306 int trans = nm_db_trans_begin(m);
1307 if (trans < 0)
1308 return -1;
1309
1310 /* note that unlink() is probably unnecessary here, it's already removed
1311 * by mh_sync_mailbox_message(), but for sure... */
1312 notmuch_filenames_t *ls = NULL;
1313 st = notmuch_database_remove_message(db, path);
1314 switch (st)
1315 {
1316 case NOTMUCH_STATUS_SUCCESS:
1317 mutt_debug(LL_DEBUG2, "nm: remove success, call unlink\n");
1318 unlink(path);
1319 break;
1320 case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
1321 mutt_debug(LL_DEBUG2, "nm: remove success (duplicate), call unlink\n");
1322 unlink(path);
1323 for (ls = notmuch_message_get_filenames(msg);
1324 ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
1325 {
1326 path = notmuch_filenames_get(ls);
1327
1328 mutt_debug(LL_DEBUG2, "nm: remove duplicate: '%s'\n", path);
1329 unlink(path);
1330 notmuch_database_remove_message(db, path);
1331 }
1332 break;
1333 default:
1334 mutt_debug(LL_DEBUG1, "nm: failed to remove '%s' [st=%d]\n", path, (int) st);
1335 break;
1336 }
1337
1338 notmuch_message_destroy(msg);
1339 if (trans)
1340 nm_db_trans_end(m);
1341 return 0;
1342}
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 1353 of file notmuch.c.

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

1459{
1460 notmuch_query_t *q = notmuch_query_create(db, qstr);
1461 if (!q)
1462 return 0;
1463
1464 unsigned int res = 0;
1465
1467#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
1468 if (notmuch_query_count_messages(q, &res) != NOTMUCH_STATUS_SUCCESS)
1469 res = 0; /* may not be defined on error */
1470#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
1471 if (notmuch_query_count_messages_st(q, &res) != NOTMUCH_STATUS_SUCCESS)
1472 res = 0; /* may not be defined on error */
1473#else
1474 res = notmuch_query_count_messages(q);
1475#endif
1476 notmuch_query_destroy(q);
1477 mutt_debug(LL_DEBUG1, "nm: count '%s', result=%d\n", qstr, res);
1478
1479 if ((limit > 0) && (res > limit))
1480 res = limit;
1481
1482 return res;
1483}
+ 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 1491 of file notmuch.c.

1492{
1493 struct NmEmailData *edata = nm_edata_get(e);
1494 if (!edata)
1495 return NULL;
1496
1497 return edata->folder;
1498}
+ 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 1510 of file notmuch.c.

1511{
1512 char *full_folder = nm_email_get_folder(e);
1513 if (!full_folder)
1514 return NULL;
1515
1516 const char *db_path = nm_db_get_filename(m);
1517 if (!db_path)
1518 return NULL;
1519
1520 size_t prefix = mutt_str_startswith(full_folder, db_path);
1521
1522 char *path = full_folder + prefix;
1523 if (*path == '/')
1524 path++;
1525
1526 return path;
1527}
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 1536 of file notmuch.c.

1537{
1538 if (!m)
1539 return -1;
1540
1541 struct NmMboxData *mdata = nm_mdata_get(m);
1542 if (!mdata)
1543 return -1;
1544
1545 notmuch_query_t *q = NULL;
1546 notmuch_database_t *db = NULL;
1547 notmuch_message_t *msg = NULL;
1548 int rc = -1;
1549
1550 if (!(db = nm_db_get(m, false)) || !(msg = get_nm_message(db, e)))
1551 goto done;
1552
1553 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages...[current count=%d]\n",
1554 m->msg_count);
1555
1556 progress_setup(m);
1557 const char *id = notmuch_message_get_thread_id(msg);
1558 if (!id)
1559 goto done;
1560
1561 struct Buffer *qstr = buf_pool_get();
1562 buf_printf(qstr, "thread:%s", id);
1563 q = notmuch_query_create(db, buf_string(qstr));
1564 buf_pool_release(&qstr);
1565 if (!q)
1566 goto done;
1568 notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
1569
1570 read_threads_query(m, q, true, 0);
1571 mdata->mtime.tv_sec = mutt_date_now();
1572 mdata->mtime.tv_nsec = 0;
1573 rc = 0;
1574
1575 if (m->msg_count > mdata->oldmsgcount)
1577done:
1578 if (q)
1579 notmuch_query_destroy(q);
1580
1581 nm_db_release(m);
1582
1583 if (m->msg_count == mdata->oldmsgcount)
1584 mutt_message(_("No more messages in the thread"));
1585
1586 mdata->oldmsgcount = 0;
1587 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
1588 rc, m->msg_count);
1589 progress_free(&mdata->progress);
1590 return rc;
1591}
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:233
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:189
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:456
static notmuch_message_t * get_nm_message(notmuch_database_t *db, struct Email *e)
Find a Notmuch message.
Definition: notmuch.c:1069
static bool read_threads_query(struct Mailbox *m, notmuch_query_t *q, bool dedup, int limit)
Perform a query with threads.
Definition: notmuch.c:1032
static void progress_setup(struct Mailbox *m)
Set up the Progress Bar.
Definition: notmuch.c:700
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:110
int oldmsgcount
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 1601 of file notmuch.c.

1602{
1603 mutt_debug(LL_DEBUG2, "(%s)\n", buf);
1604 struct NmMboxData *mdata = nm_mdata_get(m);
1605 char url[PATH_MAX + 1024 + 32]; /* path to DB + query + URL "decoration" */
1606 int added;
1607 bool using_default_data = false;
1608
1609 // No existing data. Try to get a default NmMboxData.
1610 if (!mdata)
1611 {
1613
1614 // Failed to get default data.
1615 if (!mdata)
1616 return NULL;
1617
1618 using_default_data = true;
1619 }
1620
1622 cs_subset_string(NeoMutt->sub, "nm_query_type"));
1623 mdata->query_type = nm_parse_type_from_query(buf, query_type);
1624
1625 const short c_nm_db_limit = cs_subset_number(NeoMutt->sub, "nm_db_limit");
1626 if (get_limit(mdata) == c_nm_db_limit)
1627 {
1628 added = snprintf(url, sizeof(url), "%s%s?type=%s&query=", NmUrlProtocol,
1630 }
1631 else
1632 {
1633 added = snprintf(url, sizeof(url), "%s%s?type=%s&limit=%d&query=", NmUrlProtocol,
1636 }
1637
1638 if (added >= sizeof(url))
1639 {
1640 // snprintf output was truncated, so can't create URL
1641 return NULL;
1642 }
1643
1644 url_pct_encode(&url[added], sizeof(url) - added, buf);
1645
1646 mutt_str_copy(buf, url, buflen);
1647 buf[buflen - 1] = '\0';
1648
1649 if (using_default_data)
1650 nm_mdata_free((void **) &mdata);
1651
1652 mutt_debug(LL_DEBUG1, "nm: url from query '%s'\n", buf);
1653 return buf;
1654}
static struct NmMboxData * nm_get_default_data(void)
Create a Mailbox with default Notmuch settings.
Definition: notmuch.c:177
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:49
const char * nm_query_type_to_string(enum NmQueryType query_type)
Turn a query type into a string.
Definition: query.c:96
NmQueryType
Notmuch Query Types.
Definition: query.h:35
void url_pct_encode(char *buf, size_t buflen, const char *src)
Percent-encode a string.
Definition: url.c: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 1660 of file notmuch.c.

1661{
1662 const short c_nm_query_window_duration = cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
1663 const bool c_nm_query_window_enable = cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
1664
1665 return c_nm_query_window_enable || (c_nm_query_window_duration > 0);
1666}
+ 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 1677 of file notmuch.c.

1678{
1679 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1680 if (c_nm_query_window_current_position != 0)
1681 {
1682 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1683 c_nm_query_window_current_position - 1, NULL);
1684 }
1685
1686 mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position - 1);
1687}
+ 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 1697 of file notmuch.c.

1698{
1699 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1700 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1701 c_nm_query_window_current_position + 1, NULL);
1702 mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position + 1);
1703}
+ 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 1708 of file notmuch.c.

1709{
1710 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position", 0, NULL);
1711 mutt_debug(LL_DEBUG2, "Reset nm_query_window_current_position to 0\n");
1712}
+ 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 1720 of file notmuch.c.

1721{
1722 struct NmMboxData *mdata = nm_mdata_get(m);
1723 if (!mdata)
1724 return false;
1725
1726 notmuch_database_t *db = nm_db_get(m, false);
1727 char *orig_str = get_query_string(mdata, true);
1728
1729 if (!db || !orig_str)
1730 return false;
1731
1732 char *new_str = NULL;
1733 bool rc = false;
1734 if (mutt_str_asprintf(&new_str, "id:%s and (%s)", email_get_id(e), orig_str) < 0)
1735 return false;
1736
1737 mutt_debug(LL_DEBUG2, "nm: checking if message is still queried: %s\n", new_str);
1738
1739 notmuch_query_t *q = notmuch_query_create(db, new_str);
1740
1741 switch (mdata->query_type)
1742 {
1743 case NM_QUERY_TYPE_UNKNOWN: // UNKNOWN should never occur, but MESGS is default
1745 {
1746 notmuch_messages_t *messages = get_messages(q);
1747
1748 if (!messages)
1749 return false;
1750
1751 rc = notmuch_messages_valid(messages);
1752 notmuch_messages_destroy(messages);
1753 break;
1754 }
1756 {
1757 notmuch_threads_t *threads = get_threads(q);
1758
1759 if (!threads)
1760 return false;
1761
1762 rc = notmuch_threads_valid(threads);
1763 notmuch_threads_destroy(threads);
1764 break;
1765 }
1766 }
1767
1768 notmuch_query_destroy(q);
1769
1770 mutt_debug(LL_DEBUG2, "nm: checking if message is still queried: %s = %s\n",
1771 new_str, rc ? "true" : "false");
1772
1773 return rc;
1774}
@ 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 1785 of file notmuch.c.

1787{
1788 char buf[PATH_MAX] = { 0 };
1789 struct NmMboxData *mdata = nm_mdata_get(m);
1790 if (!mdata || !new_file)
1791 return -1;
1792
1793 if (!old_file && nm_edata_get(e))
1794 {
1795 email_get_fullpath(e, buf, sizeof(buf));
1796 old_file = buf;
1797 }
1798
1799 int rc = rename_filename(m, old_file, new_file, e);
1800
1801 nm_db_release(m);
1802 mdata->mtime.tv_sec = mutt_date_now();
1803 mdata->mtime.tv_nsec = 0;
1804 return rc;
1805}
static int rename_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Rename the file.
Definition: notmuch.c:1353
+ 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 1895 of file notmuch.c.

1896{
1897 // Create a new notmuch mailbox from scratch and add plumbing for DB access.
1898 char *default_url = nm_get_default_url();
1899 struct Mailbox *m = mx_path_resolve(default_url);
1900
1901 FREE(&default_url);
1902
1903 // These are no-ops for an initialized mailbox.
1904 init_mailbox(m);
1905 mx_mbox_ac_link(m);
1906
1907 return m;
1908}
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:251
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1641
static int init_mailbox(struct Mailbox *m)
Add Notmuch data to the Mailbox.
Definition: notmuch.c:200
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 1918 of file notmuch.c.

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

2002{
2003 struct NmMboxData *mdata = nm_mdata_get(m);
2004 if (!mdata)
2005 return -1;
2006
2007 notmuch_database_t *db = NULL;
2008 notmuch_tags_t *tags = NULL;
2009 const char *tag = NULL;
2010 int rc = -1;
2011
2012 if (!(db = nm_db_get(m, false)) || !(tags = notmuch_database_get_all_tags(db)))
2013 goto done;
2014
2015 *tag_count = 0;
2016 mutt_debug(LL_DEBUG1, "nm: get all tags\n");
2017
2018 while (notmuch_tags_valid(tags))
2019 {
2020 tag = notmuch_tags_get(tags);
2021 /* Skip empty string */
2022 if (*tag)
2023 {
2024 if (tag_list)
2025 tag_list[*tag_count] = mutt_str_dup(tag);
2026 (*tag_count)++;
2027 }
2028 notmuch_tags_move_to_next(tags);
2029 }
2030
2031 rc = 0;
2032done:
2033 if (tags)
2034 notmuch_tags_destroy(tags);
2035
2036 nm_db_release(m);
2037
2038 mutt_debug(LL_DEBUG1, "nm: get all tags done [rc=%d tag_count=%u]\n", rc, *tag_count);
2039 return rc;
2040}
+ 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 },
{ NULL, NULL, 0 },
}
#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:1465
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:753

Notmuch Commands.

Definition at line 93 of file notmuch.c.

◆ 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.