NeoMutt  2025-01-09-41-g086358
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 108 of file notmuch.c.

109{
111}
void commands_register(const struct Command *cmds, const size_t num_cmds)
Add commands to Commands array.
Definition: command.c:53
#define mutt_array_size(x)
Definition: memory.h:38
static const struct Command NmCommands[]
Notmuch Commands.
Definition: notmuch.c:93
+ 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 118 of file notmuch.c.

119{
120#ifdef USE_HCACHE
121 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
122 return hcache_open(c_header_cache, mailbox_path(m), NULL, true);
123#else
124 return NULL;
125#endif
126}
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
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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 132 of file notmuch.c.

133{
134#ifdef USE_HCACHE
135 hcache_close(ptr);
136#endif
137}
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 144 of file notmuch.c.

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

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

200{
201 if (!m || (m->type != MUTT_NOTMUCH))
202 return -1;
203
204 if (m->mdata)
205 return 0;
206
208 if (!m->mdata)
209 return -1;
210
212 return 0;
213}
@ 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 221 of file notmuch.c.

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

238{
239 snprintf(buf, buflen, "%s/%s", nm_email_get_folder(e), e->path);
240 return buf;
241}
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1488
char * path
Path of Email (for local Mailboxes)
Definition: email.h:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_window_reset()

static void query_window_reset ( void  )
static

Restore vfolder's search window to its original position.

After moving a vfolder search window backward and forward, calling this function will reset the search position to its original value, setting to 0 the user settable variable:

nm_query_window_current_position

Definition at line 252 of file notmuch.c.

253{
254 mutt_debug(LL_DEBUG2, "entering\n");
255 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position", 0, NULL);
256}
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:297
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ windowed_query_from_query()

static bool windowed_query_from_query ( const char *  query,
char *  buf,
size_t  buflen 
)
static

Transforms a vfolder search query into a windowed one.

Parameters
[in]queryvfolder search string
[out]bufallocated string buffer to receive the modified search query
[in]buflenallocated maximum size of the buf string buffer
Return values
trueTransformed search query is available as a string in buf
falseSearch query shall not be transformed

Creates a date: search term window from the following user settings:

  • nm_query_window_enable (only required for nm_query_window_duration = 0)
  • nm_query_window_duration
  • nm_query_window_timebase
  • nm_query_window_current_position

The window won't be applied:

  • If the duration of the search query is set to 0 this function will be disabled unless a user explicitly enables windowed queries.
  • If the timebase is invalid, it will show an error message and do nothing.

If there's no search registered in nm_query_window_current_search or this is a new search, it will reset the window and do the search.

Definition at line 282 of file notmuch.c.

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

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

◆ get_limit()

static int get_limit ( struct NmMboxData mdata)
static

Get the database limit.

Parameters
mdataNotmuch Mailbox data
Return values
numCurrent limit

Definition at line 414 of file notmuch.c.

415{
416 return mdata ? mdata->db_limit : 0;
417}
+ Here is the caller graph for this function:

◆ apply_exclude_tags()

static void apply_exclude_tags ( notmuch_query_t *  query)
static

Exclude the configured tags.

Parameters
queryNotmuch query

Definition at line 423 of file notmuch.c.

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

450{
451 struct NmMboxData *mdata = nm_mdata_get(m);
452 if (!mdata)
453 return NULL;
454
455 notmuch_database_t *db = nm_db_get(m, writable);
456 const char *str = get_query_string(mdata, true);
457
458 if (!db || !str)
459 goto err;
460
461 notmuch_query_t *q = notmuch_query_create(db, str);
462 if (!q)
463 goto err;
464
466 notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
467 mutt_debug(LL_DEBUG2, "nm: query successfully initialized (%s)\n", str);
468 return q;
469err:
470 nm_db_release(m);
471 return NULL;
472}
notmuch_database_t * nm_db_get(struct Mailbox *m, bool writable)
Get the Notmuch database.
Definition: db.c:209
int nm_db_release(struct Mailbox *m)
Close the Notmuch database.
Definition: db.c:233
struct NmMboxData * nm_mdata_get(struct Mailbox *m)
Get the Notmuch Mailbox data.
Definition: mdata.c:96
static char * get_query_string(struct NmMboxData *mdata, bool window)
Builds the notmuch vfolder search string.
Definition: notmuch.c:346
static void apply_exclude_tags(notmuch_query_t *query)
Exclude the configured tags.
Definition: notmuch.c:423
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_email_tags()

static int update_email_tags ( struct Email e,
notmuch_message_t *  msg 
)
static

Update the Email's tags from Notmuch.

Parameters
eEmail
msgNotmuch message
Return values
0Success
1Tags unchanged

Definition at line 481 of file notmuch.c.

482{
483 struct NmEmailData *edata = nm_edata_get(e);
484 struct Buffer *new_tags = buf_pool_get();
485 struct Buffer *old_tags = buf_pool_get();
486
487 mutt_debug(LL_DEBUG2, "nm: tags update requested (%s)\n", edata->virtual_id);
488
489 for (notmuch_tags_t *tags = notmuch_message_get_tags(msg);
490 tags && notmuch_tags_valid(tags); notmuch_tags_move_to_next(tags))
491 {
492 const char *t = notmuch_tags_get(tags);
493 if (!t || (*t == '\0'))
494 continue;
495
496 buf_join_str(new_tags, t, ' ');
497 }
498
499 driver_tags_get(&e->tags, old_tags);
500
501 if (!buf_is_empty(new_tags) && !buf_is_empty(old_tags) &&
502 (buf_str_equal(old_tags, new_tags)))
503 {
504 buf_pool_release(&new_tags);
505 buf_pool_release(&old_tags);
506 mutt_debug(LL_DEBUG2, "nm: tags unchanged\n");
507 return 1;
508 }
509 buf_pool_release(&old_tags);
510
511 /* new version */
512 driver_tags_replace(&e->tags, buf_string(new_tags));
513 buf_reset(new_tags);
514
515 driver_tags_get_transformed(&e->tags, new_tags);
516 mutt_debug(LL_DEBUG2, "nm: new tags transformed: '%s'\n", buf_string(new_tags));
517 buf_reset(new_tags);
518
519 driver_tags_get(&e->tags, new_tags);
520 mutt_debug(LL_DEBUG2, "nm: new tag: '%s'\n", buf_string(new_tags));
521 buf_pool_release(&new_tags);
522
523 return 0;
524}
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:750
bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal.
Definition: buffer.c:685
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 533 of file notmuch.c.

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

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

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

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

◆ get_message_last_filename()

static 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 680 of file notmuch.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Variable Documentation

◆ NmCommands

const struct Command NmCommands[]
static
Initial value:
= {
{ "unvirtual-mailboxes", parse_unmailboxes, 0 },
{ "virtual-mailboxes", parse_mailboxes, MUTT_NAMED },
}
#define MUTT_NAMED
Definition: commands.h:36
enum CommandResult parse_unmailboxes(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'unmailboxes' command - Implements Command::parse() -.
Definition: commands.c:1462
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 101 of file notmuch.c.

◆ NmUrlProtocolLen

const int NmUrlProtocolLen = sizeof(NmUrlProtocol) - 1

Length of NmUrlProtocol string.

Definition at line 103 of file notmuch.c.