NeoMutt  2024-10-02-37-gfa9146
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);
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
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:91
#define FREE(x)
Definition: memory.h:45
#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:1469
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:352
struct Url * db_url
Parsed view url of the Notmuch database.
Definition: mdata.h:36
enum NmQueryType query_type
Messages or Threads.
Definition: mdata.h:39
int db_limit
Maximum number of results to return.
Definition: mdata.h:38
char * db_query
Previous query.
Definition: mdata.h:37
Parsed Query String.
Definition: url.h:58
char * name
Query name.
Definition: url.h:59
char * value
Query value.
Definition: url.h:60
struct UrlQueryList query_strings
List of query strings.
Definition: url.h:76
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c: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:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
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 return 0;
563 }
564
565 return 1;
566}
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c: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
bool old
Email is seen, but unread.
Definition: email.h:49
+ 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 574 of file notmuch.c.

575{
576 char *p = strrchr(path, '/');
577
578 if (p && ((p - path) > 3) &&
579 (mutt_strn_equal(p - 3, "cur", 3) || mutt_strn_equal(p - 3, "new", 3) ||
580 mutt_strn_equal(p - 3, "tmp", 3)))
581 {
582 p -= 3;
583 for (; (p > path) && (*(p - 1) == '/'); p--)
584 ; // do nothing
585
586 return mutt_strn_dup(path, p - path);
587 }
588
589 return NULL;
590}
+ 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 599 of file notmuch.c.

600{
601 if (!id)
602 return NULL;
603
604 char *mid = NULL;
605 mutt_str_asprintf(&mid, "<%s>", id);
606 return mid;
607}
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 617 of file notmuch.c.

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

662{
663 const char *name = NULL;
664
665 for (notmuch_filenames_t *ls = notmuch_message_get_filenames(msg);
666 ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
667 {
668 name = notmuch_filenames_get(ls);
669 }
670
671 return name;
672}
+ 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 678 of file notmuch.c.

679{
680 if (!m->verbose)
681 return;
682
683 struct NmMboxData *mdata = nm_mdata_get(m);
684 if (!mdata)
685 return;
686
687 mdata->oldmsgcount = m->msg_count;
688 mdata->ignmsgcount = 0;
689 mdata->progress = progress_new(MUTT_PROGRESS_READ, mdata->oldmsgcount);
690 progress_set_message(mdata->progress, _("Reading messages..."));
691}
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:82
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c: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 697 of file notmuch.c.

698{
699 struct NmMboxData *mdata = nm_mdata_get(m);
700
701 if (!m->verbose || !mdata || !mdata->progress)
702 return;
703
704 progress_update(mdata->progress, m->msg_count + mdata->ignmsgcount, -1);
705}
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 714 of file notmuch.c.

715{
716 if (!m || !msg)
717 return NULL;
718
719 const char *id = notmuch_message_get_message_id(msg);
720 if (!id)
721 return NULL;
722
723 mutt_debug(LL_DEBUG2, "nm: neomutt email, id='%s'\n", id);
724
725 if (!m->id_hash)
726 {
727 mutt_debug(LL_DEBUG2, "nm: init hash\n");
729 if (!m->id_hash)
730 return NULL;
731 }
732
733 char *mid = nm2mutt_message_id(id);
734 mutt_debug(LL_DEBUG2, "nm: neomutt id='%s'\n", mid);
735
736 struct Email *e = mutt_hash_find(m->id_hash, mid);
737 FREE(&mid);
738 return e;
739}
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 748 of file notmuch.c.

750{
751 struct NmMboxData *mdata = nm_mdata_get(m);
752 if (!mdata)
753 return;
754
755 char *newpath = NULL;
756 struct Email *e = NULL;
757
758 /* deduplicate */
759 if (dedup && get_mutt_email(m, msg))
760 {
761 mdata->ignmsgcount++;
763 mutt_debug(LL_DEBUG2, "nm: ignore id=%s, already in the m\n",
764 notmuch_message_get_message_id(msg));
765 return;
766 }
767
768 const char *path = get_message_last_filename(msg);
769 if (!path)
770 return;
771
772 mutt_debug(LL_DEBUG2, "nm: appending message, i=%d, id=%s, path=%s\n",
773 m->msg_count, notmuch_message_get_message_id(msg), path);
774
776
777#ifdef USE_HCACHE
779 if (!e)
780#endif
781 {
782 if (access(path, F_OK) == 0)
783 {
784 /* We pass is_old=false as argument here, but e->old will be updated later
785 * by update_message_path() (called by init_email() below). */
786 e = maildir_email_new();
787 if (!maildir_parse_message(path, false, e))
788 email_free(&e);
789 }
790 else
791 {
792 /* maybe moved try find it... */
793 char *folder = get_folder_from_path(path);
794
795 if (folder)
796 {
797 FILE *fp = maildir_open_find_message(folder, path, &newpath);
798 if (fp)
799 {
800 e = maildir_email_new();
801 if (!maildir_parse_stream(fp, newpath, false, e))
802 email_free(&e);
803 mutt_file_fclose(&fp);
804
805 mutt_debug(LL_DEBUG1, "nm: not up-to-date: %s -> %s\n", path, newpath);
806 }
807 }
808 FREE(&folder);
809 }
810
811 if (!e)
812 {
813 mutt_debug(LL_DEBUG1, "nm: failed to parse message: %s\n", path);
814 goto done;
815 }
816
817#ifdef USE_HCACHE
818 hcache_store_email(hc, newpath ? newpath : path,
819 mutt_str_len(newpath ? newpath : path), e, 0);
820#endif
821 }
822
823 if (init_email(e, newpath ? newpath : path, msg) != 0)
824 {
825 email_free(&e);
826 mutt_debug(LL_DEBUG1, "nm: failed to append email!\n");
827 goto done;
828 }
829
830 e->active = true;
831 e->index = m->msg_count;
832 mailbox_size_add(m, e);
833 m->emails[m->msg_count] = e;
834 m->msg_count++;
835
836 if (newpath)
837 {
838 /* remember that file has been moved -- nm_mbox_sync() will update the DB */
839 struct NmEmailData *edata = nm_edata_get(e);
840 if (edata)
841 {
842 mutt_debug(LL_DEBUG1, "nm: remember obsolete path: %s\n", path);
843 edata->oldpath = mutt_str_dup(path);
844 }
845 }
847done:
848 FREE(&newpath);
849}
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:138
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
@ 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:190
struct Email * maildir_email_new(void)
Create a Maildir Email.
Definition: mailbox.c:68
bool maildir_parse_stream(FILE *fp, const char *fname, bool is_old, struct Email *e)
Parse a Maildir message.
Definition: mailbox.c:153
FILE * maildir_open_find_message(const char *folder, const char *msg, char **newname)
Find a message by name.
Definition: message.c:170
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:1206
static int init_email(struct Email *e, const char *path, notmuch_message_t *msg)
Set up an email's Notmuch data.
Definition: notmuch.c:617
static const char * get_message_last_filename(notmuch_message_t *msg)
Get a message's last filename.
Definition: notmuch.c:661
static char * get_folder_from_path(const char *path)
Find an email's folder from its path.
Definition: notmuch.c:574
static void nm_progress_update(struct Mailbox *m)
Update the progress counter.
Definition: notmuch.c:697
static struct Email * get_mutt_email(struct Mailbox *m, notmuch_message_t *msg)
Get the Email of a Notmuch message.
Definition: notmuch.c:714
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 861 of file notmuch.c.

863{
864 notmuch_messages_t *msgs = NULL;
865
866 for (msgs = notmuch_message_get_replies(top); notmuch_messages_valid(msgs);
867 notmuch_messages_move_to_next(msgs))
868 {
869 notmuch_message_t *nm = notmuch_messages_get(msgs);
870 append_message(hc, m, nm, dedup);
871 /* recurse through all the replies to this message too */
872 append_replies(hc, m, q, nm, dedup);
873 notmuch_message_destroy(nm);
874 }
875}
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:861
static void append_message(struct HeaderCache *hc, struct Mailbox *m, notmuch_message_t *msg, bool dedup)
Associate a message.
Definition: notmuch.c:748
+ 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 888 of file notmuch.c.

890{
891 notmuch_messages_t *msgs = NULL;
892
893 for (msgs = notmuch_thread_get_toplevel_messages(thread);
894 notmuch_messages_valid(msgs); notmuch_messages_move_to_next(msgs))
895 {
896 notmuch_message_t *nm = notmuch_messages_get(msgs);
897 append_message(hc, m, nm, dedup);
898 append_replies(hc, m, q, nm, dedup);
899 notmuch_message_destroy(nm);
900 }
901}
+ 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 912 of file notmuch.c.

913{
914 if (!query)
915 return NULL;
916
917 notmuch_messages_t *msgs = NULL;
918
919#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
920 if (notmuch_query_search_messages(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
921 return NULL;
922#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
923 if (notmuch_query_search_messages_st(query, &msgs) != NOTMUCH_STATUS_SUCCESS)
924 return NULL;
925#else
926 msgs = notmuch_query_search_messages(query);
927#endif
928
929 return msgs;
930}
+ 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 940 of file notmuch.c.

941{
942 struct NmMboxData *mdata = nm_mdata_get(m);
943 if (!mdata)
944 return false;
945
946 int limit = get_limit(mdata);
947
948 notmuch_messages_t *msgs = get_messages(q);
949
950 if (!msgs)
951 return false;
952
953 struct HeaderCache *hc = nm_hcache_open(m);
954
955 for (; notmuch_messages_valid(msgs) && ((limit == 0) || (m->msg_count < limit));
956 notmuch_messages_move_to_next(msgs))
957 {
958 if (SigInt)
959 {
960 nm_hcache_close(&hc);
961 SigInt = false;
962 return false;
963 }
964 notmuch_message_t *nm = notmuch_messages_get(msgs);
965 append_message(hc, m, nm, dedup);
966 notmuch_message_destroy(nm);
967 }
968
969 nm_hcache_close(&hc);
970 return true;
971}
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:912
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 982 of file notmuch.c.

983{
984 if (!query)
985 return NULL;
986
987 notmuch_threads_t *threads = NULL;
988#if LIBNOTMUCH_CHECK_VERSION(5, 0, 0)
989 if (notmuch_query_search_threads(query, &threads) != NOTMUCH_STATUS_SUCCESS)
990 return NULL;
991#elif LIBNOTMUCH_CHECK_VERSION(4, 3, 0)
992 if (notmuch_query_search_threads_st(query, &threads) != NOTMUCH_STATUS_SUCCESS)
993 return NULL;
994#else
995 threads = notmuch_query_search_threads(query);
996#endif
997
998 return threads;
999}
+ 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 1010 of file notmuch.c.

1011{
1012 struct NmMboxData *mdata = nm_mdata_get(m);
1013 if (!mdata)
1014 return false;
1015
1016 notmuch_threads_t *threads = get_threads(q);
1017 if (!threads)
1018 return false;
1019
1020 struct HeaderCache *hc = nm_hcache_open(m);
1021
1022 for (; notmuch_threads_valid(threads) && ((limit == 0) || (m->msg_count < limit));
1023 notmuch_threads_move_to_next(threads))
1024 {
1025 if (SigInt)
1026 {
1027 nm_hcache_close(&hc);
1028 SigInt = false;
1029 return false;
1030 }
1031 notmuch_thread_t *thread = notmuch_threads_get(threads);
1032 append_thread(hc, m, q, thread, dedup);
1033 notmuch_thread_destroy(thread);
1034 }
1035
1036 nm_hcache_close(&hc);
1037 return true;
1038}
static notmuch_threads_t * get_threads(notmuch_query_t *query)
Load threads for a query.
Definition: notmuch.c:982
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:888
+ 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 1047 of file notmuch.c.

1048{
1049 notmuch_message_t *msg = NULL;
1050 char *id = email_get_id(e);
1051
1052 mutt_debug(LL_DEBUG2, "nm: find message (%s)\n", id);
1053
1054 if (id && db)
1055 notmuch_database_find_message(db, id, &msg);
1056
1057 return msg;
1058}
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 1066 of file notmuch.c.

1067{
1068 const char *possible_match_tag = NULL;
1069 notmuch_tags_t *tags = NULL;
1070
1071 for (tags = notmuch_message_get_tags(msg); notmuch_tags_valid(tags);
1072 notmuch_tags_move_to_next(tags))
1073 {
1074 possible_match_tag = notmuch_tags_get(tags);
1075 if (mutt_str_equal(possible_match_tag, tag))
1076 {
1077 return true;
1078 }
1079 }
1080 return false;
1081}
+ 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 1088 of file notmuch.c.

1089{
1090 const char *new_file = get_message_last_filename(msg);
1091 char old_file[PATH_MAX] = { 0 };
1092 email_get_fullpath(e, old_file, sizeof(old_file));
1093
1094 if (!mutt_str_equal(old_file, new_file))
1095 update_message_path(e, new_file);
1096}
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 1105 of file notmuch.c.

1106{
1107 if (!tag_str)
1108 return -1;
1109
1110 notmuch_message_freeze(msg);
1111
1113 char **tag_elem = NULL;
1114 ARRAY_FOREACH(tag_elem, &tags.tags)
1115 {
1116 char *tag = *tag_elem;
1117
1118 if (tag[0] == '-')
1119 {
1120 mutt_debug(LL_DEBUG1, "nm: remove tag: '%s'\n", tag + 1);
1121 notmuch_message_remove_tag(msg, tag + 1);
1122 }
1123 else if (tag[0] == '!')
1124 {
1125 mutt_debug(LL_DEBUG1, "nm: toggle tag: '%s'\n", tag + 1);
1126 if (nm_message_has_tag(msg, tag + 1))
1127 {
1128 notmuch_message_remove_tag(msg, tag + 1);
1129 }
1130 else
1131 {
1132 notmuch_message_add_tag(msg, tag + 1);
1133 }
1134 }
1135 else
1136 {
1137 mutt_debug(LL_DEBUG1, "nm: add tag: '%s'\n", (tag[0] == '+') ? tag + 1 : tag);
1138 notmuch_message_add_tag(msg, (tag[0] == '+') ? tag + 1 : tag);
1139 }
1140 }
1141
1142 notmuch_message_thaw(msg);
1144
1145 return 0;
1146}
static bool nm_message_has_tag(notmuch_message_t *msg, char *tag)
Does a message have this tag?
Definition: notmuch.c:1066
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 1159 of file notmuch.c.

1160{
1161 if (!tag_str)
1162 return -1;
1163
1164 const char *const c_nm_unread_tag = cs_subset_string(NeoMutt->sub, "nm_unread_tag");
1165 const char *const c_nm_replied_tag = cs_subset_string(NeoMutt->sub, "nm_replied_tag");
1166 const char *const c_nm_flagged_tag = cs_subset_string(NeoMutt->sub, "nm_flagged_tag");
1167
1169 char **tag_elem = NULL;
1170 ARRAY_FOREACH(tag_elem, &tags.tags)
1171 {
1172 char *tag = *tag_elem;
1173
1174 if (tag[0] == '-')
1175 {
1176 tag++;
1177 if (mutt_str_equal(tag, c_nm_unread_tag))
1178 mutt_set_flag(m, e, MUTT_READ, true, true);
1179 else if (mutt_str_equal(tag, c_nm_replied_tag))
1180 mutt_set_flag(m, e, MUTT_REPLIED, false, true);
1181 else if (mutt_str_equal(tag, c_nm_flagged_tag))
1182 mutt_set_flag(m, e, MUTT_FLAG, false, true);
1183 }
1184 else
1185 {
1186 tag = (tag[0] == '+') ? tag + 1 : tag;
1187 if (mutt_str_equal(tag, c_nm_unread_tag))
1188 mutt_set_flag(m, e, MUTT_READ, false, true);
1189 else if (mutt_str_equal(tag, c_nm_replied_tag))
1190 mutt_set_flag(m, e, MUTT_REPLIED, true, true);
1191 else if (mutt_str_equal(tag, c_nm_flagged_tag))
1192 mutt_set_flag(m, e, MUTT_FLAG, true, true);
1193 }
1194 }
1195
1197
1198 return 0;
1199}
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 1211 of file notmuch.c.

1212{
1213 char filename[PATH_MAX] = { 0 };
1214 char suffix[PATH_MAX] = { 0 };
1215 char folder[PATH_MAX] = { 0 };
1216
1217 mutt_str_copy(folder, old, sizeof(folder));
1218 char *p = strrchr(folder, '/');
1219 if (p)
1220 {
1221 *p = '\0';
1222 p++;
1223 }
1224 else
1225 {
1226 p = folder;
1227 }
1228
1229 mutt_str_copy(filename, p, sizeof(filename));
1230
1231 /* remove (new,cur,...) from folder path */
1232 p = strrchr(folder, '/');
1233 if (p)
1234 *p = '\0';
1235
1236 /* remove old flags from filename */
1237 const char c_maildir_field_delimiter = *cc_maildir_field_delimiter();
1238 p = strchr(filename, c_maildir_field_delimiter);
1239 if (p)
1240 *p = '\0';
1241
1242 /* compose new flags */
1243 maildir_gen_flags(suffix, sizeof(suffix), e);
1244
1245 snprintf(buf, buflen, "%s/%s/%s%s", folder,
1246 (e->read || e->old) ? "cur" : "new", filename, suffix);
1247
1248 if (mutt_str_equal(old, buf))
1249 return 1;
1250
1251 if (rename(old, buf) != 0)
1252 {
1253 mutt_debug(LL_DEBUG1, "nm: rename(2) failed %s -> %s\n", old, buf);
1254 return -1;
1255 }
1256
1257 return 0;
1258}
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:73
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 1267 of file notmuch.c.

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

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

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

1470{
1471 struct NmEmailData *edata = nm_edata_get(e);
1472 if (!edata)
1473 return NULL;
1474
1475 return edata->folder;
1476}
+ 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 1488 of file notmuch.c.

1489{
1490 char *full_folder = nm_email_get_folder(e);
1491 if (!full_folder)
1492 return NULL;
1493
1494 const char *db_path = nm_db_get_filename(m);
1495 if (!db_path)
1496 return NULL;
1497
1498 size_t prefix = mutt_str_startswith(full_folder, db_path);
1499
1500 char *path = full_folder + prefix;
1501 if (*path == '/')
1502 path++;
1503
1504 return path;
1505}
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 1514 of file notmuch.c.

1515{
1516 if (!m)
1517 return -1;
1518
1519 struct NmMboxData *mdata = nm_mdata_get(m);
1520 if (!mdata)
1521 return -1;
1522
1523 notmuch_query_t *q = NULL;
1524 notmuch_database_t *db = NULL;
1525 notmuch_message_t *msg = NULL;
1526 int rc = -1;
1527
1528 if (!(db = nm_db_get(m, false)) || !(msg = get_nm_message(db, e)))
1529 goto done;
1530
1531 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages...[current count=%d]\n",
1532 m->msg_count);
1533
1534 progress_setup(m);
1535 const char *id = notmuch_message_get_thread_id(msg);
1536 if (!id)
1537 goto done;
1538
1539 struct Buffer *qstr = buf_pool_get();
1540 buf_printf(qstr, "thread:%s", id);
1541 q = notmuch_query_create(db, buf_string(qstr));
1542 buf_pool_release(&qstr);
1543 if (!q)
1544 goto done;
1546 notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
1547
1548 read_threads_query(m, q, true, 0);
1549 mdata->mtime.tv_sec = mutt_date_now();
1550 mdata->mtime.tv_nsec = 0;
1551 rc = 0;
1552
1553 if (m->msg_count > mdata->oldmsgcount)
1555done:
1556 if (q)
1557 notmuch_query_destroy(q);
1558
1559 nm_db_release(m);
1560
1561 if (m->msg_count == mdata->oldmsgcount)
1562 mutt_message(_("No more messages in the thread"));
1563
1564 mdata->oldmsgcount = 0;
1565 mutt_debug(LL_DEBUG1, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
1566 rc, m->msg_count);
1567 progress_free(&mdata->progress);
1568 return rc;
1569}
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:1047
static bool read_threads_query(struct Mailbox *m, notmuch_query_t *q, bool dedup, int limit)
Perform a query with threads.
Definition: notmuch.c:1010
static void progress_setup(struct Mailbox *m)
Set up the Progress Bar.
Definition: notmuch.c:678
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 1579 of file notmuch.c.

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

1639{
1640 const short c_nm_query_window_duration = cs_subset_number(NeoMutt->sub, "nm_query_window_duration");
1641 const bool c_nm_query_window_enable = cs_subset_bool(NeoMutt->sub, "nm_query_window_enable");
1642
1643 return c_nm_query_window_enable || (c_nm_query_window_duration > 0);
1644}
+ 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 1655 of file notmuch.c.

1656{
1657 const short c_nm_query_window_current_position = cs_subset_number(NeoMutt->sub, "nm_query_window_current_position");
1658 if (c_nm_query_window_current_position != 0)
1659 {
1660 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1661 c_nm_query_window_current_position - 1, NULL);
1662 }
1663
1664 mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position - 1);
1665}
+ 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 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 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position",
1679 c_nm_query_window_current_position + 1, NULL);
1680 mutt_debug(LL_DEBUG2, "(%d)\n", c_nm_query_window_current_position + 1);
1681}
+ 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 1686 of file notmuch.c.

1687{
1688 cs_subset_str_native_set(NeoMutt->sub, "nm_query_window_current_position", 0, NULL);
1689 mutt_debug(LL_DEBUG2, "Reset nm_query_window_current_position to 0\n");
1690}
+ 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 1698 of file notmuch.c.

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

1765{
1766 char buf[PATH_MAX] = { 0 };
1767 struct NmMboxData *mdata = nm_mdata_get(m);
1768 if (!mdata || !new_file)
1769 return -1;
1770
1771 if (!old_file && nm_edata_get(e))
1772 {
1773 email_get_fullpath(e, buf, sizeof(buf));
1774 old_file = buf;
1775 }
1776
1777 int rc = rename_filename(m, old_file, new_file, e);
1778
1779 nm_db_release(m);
1780 mdata->mtime.tv_sec = mutt_date_now();
1781 mdata->mtime.tv_nsec = 0;
1782 return rc;
1783}
static int rename_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Rename the file.
Definition: notmuch.c:1331
+ 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 1873 of file notmuch.c.

1874{
1875 // Create a new notmuch mailbox from scratch and add plumbing for DB access.
1876 char *default_url = nm_get_default_url();
1877 struct Mailbox *m = mx_path_resolve(default_url);
1878
1879 FREE(&default_url);
1880
1881 // These are no-ops for an initialized mailbox.
1882 init_mailbox(m);
1883 mx_mbox_ac_link(m);
1884
1885 return m;
1886}
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:1636
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 1896 of file notmuch.c.

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

1980{
1981 struct NmMboxData *mdata = nm_mdata_get(m);
1982 if (!mdata)
1983 return -1;
1984
1985 notmuch_database_t *db = NULL;
1986 notmuch_tags_t *tags = NULL;
1987 const char *tag = NULL;
1988 int rc = -1;
1989
1990 if (!(db = nm_db_get(m, false)) || !(tags = notmuch_database_get_all_tags(db)))
1991 goto done;
1992
1993 *tag_count = 0;
1994 mutt_debug(LL_DEBUG1, "nm: get all tags\n");
1995
1996 while (notmuch_tags_valid(tags))
1997 {
1998 tag = notmuch_tags_get(tags);
1999 /* Skip empty string */
2000 if (*tag)
2001 {
2002 if (tag_list)
2003 tag_list[*tag_count] = mutt_str_dup(tag);
2004 (*tag_count)++;
2005 }
2006 notmuch_tags_move_to_next(tags);
2007 }
2008
2009 rc = 0;
2010done:
2011 if (tags)
2012 notmuch_tags_destroy(tags);
2013
2014 nm_db_release(m);
2015
2016 mutt_debug(LL_DEBUG1, "nm: get all tags done [rc=%d tag_count=%u]\n", rc, *tag_count);
2017 return rc;
2018}
+ 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:1448
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:739

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.