NeoMutt  2025-01-09-117-gace867
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
notmuch.c File Reference

Notmuch virtual mailbox type. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <notmuch.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "lib.h"
#include "editor/lib.h"
#include "hcache/lib.h"
#include "history/lib.h"
#include "index/lib.h"
#include "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:1489
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);
575 ASSERT(e->body);
576 ASSERT(e->env);
577
578 FREE(&e->env->message_id);
579 e->env->message_id = message_id;
580 message_id = NULL;
581
582 return 0;
583 }
584
585 return 1;
586}
@ 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 594 of file notmuch.c.

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

620{
621 if (!id)
622 return NULL;
623
624 char *mid = NULL;
625 mutt_str_asprintf(&mid, "<%s>", id);
626 return mid;
627}
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 637 of file notmuch.c.

638{
639 if (nm_edata_get(e))
640 return 0;
641
642 struct NmEmailData *edata = nm_edata_new();
643 e->nm_edata = edata;
644
645 /* Notmuch ensures that message Id exists (if not notmuch Notmuch will
646 * generate an ID), so it's more safe than use neomutt Email->env->id */
647 const char *id = notmuch_message_get_message_id(msg);
648 edata->virtual_id = mutt_str_dup(id);
649
650 mutt_debug(LL_DEBUG2, "nm: [e=%p, edata=%p] (%s)\n", (void *) e, (void *) edata, id);
651
652 char *nm_msg_id = nm2mutt_message_id(id);
653 if (!e->env->message_id)
654 {
655 e->env->message_id = nm_msg_id;
656 }
657 else if (!mutt_str_equal(e->env->message_id, nm_msg_id))
658 {
659 FREE(&e->env->message_id);
660 e->env->message_id = nm_msg_id;
661 }
662 else
663 {
664 FREE(&nm_msg_id);
665 }
666
667 if (update_message_path(e, path) != 0)
668 return -1;
669
670 update_email_tags(e, msg);
671
672 return 0;
673}
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:619
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 681 of file notmuch.c.

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

699{
700 if (!m->verbose)
701 return;
702
703 struct NmMboxData *mdata = nm_mdata_get(m);
704 if (!mdata)
705 return;
706
707 mdata->oldmsgcount = m->msg_count;
708 mdata->ignmsgcount = 0;
709 mdata->progress = progress_new(MUTT_PROGRESS_READ, mdata->oldmsgcount);
710 progress_set_message(mdata->progress, _("Reading messages..."));
711}
@ 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 717 of file notmuch.c.

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

735{
736 if (!m || !msg)
737 return NULL;
738
739 const char *id = notmuch_message_get_message_id(msg);
740 if (!id)
741 return NULL;
742
743 mutt_debug(LL_DEBUG2, "nm: neomutt email, id='%s'\n", id);
744
745 if (!m->id_hash)
746 {
747 mutt_debug(LL_DEBUG2, "nm: init hash\n");
749 if (!m->id_hash)
750 return NULL;
751 }
752
753 char *mid = nm2mutt_message_id(id);
754 mutt_debug(LL_DEBUG2, "nm: neomutt id='%s'\n", mid);
755
756 struct Email *e = mutt_hash_find(m->id_hash, mid);
757 FREE(&mid);
758 return e;
759}
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 768 of file notmuch.c.

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

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

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

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

961{
962 struct NmMboxData *mdata = nm_mdata_get(m);
963 if (!mdata)
964 return false;
965
966 int limit = get_limit(mdata);
967
968 notmuch_messages_t *msgs = get_messages(q);
969
970 if (!msgs)
971 return false;
972
973 struct HeaderCache *hc = nm_hcache_open(m);
974
975 for (; notmuch_messages_valid(msgs) && ((limit == 0) || (m->msg_count < limit));
976 notmuch_messages_move_to_next(msgs))
977 {
978 if (SigInt)
979 {
980 nm_hcache_close(&hc);
981 SigInt = false;
982 return false;
983 }
984 notmuch_message_t *nm = notmuch_messages_get(msgs);
985 append_message(hc, m, nm, dedup);
986 notmuch_message_destroy(nm);
987 }
988
989 nm_hcache_close(&hc);
990 return true;
991}
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:932
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 1002 of file notmuch.c.

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

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

1068{
1069 notmuch_message_t *msg = NULL;
1070 char *id = email_get_id(e);
1071
1072 mutt_debug(LL_DEBUG2, "nm: find message (%s)\n", id);
1073
1074 if (id && db)
1075 notmuch_database_find_message(db, id, &msg);
1076
1077 return msg;
1078}
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 1086 of file notmuch.c.

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

1109{
1110 const char *new_file = get_message_last_filename(msg);
1111 char old_file[PATH_MAX] = { 0 };
1112 email_get_fullpath(e, old_file, sizeof(old_file));
1113
1114 if (!mutt_str_equal(old_file, new_file))
1115 update_message_path(e, new_file);
1116}
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 1125 of file notmuch.c.

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

1180{
1181 if (!tag_str)
1182 return -1;
1183
1184 const char *const c_nm_unread_tag = cs_subset_string(NeoMutt->sub, "nm_unread_tag");
1185 const char *const c_nm_replied_tag = cs_subset_string(NeoMutt->sub, "nm_replied_tag");
1186 const char *const c_nm_flagged_tag = cs_subset_string(NeoMutt->sub, "nm_flagged_tag");
1187
1189 char **tag_elem = NULL;
1190 ARRAY_FOREACH(tag_elem, &tags.tags)
1191 {
1192 char *tag = *tag_elem;
1193
1194 if (tag[0] == '-')
1195 {
1196 tag++;
1197 if (mutt_str_equal(tag, c_nm_unread_tag))
1198 mutt_set_flag(m, e, MUTT_READ, true, true);
1199 else if (mutt_str_equal(tag, c_nm_replied_tag))
1200 mutt_set_flag(m, e, MUTT_REPLIED, false, true);
1201 else if (mutt_str_equal(tag, c_nm_flagged_tag))
1202 mutt_set_flag(m, e, MUTT_FLAG, false, true);
1203 }
1204 else
1205 {
1206 tag = (tag[0] == '+') ? tag + 1 : tag;
1207 if (mutt_str_equal(tag, c_nm_unread_tag))
1208 mutt_set_flag(m, e, MUTT_READ, false, true);
1209 else if (mutt_str_equal(tag, c_nm_replied_tag))
1210 mutt_set_flag(m, e, MUTT_REPLIED, true, true);
1211 else if (mutt_str_equal(tag, c_nm_flagged_tag))
1212 mutt_set_flag(m, e, MUTT_FLAG, true, true);
1213 }
1214 }
1215
1217
1218 return 0;
1219}
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 1231 of file notmuch.c.

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

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

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

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

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

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

1535{
1536 if (!m)
1537 return -1;
1538
1539 struct NmMboxData *mdata = nm_mdata_get(m);
1540 if (!mdata)
1541 return -1;
1542
1543 notmuch_query_t *q = NULL;
1544 notmuch_database_t *db = NULL;
1545 notmuch_message_t *msg = NULL;
1546 int rc = -1;
1547
1548 if (!(db = nm_db_get(m, false)) || !(msg = get_nm_message(db, e)))
1549 goto done;
1550
1551 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages...[current count=%d]\n",
1552 m->msg_count);
1553
1554 progress_setup(m);
1555 const char *id = notmuch_message_get_thread_id(msg);
1556 if (!id)
1557 goto done;
1558
1559 struct Buffer *qstr = buf_pool_get();
1560 buf_printf(qstr, "thread:%s", id);
1561 q = notmuch_query_create(db, buf_string(qstr));
1562 buf_pool_release(&qstr);
1563 if (!q)
1564 goto done;
1566 notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
1567
1568 read_threads_query(m, q, true, 0);
1569 mdata->mtime.tv_sec = mutt_date_now();
1570 mdata->mtime.tv_nsec = 0;
1571 rc = 0;
1572
1573 if (m->msg_count > mdata->oldmsgcount)
1575done:
1576 if (q)
1577 notmuch_query_destroy(q);
1578
1579 nm_db_release(m);
1580
1581 if (m->msg_count == mdata->oldmsgcount)
1582 mutt_message(_("No more messages in the thread"));
1583
1584 mdata->oldmsgcount = 0;
1585 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
1586 rc, m->msg_count);
1587 progress_free(&mdata->progress);
1588 return rc;
1589}
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:1067
static bool read_threads_query(struct Mailbox *m, notmuch_query_t *q, bool dedup, int limit)
Perform a query with threads.
Definition: notmuch.c:1030
static void progress_setup(struct Mailbox *m)
Set up the Progress Bar.
Definition: notmuch.c:698
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 1599 of file notmuch.c.

1600{
1601 mutt_debug(LL_DEBUG2, "(%s)\n", buf);
1602 struct NmMboxData *mdata = nm_mdata_get(m);
1603 char url[PATH_MAX + 1024 + 32]; /* path to DB + query + URL "decoration" */
1604 int added;
1605 bool using_default_data = false;
1606
1607 // No existing data. Try to get a default NmMboxData.
1608 if (!mdata)
1609 {
1611
1612 // Failed to get default data.
1613 if (!mdata)
1614 return NULL;
1615
1616 using_default_data = true;
1617 }
1618
1620 cs_subset_string(NeoMutt->sub, "nm_query_type"));
1621 mdata->query_type = nm_parse_type_from_query(buf, query_type);
1622
1623 const short c_nm_db_limit = cs_subset_number(NeoMutt->sub, "nm_db_limit");
1624 if (get_limit(mdata) == c_nm_db_limit)
1625 {
1626 added = snprintf(url, sizeof(url), "%s%s?type=%s&query=", NmUrlProtocol,
1628 }
1629 else
1630 {
1631 added = snprintf(url, sizeof(url), "%s%s?type=%s&limit=%d&query=", NmUrlProtocol,
1634 }
1635
1636 if (added >= sizeof(url))
1637 {
1638 // snprintf output was truncated, so can't create URL
1639 return NULL;
1640 }
1641
1642 url_pct_encode(&url[added], sizeof(url) - added, buf);
1643
1644 mutt_str_copy(buf, url, buflen);
1645 buf[buflen - 1] = '\0';
1646
1647 if (using_default_data)
1648 nm_mdata_free((void **) &mdata);
1649
1650 mutt_debug(LL_DEBUG1, "nm: url from query '%s'\n", buf);
1651 return buf;
1652}
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 1658 of file notmuch.c.

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

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

1696{
1697 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1698 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1699 c_nm_query_window_current_position + 1, NULL);
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_reset()

void nm_query_window_reset ( void  )

Resets the vfolder window position to the present.

Definition at line 1706 of file notmuch.c.

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

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

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

1894{
1895 // Create a new notmuch mailbox from scratch and add plumbing for DB access.
1896 char *default_url = nm_get_default_url();
1897 struct Mailbox *m = mx_path_resolve(default_url);
1898
1899 FREE(&default_url);
1900
1901 // These are no-ops for an initialized mailbox.
1902 init_mailbox(m);
1903 mx_mbox_ac_link(m);
1904
1905 return m;
1906}
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 1916 of file notmuch.c.

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

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