NeoMutt  2022-04-29-70-g0c028c
Teaching an old dog new tricks
DOXYGEN
mx.c File Reference

Mailbox multiplexor. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "mutt.h"
#include "mx.h"
#include "maildir/lib.h"
#include "mbox/lib.h"
#include "menu/lib.h"
#include "question/lib.h"
#include "commands.h"
#include "copy.h"
#include "hook.h"
#include "keymap.h"
#include "mutt_globals.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "muttlib.h"
#include "opcodes.h"
#include "options.h"
#include "protos.h"
#include "compmbox/lib.h"
#include "imap/lib.h"
#include "pop/lib.h"
#include "nntp/lib.h"
#include "nntp/adata.h"
#include "nntp/mdata.h"
#include "notmuch/lib.h"
#include <libintl.h>
+ Include dependency graph for mx.c:

Go to the source code of this file.

Functions

const struct MxOpsmx_get_ops (enum MailboxType type)
 Get mailbox operations. More...
 
static bool mutt_is_spool (const char *str)
 Is this the spool_file? More...
 
int mx_access (const char *path, int flags)
 Wrapper for access, checks permissions on a given mailbox. More...
 
static bool mx_open_mailbox_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a mailbox for appending. More...
 
bool mx_mbox_ac_link (struct Mailbox *m)
 Link a Mailbox to an existing or new Account. More...
 
bool mx_mbox_open (struct Mailbox *m, OpenMailboxFlags flags)
 Open a mailbox and parse it. More...
 
void mx_fastclose_mailbox (struct Mailbox *m, bool keep_account)
 Free up memory associated with the Mailbox. More...
 
static enum MxStatus sync_mailbox (struct Mailbox *m)
 Save changes to disk. More...
 
static int trash_append (struct Mailbox *m)
 Move deleted mails to the trash folder. More...
 
enum MxStatus mx_mbox_close (struct Mailbox *m)
 Save changes and close mailbox. More...
 
enum MxStatus mx_mbox_sync (struct Mailbox *m)
 Save changes to mailbox. More...
 
struct Messagemx_msg_open_new (struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
 Open a new message. More...
 
enum MxStatus mx_mbox_check (struct Mailbox *m)
 Check for new mail - Wrapper for MxOps::mbox_check() More...
 
struct Messagemx_msg_open (struct Mailbox *m, int msgno)
 Return a stream pointer for a message. More...
 
int mx_msg_commit (struct Mailbox *m, struct Message *msg)
 Commit a message to a folder - Wrapper for MxOps::msg_commit() More...
 
int mx_msg_close (struct Mailbox *m, struct Message **msg)
 Close a message. More...
 
void mx_alloc_memory (struct Mailbox *m)
 Create storage for the emails. More...
 
int mx_path_is_empty (const char *path)
 Is the mailbox empty. More...
 
int mx_tags_edit (struct Mailbox *m, const char *tags, struct Buffer *buf)
 Start the tag editor of the mailbox. More...
 
int mx_tags_commit (struct Mailbox *m, struct Email *e, const char *tags)
 Save tags to the Mailbox - Wrapper for MxOps::tags_commit() More...
 
bool mx_tags_is_supported (struct Mailbox *m)
 Return true if mailbox support tagging. More...
 
enum MailboxType mx_path_probe (const char *path)
 Find a mailbox that understands a path. More...
 
int mx_path_canon (char *buf, size_t buflen, const char *folder, enum MailboxType *type)
 Canonicalise a mailbox path - Wrapper for MxOps::path_canon() More...
 
int mx_path_canon2 (struct Mailbox *m, const char *folder)
 Canonicalise the path to realpath. More...
 
int mx_path_pretty (char *buf, size_t buflen, const char *folder)
 Abbreviate a mailbox path - Wrapper for MxOps::path_pretty() More...
 
int mx_path_parent (char *buf, size_t buflen)
 Find the parent of a mailbox path - Wrapper for MxOps::path_parent() More...
 
int mx_msg_padding_size (struct Mailbox *m)
 Bytes of padding between messages - Wrapper for MxOps::msg_padding_size() More...
 
struct Accountmx_ac_find (struct Mailbox *m)
 Find the Account owning a Mailbox. More...
 
struct Mailboxmx_mbox_find (struct Account *a, const char *path)
 Find a Mailbox on an Account. More...
 
struct Mailboxmx_mbox_find2 (const char *path)
 Find a Mailbox on an Account. More...
 
struct Mailboxmx_path_resolve (const char *path)
 Get a Mailbox for a path. More...
 
static struct Mailboxmx_mbox_find_by_name_ac (struct Account *a, const char *name)
 Find a Mailbox with given name under an Account. More...
 
static struct Mailboxmx_mbox_find_by_name (const char *name)
 Find a Mailbox with given name. More...
 
struct Mailboxmx_resolve (const char *path_or_name)
 Get a Mailbox from either a path or name. More...
 
bool mx_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Wrapper for MxOps::ac_add() More...
 
int mx_ac_remove (struct Mailbox *m, bool keep_account)
 Remove a Mailbox from an Account and delete Account if empty. More...
 
enum MxStatus mx_mbox_check_stats (struct Mailbox *m, uint8_t flags)
 Check the statistics for a mailbox - Wrapper for MxOps::mbox_check_stats() More...
 
int mx_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Wrapper for MxOps::msg_save_hcache() More...
 
enum MailboxType mx_type (struct Mailbox *m)
 Return the type of the Mailbox. More...
 
int mx_toggle_write (struct Mailbox *m)
 Toggle the mailbox's readonly flag. More...
 

Variables

static const struct Mapping MboxTypeMap []
 
struct EnumDef MboxTypeDef
 
const struct MxOpsMxOps []
 All the Mailbox backends. More...
 

Detailed Description

Mailbox multiplexor.

Authors
  • Michael R. Elkins
  • Thomas Roessler
  • Richard Russon
  • Pietro Cerutti

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 mx.c.

Function Documentation

◆ mx_get_ops()

const struct MxOps* mx_get_ops ( enum MailboxType  type)

Get mailbox operations.

Parameters
typeMailbox type
Return values
ptrMailbox function
NULLError

Definition at line 141 of file mx.c.

142 {
143  for (const struct MxOps **ops = MxOps; *ops; ops++)
144  if ((*ops)->type == type)
145  return *ops;
146 
147  return NULL;
148 }
Definition: mxapi.h:112
+ Here is the caller graph for this function:

◆ mutt_is_spool()

static bool mutt_is_spool ( const char *  str)
static

Is this the spool_file?

Parameters
strName to check
Return values
trueIt is the spool_file

Definition at line 155 of file mx.c.

156 {
157  const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
158  if (mutt_str_equal(str, c_spool_file))
159  return true;
160 
161  struct Url *ua = url_parse(str);
162  struct Url *ub = url_parse(c_spool_file);
163 
164  const bool is_spool = ua && ub && (ua->scheme == ub->scheme) &&
165  mutt_istr_equal(ua->host, ub->host) &&
166  mutt_istr_equal(ua->path, ub->path) &&
167  (!ua->user || !ub->user || mutt_str_equal(ua->user, ub->user));
168 
169  url_free(&ua);
170  url_free(&ub);
171  return is_spool;
172 }
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * user
Username.
Definition: url.h:71
char * host
Host.
Definition: url.h:73
char * path
Path.
Definition: url.h:75
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:70
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
+ Here is the call graph for this function:

◆ mx_access()

int mx_access ( const char *  path,
int  flags 
)

Wrapper for access, checks permissions on a given mailbox.

Parameters
pathPath of mailbox
flagsFlags, e.g. W_OK
Return values
0Success, allowed
<0Failure, not allowed

We may be interested in using ACL-style flags at some point, currently we use the normal access() flags.

Definition at line 184 of file mx.c.

185 {
186 #ifdef USE_IMAP
187  if (imap_path_probe(path, NULL) == MUTT_IMAP)
188  return imap_access(path);
189 #endif
190 
191  return access(path, flags);
192 }
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2400
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:473
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_open_mailbox_append()

static bool mx_open_mailbox_append ( struct Mailbox m,
OpenMailboxFlags  flags 
)
static

Open a mailbox for appending.

Parameters
mMailbox
flagsFlags, see OpenMailboxFlags
Return values
trueSuccess
falseFailure

Definition at line 201 of file mx.c.

202 {
203  if (!m)
204  return false;
205 
206  struct stat st = { 0 };
207 
208  m->append = true;
209  if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR))
210  {
212 
213  if (m->type == MUTT_UNKNOWN)
214  {
215  if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
216  {
218  }
219  else
220  {
221  mutt_error(_("%s is not a mailbox"), mailbox_path(m));
222  return false;
223  }
224  }
225 
226  if (m->type == MUTT_MAILBOX_ERROR)
227  {
228  if (stat(mailbox_path(m), &st) == -1)
229  {
230  if (errno == ENOENT)
231  {
232 #ifdef USE_COMP_MBOX
233  if (mutt_comp_can_append(m))
234  m->type = MUTT_COMPRESSED;
235  else
236 #endif
237  m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
238  flags |= MUTT_APPENDNEW;
239  }
240  else
241  {
243  return false;
244  }
245  }
246  else
247  return false;
248  }
249 
250  m->mx_ops = mx_get_ops(m->type);
251  }
252 
253  if (!m->mx_ops || !m->mx_ops->mbox_open_append)
254  return false;
255 
256  const bool rc = m->mx_ops->mbox_open_append(m, flags);
257  m->opened++;
258  return rc;
259 }
bool mutt_comp_can_append(struct Mailbox *m)
Can we append to this path?
Definition: compress.c:362
#define mutt_error(...)
Definition: logging.h:87
#define mutt_perror(...)
Definition: logging.h:88
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:97
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:211
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition: mailbox.h:43
@ MUTT_COMPRESSED
Compressed file Mailbox type.
Definition: mailbox.h:53
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
#define _(a)
Definition: message.h:28
const struct MxOps * mx_get_ops(enum MailboxType type)
Get mailbox operations.
Definition: mx.c:141
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1327
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND,.
Definition: mxapi.h:66
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:63
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition: mxapi.h:70
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:110
const struct MxOps * mx_ops
MXAPI callback functions.
Definition: mailbox.h:108
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
int opened
Number of times mailbox is opened.
Definition: mailbox.h:129
bool(* mbox_open_append)(struct Mailbox *m, OpenMailboxFlags flags)
Definition: mxapi.h:175
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_ac_link()

bool mx_mbox_ac_link ( struct Mailbox m)

Link a Mailbox to an existing or new Account.

Parameters
mMailbox to link
Return values
trueSuccess
falseFailure

Definition at line 267 of file mx.c.

268 {
269  if (!m)
270  return false;
271 
272  if (m->account)
273  return true;
274 
275  struct Account *a = mx_ac_find(m);
276  const bool new_account = !a;
277  if (new_account)
278  {
279  a = account_new(NULL, NeoMutt->sub);
280  a->type = m->type;
281  }
282  if (!mx_ac_add(a, m))
283  {
284  if (new_account)
285  {
286  account_free(&a);
287  }
288  return false;
289  }
290  if (new_account)
291  {
293  }
294  return true;
295 }
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:43
void account_free(struct Account **ptr)
Free an Account.
Definition: account.c:141
bool mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1764
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1563
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition: neomutt.c:84
A group of associated Mailboxes.
Definition: account.h:37
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:38
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:128
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_open()

bool mx_mbox_open ( struct Mailbox m,
OpenMailboxFlags  flags 
)

Open a mailbox and parse it.

Parameters
mMailbox to open
flagsFlags, see OpenMailboxFlags
Return values
trueSuccess
falseError

Definition at line 304 of file mx.c.

305 {
306  if (!m)
307  return false;
308 
309  if ((m->type == MUTT_UNKNOWN) && (flags & (MUTT_NEWFOLDER | MUTT_APPEND)))
310  {
311  m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
312  m->mx_ops = mx_get_ops(m->type);
313  }
314 
315  const bool newly_linked_account = !m->account;
316  if (newly_linked_account)
317  {
318  if (!mx_mbox_ac_link(m))
319  {
320  return false;
321  }
322  }
323 
324  m->verbose = !(flags & MUTT_QUIET);
325  m->readonly = (flags & MUTT_READONLY);
326  m->peekonly = (flags & MUTT_PEEK);
327 
328  if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
329  {
330  if (!mx_open_mailbox_append(m, flags))
331  {
332  goto error;
333  }
334  return true;
335  }
336 
337  if (m->opened > 0)
338  {
339  m->opened++;
340  return true;
341  }
342 
343  m->size = 0;
344  m->msg_unread = 0;
345  m->msg_flagged = 0;
346  m->rights = MUTT_ACL_ALL;
347 
348  if (m->type == MUTT_UNKNOWN)
349  {
351  m->mx_ops = mx_get_ops(m->type);
352  }
353 
354  if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR) || !m->mx_ops)
355  {
356  if (m->type == MUTT_MAILBOX_ERROR)
358  else if ((m->type == MUTT_UNKNOWN) || !m->mx_ops)
359  mutt_error(_("%s is not a mailbox"), mailbox_path(m));
360  goto error;
361  }
362 
364 
365  /* if the user has a 'push' command in their .neomuttrc, or in a folder-hook,
366  * it will cause the progress messages not to be displayed because
367  * mutt_refresh() will think we are in the middle of a macro. so set a
368  * flag to indicate that we should really refresh the screen. */
369  OptForceRefresh = true;
370 
371  if (m->verbose)
372  mutt_message(_("Reading %s..."), mailbox_path(m));
373 
374  // Clear out any existing emails
375  for (int i = 0; i < m->email_max; i++)
376  {
377  email_free(&m->emails[i]);
378  }
379 
380  m->msg_count = 0;
381  m->msg_unread = 0;
382  m->msg_flagged = 0;
383  m->msg_new = 0;
384  m->msg_deleted = 0;
385  m->msg_tagged = 0;
386  m->vcount = 0;
387 
388  enum MxOpenReturns rc = m->mx_ops->mbox_open(m);
389  m->opened++;
390 
391  if ((rc == MX_OPEN_OK) || (rc == MX_OPEN_ABORT))
392  {
393  if ((flags & MUTT_NOSORT) == 0)
394  {
395  /* avoid unnecessary work since the mailbox is completely unthreaded
396  * to begin with */
397  OptSortSubthreads = false;
398  OptNeedRescore = false;
399  }
400  if (m->verbose)
402  if (rc == MX_OPEN_ABORT)
403  {
404  mutt_error(_("Reading from %s interrupted..."), mailbox_path(m));
405  }
406  }
407  else
408  {
409  goto error;
410  }
411 
412  if (!m->peekonly)
413  m->has_new = false;
414  OptForceRefresh = false;
415 
416  return true;
417 
418 error:
419  mx_fastclose_mailbox(m, newly_linked_account);
420  if (newly_linked_account)
422  return false;
423 }
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:96
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
#define mutt_message(...)
Definition: logging.h:86
#define MUTT_ACL_ALL
Definition: mailbox.h:73
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition: mutt_header.c:370
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition: mx.c:430
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:267
static bool mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox for appending.
Definition: mx.c:201
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:64
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:65
MxOpenReturns
Return values for mbox_open()
Definition: mxapi.h:97
@ MX_OPEN_ABORT
Open was aborted.
Definition: mxapi.h:100
@ MX_OPEN_OK
Open succeeded.
Definition: mxapi.h:98
#define MUTT_PEEK
Revert atime back after taking a look (if applicable)
Definition: mxapi.h:69
#define MUTT_NOSORT
Do not sort the mailbox after opening it.
Definition: mxapi.h:62
bool OptNeedRescore
(pseudo) set when the 'score' command is used
Definition: options.h:47
bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:42
bool OptSortSubthreads
(pseudo) used when $sort_aux changes
Definition: options.h:59
int vcount
The number of virtual messages.
Definition: mailbox.h:99
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
int msg_new
Number of new messages.
Definition: mailbox.h:92
int msg_count
Total number of messages.
Definition: mailbox.h:88
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:118
int email_max
Number of pointers in emails.
Definition: mailbox.h:97
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
bool peekonly
Just taking a glance, revert atime.
Definition: mailbox.h:114
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:93
off_t size
Size of the Mailbox.
Definition: mailbox.h:84
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:90
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:116
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:94
bool verbose
Display status messages?
Definition: mailbox.h:115
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
enum MxOpenReturns(* mbox_open)(struct Mailbox *m)
Definition: mxapi.h:160
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_fastclose_mailbox()

void mx_fastclose_mailbox ( struct Mailbox m,
bool  keep_account 
)

Free up memory associated with the Mailbox.

Parameters
mMailbox
keep_accountMake sure not to remove the mailbox's account

Definition at line 430 of file mx.c.

431 {
432  if (!m)
433  return;
434 
435  m->opened--;
436  if (m->opened != 0)
437  return;
438 
439  /* never announce that a mailbox we've just left has new mail.
440  * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
441  if (!m->peekonly)
443 
444  if (m->mx_ops)
445  m->mx_ops->mbox_close(m);
446 
448  mutt_hash_free(&m->id_hash);
450 
451  if (m->emails)
452  {
453  for (int i = 0; i < m->msg_count; i++)
454  {
455  if (!m->emails[i])
456  break;
457  email_free(&m->emails[i]);
458  }
459  }
460 
461  if (!m->visible)
462  {
463  mx_ac_remove(m, keep_account);
464  }
465 }
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
void mutt_mailbox_set_notified(struct Mailbox *m)
Note when the user was last notified of new mail.
Definition: mutt_mailbox.c:312
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1781
struct HashTable * subj_hash
Hash Table by subject.
Definition: mailbox.h:125
struct HashTable * id_hash
Hash Table by msg id.
Definition: mailbox.h:124
struct HashTable * label_hash
Hash Table for x-labels.
Definition: mailbox.h:126
bool visible
True if a result of "mailboxes".
Definition: mailbox.h:131
enum MxStatus(* mbox_close)(struct Mailbox *m)
Definition: mxapi.h:228
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sync_mailbox()

static enum MxStatus sync_mailbox ( struct Mailbox m)
static

Save changes to disk.

Parameters
mMailbox
Return values
enumMxStatus

Definition at line 430 of file mx.c.

473 {
474  if (!m || !m->mx_ops || !m->mx_ops->mbox_sync)
475  return MX_STATUS_ERROR;
476 
477  if (m->verbose)
478  {
479  /* L10N: Displayed before/as a mailbox is being synced */
480  mutt_message(_("Writing %s..."), mailbox_path(m));
481  }
482 
483  enum MxStatus rc = m->mx_ops->mbox_sync(m);
484  if (rc != MX_STATUS_OK)
485  {
486  mutt_debug(LL_DEBUG2, "mbox_sync returned: %d\n", rc);
487  if ((rc == MX_STATUS_ERROR) && m->verbose)
488  {
489  /* L10N: Displayed if a mailbox sync fails */
490  mutt_error(_("Unable to write %s"), mailbox_path(m));
491  }
492  }
493 
494  return rc;
495 }
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:84
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:85
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:86
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition: mxapi.h:215

◆ trash_append()

static int trash_append ( struct Mailbox m)
static

Move deleted mails to the trash folder.

Parameters
mMailbox
Return values
0Success
-1Failure

Definition at line 503 of file mx.c.

504 {
505  if (!m)
506  return -1;
507 
508  struct stat st = { 0 };
509  struct stat stc = { 0 };
510  int rc;
511 
512  const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
513  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
514  if (!c_trash || (m->msg_deleted == 0) || ((m->type == MUTT_MAILDIR) && c_maildir_trash))
515  {
516  return 0;
517  }
518 
519  int delmsgcount = 0;
520  int first_del = -1;
521  for (int i = 0; i < m->msg_count; i++)
522  {
523  struct Email *e = m->emails[i];
524  if (!e)
525  break;
526 
527  if (e->deleted && !e->purge)
528  {
529  if (first_del < 0)
530  first_del = i;
531  delmsgcount++;
532  }
533  }
534 
535  if (delmsgcount == 0)
536  return 0; /* nothing to be done */
537 
538  /* avoid the "append messages" prompt */
539  const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
540  cs_subset_str_native_set(NeoMutt->sub, "confirm_append", false, NULL);
541  rc = mutt_save_confirm(c_trash, &st);
542  cs_subset_str_native_set(NeoMutt->sub, "confirm_append", c_confirm_append, NULL);
543  if (rc != 0)
544  {
545  /* L10N: Although we know the precise number of messages, we do not show it to the user.
546  So feel free to use a "generic plural" as plural translation if your language has one. */
547  mutt_error(ngettext("message not deleted", "messages not deleted", delmsgcount));
548  return -1;
549  }
550 
551  if ((lstat(mailbox_path(m), &stc) == 0) && (stc.st_ino == st.st_ino) &&
552  (stc.st_dev == st.st_dev) && (stc.st_rdev == st.st_rdev))
553  {
554  return 0; /* we are in the trash folder: simple sync */
555  }
556 
557 #ifdef USE_IMAP
558  if ((m->type == MUTT_IMAP) && (imap_path_probe(c_trash, NULL) == MUTT_IMAP))
559  {
560  if (imap_fast_trash(m, c_trash) == 0)
561  return 0;
562  }
563 #endif
564 
565  struct Mailbox *m_trash = mx_path_resolve(c_trash);
566  const bool old_append = m_trash->append;
567  if (!mx_mbox_open(m_trash, MUTT_APPEND))
568  {
569  mutt_error(_("Can't open trash folder"));
570  mailbox_free(&m_trash);
571  return -1;
572  }
573 
574  /* continue from initial scan above */
575  for (int i = first_del; i < m->msg_count; i++)
576  {
577  struct Email *e = m->emails[i];
578  if (!e)
579  break;
580 
581  if (e->deleted && !e->purge)
582  {
583  if (mutt_append_message(m_trash, m, e, NULL, MUTT_CM_NO_FLAGS, CH_NO_FLAGS) == -1)
584  {
585  mx_mbox_close(m_trash);
586  // L10N: Displayed if appending to $trash fails when syncing or closing a mailbox
587  mutt_error(_("Unable to append to trash folder"));
588  m_trash->append = old_append;
589  return -1;
590  }
591  }
592  }
593 
594  mx_mbox_close(m_trash);
595  m_trash->append = old_append;
596  mailbox_free(&m_trash);
597 
598  return 0;
599 }
int mutt_append_message(struct Mailbox *m_dst, struct Mailbox *m_src, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
Append a message.
Definition: copy.c:939
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
int imap_fast_trash(struct Mailbox *m, const char *dest)
Use server COPY command to copy deleted messages to trash.
Definition: imap.c:1424
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1355
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
The envelope/body of an email.
Definition: email.h:37
bool purge
Skip trash folder when deleting.
Definition: email.h:77
bool deleted
Email is deleted.
Definition: email.h:76
A mailbox.
Definition: mailbox.h:79
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:305

◆ mx_mbox_close()

enum MxStatus mx_mbox_close ( struct Mailbox m)

Save changes and close mailbox.

Parameters
mMailbox
Return values
enumMxStatus
Note
The flag retvals come from a call to a backend sync function
It's very important to ensure the mailbox is properly closed before free'ing the context. For selected mailboxes, IMAP will cache the context inside connection->adata until imap_close_mailbox() removes it. Readonly, dontwrite, and append mailboxes are guaranteed to call mx_fastclose_mailbox(), so for most of NeoMutt's code you won't see return value checks for temporary contexts.

Definition at line 503 of file mx.c.

616 {
617  if (!m)
618  return MX_STATUS_ERROR;
619 
620  const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
621  if (c_mail_check_recent && !m->peekonly)
622  m->has_new = false;
623 
624  if (m->readonly || m->dontwrite || m->append || m->peekonly)
625  {
626  mx_fastclose_mailbox(m, false);
627  return 0;
628  }
629 
630  int i, read_msgs = 0;
631  enum MxStatus rc = MX_STATUS_ERROR;
632  enum QuadOption move_messages = MUTT_NO;
633  enum QuadOption purge = MUTT_YES;
634  struct Buffer *mbox = NULL;
635  struct Buffer *buf = mutt_buffer_pool_get();
636 
637 #ifdef USE_NNTP
638  if ((m->msg_unread != 0) && (m->type == MUTT_NNTP))
639  {
640  struct NntpMboxData *mdata = m->mdata;
641 
642  if (mdata && mdata->adata && mdata->group)
643  {
644  const enum QuadOption c_catchup_newsgroup = cs_subset_quad(NeoMutt->sub, "catchup_newsgroup");
645  enum QuadOption ans = query_quadoption(c_catchup_newsgroup,
646  _("Mark all articles read?"));
647  if (ans == MUTT_ABORT)
648  goto cleanup;
649  if (ans == MUTT_YES)
650  mutt_newsgroup_catchup(m, mdata->adata, mdata->group);
651  }
652  }
653 #endif
654 
655  const bool c_keep_flagged = cs_subset_bool(NeoMutt->sub, "keep_flagged");
656  for (i = 0; i < m->msg_count; i++)
657  {
658  struct Email *e = m->emails[i];
659  if (!e)
660  break;
661 
662  if (!e->deleted && e->read && !(e->flagged && c_keep_flagged))
663  read_msgs++;
664  }
665 
666 #ifdef USE_NNTP
667  /* don't need to move articles from newsgroup */
668  if (m->type == MUTT_NNTP)
669  read_msgs = 0;
670 #endif
671 
672  const enum QuadOption c_move = cs_subset_quad(NeoMutt->sub, "move");
673  if ((read_msgs != 0) && (c_move != MUTT_NO))
674  {
675  bool is_spool;
676  mbox = mutt_buffer_pool_get();
677 
679  if (p)
680  {
681  is_spool = true;
682  mutt_buffer_strcpy(mbox, p);
683  }
684  else
685  {
686  const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
687  mutt_buffer_strcpy(mbox, c_mbox);
688  is_spool = mutt_is_spool(mailbox_path(m)) &&
690  }
691 
692  if (is_spool && !mutt_buffer_is_empty(mbox))
693  {
695  mutt_buffer_printf(buf,
696  /* L10N: The first argument is the number of read messages to be
697  moved, the second argument is the target mailbox. */
698  ngettext("Move %d read message to %s?",
699  "Move %d read messages to %s?", read_msgs),
700  read_msgs, mutt_buffer_string(mbox));
701  move_messages = query_quadoption(c_move, mutt_buffer_string(buf));
702  if (move_messages == MUTT_ABORT)
703  goto cleanup;
704  }
705  }
706 
707  /* There is no point in asking whether or not to purge if we are
708  * just marking messages as "trash". */
709  const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
710  if ((m->msg_deleted != 0) && !((m->type == MUTT_MAILDIR) && c_maildir_trash))
711  {
712  mutt_buffer_printf(buf,
713  ngettext("Purge %d deleted message?",
714  "Purge %d deleted messages?", m->msg_deleted),
715  m->msg_deleted);
716  const enum QuadOption c_delete = cs_subset_quad(NeoMutt->sub, "delete");
717  purge = query_quadoption(c_delete, mutt_buffer_string(buf));
718  if (purge == MUTT_ABORT)
719  goto cleanup;
720  }
721 
722  const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
723  if (c_mark_old && !m->peekonly)
724  {
725  for (i = 0; i < m->msg_count; i++)
726  {
727  struct Email *e = m->emails[i];
728  if (!e)
729  break;
730  if (!e->deleted && !e->old && !e->read)
731  mutt_set_flag(m, e, MUTT_OLD, true);
732  }
733  }
734 
735  if (move_messages)
736  {
737  if (m->verbose)
738  mutt_message(_("Moving read messages to %s..."), mutt_buffer_string(mbox));
739 
740 #ifdef USE_IMAP
741  /* try to use server-side copy first */
742  i = 1;
743 
744  if ((m->type == MUTT_IMAP) && (imap_path_probe(mutt_buffer_string(mbox), NULL) == MUTT_IMAP))
745  {
746  /* add messages for moving, and clear old tags, if any */
747  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
748  for (i = 0; i < m->msg_count; i++)
749  {
750  struct Email *e = m->emails[i];
751  if (!e)
752  break;
753 
754  if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
755  {
756  e->tagged = true;
757  emaillist_add_email(&el, e);
758  }
759  else
760  e->tagged = false;
761  }
762 
763  i = imap_copy_messages(m, &el, mutt_buffer_string(mbox), SAVE_MOVE);
764  emaillist_clear(&el);
765  }
766 
767  if (i == 0) /* success */
769  else if (i == -1) /* horrible error, bail */
770  goto cleanup;
771  else /* use regular append-copy mode */
772 #endif
773  {
774  struct Mailbox *m_read = mx_path_resolve(mutt_buffer_string(mbox));
775  if (!mx_mbox_open(m_read, MUTT_APPEND))
776  {
777  mailbox_free(&m_read);
778  goto cleanup;
779  }
780 
781  for (i = 0; i < m->msg_count; i++)
782  {
783  struct Email *e = m->emails[i];
784  if (!e)
785  break;
786  if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
787  {
788  if (mutt_append_message(m_read, m, e, NULL, MUTT_CM_NO_FLAGS, CH_UPDATE_LEN) == 0)
789  {
790  mutt_set_flag(m, e, MUTT_DELETE, true);
791  mutt_set_flag(m, e, MUTT_PURGE, true);
792  }
793  else
794  {
795  mx_mbox_close(m_read);
796  goto cleanup;
797  }
798  }
799  }
800 
801  mx_mbox_close(m_read);
802  }
803  }
804  else if (!m->changed && (m->msg_deleted == 0))
805  {
806  if (m->verbose)
807  mutt_message(_("Mailbox is unchanged"));
808  if ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF))
809  mbox_reset_atime(m, NULL);
810  mx_fastclose_mailbox(m, false);
811  rc = MX_STATUS_OK;
812  goto cleanup;
813  }
814 
815  /* copy mails to the trash before expunging */
816  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
817  const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
818  if (purge && (m->msg_deleted != 0) && (m != m_trash))
819  {
820  if (trash_append(m) != 0)
821  goto cleanup;
822  }
823 
824 #ifdef USE_IMAP
825  /* allow IMAP to preserve the deleted flag across sessions */
826  if (m->type == MUTT_IMAP)
827  {
828  const enum MxStatus check = imap_sync_mailbox(m, (purge != MUTT_NO), true);
829  if (check == MX_STATUS_ERROR)
830  {
831  rc = check;
832  goto cleanup;
833  }
834  }
835  else
836 #endif
837  {
838  if (purge == MUTT_NO)
839  {
840  for (i = 0; i < m->msg_count; i++)
841  {
842  struct Email *e = m->emails[i];
843  if (!e)
844  break;
845 
846  e->deleted = false;
847  e->purge = false;
848  }
849  m->msg_deleted = 0;
850  }
851 
852  if (m->changed || (m->msg_deleted != 0))
853  {
854  enum MxStatus check = sync_mailbox(m);
855  if (check != MX_STATUS_OK)
856  {
857  rc = check;
858  goto cleanup;
859  }
860  }
861  }
862 
863  if (m->verbose)
864  {
865  if (move_messages)
866  {
867  mutt_message(_("%d kept, %d moved, %d deleted"),
868  m->msg_count - m->msg_deleted, read_msgs, m->msg_deleted);
869  }
870  else
871  mutt_message(_("%d kept, %d deleted"), m->msg_count - m->msg_deleted, m->msg_deleted);
872  }
873 
874  const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
875  if ((m->msg_count == m->msg_deleted) &&
876  ((m->type == MUTT_MMDF) || (m->type == MUTT_MBOX)) &&
877  !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
878  {
880  }
881 
882 #ifdef USE_SIDEBAR
883  if ((purge == MUTT_YES) && (m->msg_deleted != 0))
884  {
885  for (i = 0; i < m->msg_count; i++)
886  {
887  struct Email *e = m->emails[i];
888  if (!e)
889  break;
890  if (e->deleted && !e->read)
891  {
892  m->msg_unread--;
893  if (!e->old)
894  m->msg_new--;
895  }
896  if (e->deleted && e->flagged)
897  m->msg_flagged--;
898  }
899  }
900 #endif
901 
902  mx_fastclose_mailbox(m, false);
903 
904  rc = MX_STATUS_OK;
905 
906 cleanup:
909  return rc;
910 }
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: commands.h:51
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:159
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:138
void mutt_file_unlink_empty(const char *path)
Delete a file if it's empty.
Definition: file.c:1367
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
char * mutt_find_hook(HookFlags type, const char *pat)
Find a matching hook.
Definition: hook.c:610
#define MUTT_MBOX_HOOK
mbox-hook: move messages after reading them
Definition: hook.h:39
int imap_copy_messages(struct Mailbox *m, struct EmailList *el, const char *dest, enum MessageSaveOpt save_opt)
Server COPY messages to another folder.
Definition: message.c:1672
enum MxStatus imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
Sync all the changes to the server.
Definition: imap.c:1534
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:49
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition: mbox.c:846
@ MUTT_OLD
Old messages.
Definition: mutt.h:90
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:96
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:94
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:321
static enum MxStatus sync_mailbox(struct Mailbox *m)
Save changes to disk.
Definition: mx.c:472
static int trash_append(struct Mailbox *m)
Move deleted mails to the trash folder.
Definition: mx.c:503
static bool mutt_is_spool(const char *str)
Is this the spool_file?
Definition: mx.c:155
struct Mailbox * mx_mbox_find(struct Account *a, const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1587
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1321
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:64
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
String manipulation buffer.
Definition: buffer.h:34
bool read
Email is read.
Definition: email.h:48
bool old
Email is seen, but unread.
Definition: email.h:47
bool flagged
Marked important?
Definition: email.h:45
bool tagged
Email is tagged.
Definition: email.h:107
bool changed
Mailbox has been modified.
Definition: mailbox.h:111
void * mdata
Driver specific data.
Definition: mailbox.h:133
bool dontwrite
Don't write the mailbox on close.
Definition: mailbox.h:112
NNTP-specific Mailbox data -.
Definition: mdata.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_sync()

enum MxStatus mx_mbox_sync ( struct Mailbox m)

Save changes to mailbox.

Parameters
[in]mMailbox
Return values
enumMxStatus
Note
The flag retvals come from a call to a backend sync function

Definition at line 503 of file mx.c.

920 {
921  if (!m)
922  return MX_STATUS_ERROR;
923 
924  enum MxStatus rc = MX_STATUS_OK;
925  int purge = 1;
926  int msgcount, deleted;
927 
928  if (m->dontwrite)
929  {
930  char buf[256], tmp[256];
931  if (km_expand_key(buf, sizeof(buf), km_find_func(MENU_INDEX, OP_TOGGLE_WRITE)))
932  snprintf(tmp, sizeof(tmp), _(" Press '%s' to toggle write"), buf);
933  else
934  mutt_str_copy(tmp, _("Use 'toggle-write' to re-enable write"), sizeof(tmp));
935 
936  mutt_error(_("Mailbox is marked unwritable. %s"), tmp);
937  return MX_STATUS_ERROR;
938  }
939  else if (m->readonly)
940  {
941  mutt_error(_("Mailbox is read-only"));
942  return MX_STATUS_ERROR;
943  }
944 
945  if (!m->changed && (m->msg_deleted == 0))
946  {
947  if (m->verbose)
948  mutt_message(_("Mailbox is unchanged"));
949  return MX_STATUS_OK;
950  }
951 
952  if (m->msg_deleted != 0)
953  {
954  char buf[128];
955 
956  snprintf(buf, sizeof(buf),
957  ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
958  m->msg_deleted);
959  const enum QuadOption c_delete = cs_subset_quad(NeoMutt->sub, "delete");
960  purge = query_quadoption(c_delete, buf);
961  if (purge == MUTT_ABORT)
962  return MX_STATUS_ERROR;
963  if (purge == MUTT_NO)
964  {
965  if (!m->changed)
966  return MX_STATUS_OK; /* nothing to do! */
967  /* let IMAP servers hold on to D flags */
968  if (m->type != MUTT_IMAP)
969  {
970  for (int i = 0; i < m->msg_count; i++)
971  {
972  struct Email *e = m->emails[i];
973  if (!e)
974  break;
975  e->deleted = false;
976  e->purge = false;
977  }
978  m->msg_deleted = 0;
979  }
980  }
982  }
983 
984  /* really only for IMAP - imap_sync_mailbox results in a call to
985  * ctx_update_tables, so m->msg_deleted is 0 when it comes back */
986  msgcount = m->msg_count;
987  deleted = m->msg_deleted;
988 
989  const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
990  const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
991  if (purge && (m->msg_deleted != 0) && (m != m_trash))
992  {
993  if (trash_append(m) != 0)
994  return MX_STATUS_OK;
995  }
996 
997 #ifdef USE_IMAP
998  if (m->type == MUTT_IMAP)
999  rc = imap_sync_mailbox(m, purge, false);
1000  else
1001 #endif
1002  rc = sync_mailbox(m);
1003  if (rc != MX_STATUS_ERROR)
1004  {
1005 #ifdef USE_IMAP
1006  if ((m->type == MUTT_IMAP) && !purge)
1007  {
1008  if (m->verbose)
1009  mutt_message(_("Mailbox checkpointed"));
1010  }
1011  else
1012 #endif
1013  {
1014  if (m->verbose)
1015  mutt_message(_("%d kept, %d deleted"), msgcount - deleted, deleted);
1016  }
1017 
1018  mutt_sleep(0);
1019 
1020  const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
1021  if ((m->msg_count == m->msg_deleted) &&
1022  ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) &&
1023  !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
1024  {
1025  unlink(mailbox_path(m));
1026  mx_fastclose_mailbox(m, false);
1027  return MX_STATUS_OK;
1028  }
1029 
1030  /* if we haven't deleted any messages, we don't need to resort
1031  * ... except for certain folder formats which need "unsorted"
1032  * sort order in order to synchronize folders.
1033  *
1034  * MH and maildir are safe. mbox-style seems to need re-sorting,
1035  * at least with the new threading code. */
1036  if (purge || ((m->type != MUTT_MAILDIR) && (m->type != MUTT_MH)))
1037  {
1038  /* IMAP does this automatically after handling EXPUNGE */
1039  if (m->type != MUTT_IMAP)
1040  {
1043  }
1044  }
1045  }
1046 
1047  return rc;
1048 }
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function's mapping in a Menu.
Definition: keymap.c:957
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:929
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:222
@ NT_MAILBOX_UNTAG
Clear the 'last-tagged' pointer.
Definition: mailbox.h:180
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:178
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:179
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:47
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:629
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1454
@ MENU_INDEX
Index panel (list of emails)
Definition: type.h:50
+ Here is the caller graph for this function:

◆ mx_msg_open_new()

struct Message* mx_msg_open_new ( struct Mailbox m,
const struct Email e,
MsgOpenFlags  flags 
)

Open a new message.

Parameters
mDestination mailbox
eMessage being copied (required for maildir support, because the filename depends on the message flags)
flagsFlags, see MsgOpenFlags
Return values
ptrNew Message

Definition at line 1057 of file mx.c.

1058 {
1059  if (!m)
1060  return NULL;
1061 
1062  struct Address *p = NULL;
1063  struct Message *msg = NULL;
1064 
1065  if (!m->mx_ops || !m->mx_ops->msg_open_new)
1066  {
1067  mutt_debug(LL_DEBUG1, "function unimplemented for mailbox type %d\n", m->type);
1068  return NULL;
1069  }
1070 
1071  msg = mutt_mem_calloc(1, sizeof(struct Message));
1072  msg->write = true;
1073 
1074  if (e)
1075  {
1076  msg->flags.flagged = e->flagged;
1077  msg->flags.replied = e->replied;
1078  msg->flags.read = e->read;
1079  msg->flags.draft = (flags & MUTT_SET_DRAFT);
1080  msg->received = e->received;
1081  }
1082 
1083  if (msg->received == 0)
1084  msg->received = mutt_date_epoch();
1085 
1086  if (m->mx_ops->msg_open_new(m, msg, e))
1087  {
1088  if (m->type == MUTT_MMDF)
1089  fputs(MMDF_SEP, msg->fp);
1090 
1091  if (((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) && (flags & MUTT_ADD_FROM))
1092  {
1093  if (e)
1094  {
1095  p = TAILQ_FIRST(&e->env->return_path);
1096  if (!p)
1097  p = TAILQ_FIRST(&e->env->sender);
1098  if (!p)
1099  p = TAILQ_FIRST(&e->env->from);
1100  }
1101 
1102  // Force a 'C' locale for the date, so that day/month names are in English
1103  char buf[64] = { 0 };
1104  struct tm tm = mutt_date_localtime(msg->received);
1105 #ifdef LC_TIME_MASK
1106  locale_t loc = newlocale(LC_TIME_MASK, "C", 0);
1107  strftime_l(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", &tm, loc);
1108  freelocale(loc);
1109 #else /* !LC_TIME_MASK */
1110  strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", &tm);
1111 #endif /* LC_TIME_MASK */
1112  fprintf(msg->fp, "From %s %s\n", p ? p->mailbox : NONULL(Username), buf);
1113  }
1114  }
1115  else
1116  FREE(&msg);
1117 
1118  return msg;
1119 }
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:654
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
#define MMDF_SEP
Definition: lib.h:60
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:40
char * Username
User's login name.
Definition: mutt_globals.h:52
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:43
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:44
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
char * mailbox
Mailbox and host address.
Definition: address.h:38
struct Envelope * env
Envelope information.
Definition: email.h:66
bool replied
Email has been replied to.
Definition: email.h:49
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:59
struct AddressList return_path
Return path for the Email.
Definition: envelope.h:58
struct AddressList sender
Email's sender.
Definition: envelope.h:63
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
bool draft
Message has been read.
Definition: mxapi.h:53
bool replied
Message has been replied to.
Definition: mxapi.h:52
time_t received
Time at which this message was received.
Definition: mxapi.h:55
bool write
nonzero if message is open for writing
Definition: mxapi.h:47
bool flagged
Message is flagged.
Definition: mxapi.h:51
bool read
Message has been read.
Definition: mxapi.h:50
struct Message::@0 flags
Flags for the Message.
bool(* msg_open_new)(struct Mailbox *m, struct Message *msg, const struct Email *e)
Definition: mxapi.h:263
+ Here is the caller graph for this function:

◆ mx_mbox_check()

enum MxStatus mx_mbox_check ( struct Mailbox m)

Check for new mail - Wrapper for MxOps::mbox_check()

Parameters
mMailbox
Return values
enumMxStatus

Definition at line 1057 of file mx.c.

1127 {
1128  if (!m || !m->mx_ops)
1129  return MX_STATUS_ERROR;
1130 
1131  enum MxStatus rc = m->mx_ops->mbox_check(m);
1132  if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1133  {
1135  }
1136 
1137  return rc;
1138 }
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:177
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:89
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:87
enum MxStatus(* mbox_check)(struct Mailbox *m)
Definition: mxapi.h:188
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_msg_open()

struct Message* mx_msg_open ( struct Mailbox m,
int  msgno 
)

Return a stream pointer for a message.

Parameters
mMailbox
msgnoMessage number
Return values
ptrMessage
NULLError

Definition at line 1147 of file mx.c.

1148 {
1149  if (!m || !m->emails || (msgno < 0) || (msgno >= m->msg_count))
1150  return NULL;
1151 
1152  if (!m->mx_ops || !m->mx_ops->msg_open)
1153  {
1154  mutt_debug(LL_DEBUG1, "function not implemented for mailbox type %d\n", m->type);
1155  return NULL;
1156  }
1157 
1158  struct Message *msg = mutt_mem_calloc(1, sizeof(struct Message));
1159  if (!m->mx_ops->msg_open(m, msg, msgno))
1160  FREE(&msg);
1161 
1162  return msg;
1163 }
bool(* msg_open)(struct Mailbox *m, struct Message *msg, int msgno)
Definition: mxapi.h:246
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_msg_commit()

int mx_msg_commit ( struct Mailbox m,
struct Message msg 
)

Commit a message to a folder - Wrapper for MxOps::msg_commit()

Parameters
mMailbox
msgMessage to commit
Return values
0Success
-1Failure

Definition at line 1172 of file mx.c.

1173 {
1174  if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1175  return -1;
1176 
1177  if (!(msg->write && m->append))
1178  {
1179  mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1180  return -1;
1181  }
1182 
1183  return m->mx_ops->msg_commit(m, msg);
1184 }
int(* msg_commit)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:279
+ Here is the caller graph for this function:

◆ mx_msg_close()

int mx_msg_close ( struct Mailbox m,
struct Message **  msg 
)

Close a message.

Parameters
[in]mMailbox
[out]msgMessage to close
Return values
0Success
-1Failure

Definition at line 1193 of file mx.c.

1194 {
1195  if (!m || !msg || !*msg)
1196  return 0;
1197 
1198  int rc = 0;
1199 
1200  if (m->mx_ops && m->mx_ops->msg_close)
1201  rc = m->mx_ops->msg_close(m, *msg);
1202 
1203  if ((*msg)->path)
1204  {
1205  mutt_debug(LL_DEBUG1, "unlinking %s\n", (*msg)->path);
1206  unlink((*msg)->path);
1207  FREE(&(*msg)->path);
1208  }
1209 
1210  FREE(&(*msg)->committed_path);
1211  FREE(msg);
1212  return rc;
1213 }
int(* msg_close)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:295
+ Here is the caller graph for this function:

◆ mx_alloc_memory()

void mx_alloc_memory ( struct Mailbox m)

Create storage for the emails.

Parameters
mMailbox

Definition at line 1219 of file mx.c.

1220 {
1221  const int grow = 25;
1222  size_t s = MAX(sizeof(struct Email *), sizeof(int));
1223 
1224  if (((m->email_max + grow) * s) < (m->email_max * s))
1225  {
1226  mutt_error(_("Out of memory"));
1227  mutt_exit(1);
1228  }
1229 
1230  m->email_max += grow;
1231  if (m->emails)
1232  {
1233  mutt_mem_realloc(&m->emails, m->email_max * sizeof(struct Email *));
1234  mutt_mem_realloc(&m->v2r, m->email_max * sizeof(int));
1235  }
1236  else
1237  {
1238  m->emails = mutt_mem_calloc(m->email_max, sizeof(struct Email *));
1239  m->v2r = mutt_mem_calloc(m->email_max, sizeof(int));
1240  }
1241  for (int i = m->email_max - grow; i < m->email_max; i++)
1242  {
1243  if (i < m->email_max)
1244  {
1245  m->emails[i] = NULL;
1246  m->v2r[i] = -1;
1247  }
1248  }
1249 }
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:248
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define MAX(a, b)
Definition: memory.h:30
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:98
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_path_is_empty()

int mx_path_is_empty ( const char *  path)

Is the mailbox empty.

Parameters
pathMailbox to check
Return values
1Mailbox is empty
0Mailbox contains mail
-1Error

Definition at line 1258 of file mx.c.

1259 {
1260  if (!path || (*path == '\0'))
1261  return -1;
1262 
1263  enum MailboxType type = mx_path_probe(path);
1264  const struct MxOps *ops = mx_get_ops(type);
1265  if (!ops || !ops->path_is_empty)
1266  return -1;
1267 
1268  return ops->path_is_empty(path);
1269 }
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
int(* path_is_empty)(const char *path)
Definition: mxapi.h:435
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mxapi.h:113
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_tags_edit()

int mx_tags_edit ( struct Mailbox m,
const char *  tags,
struct Buffer buf 
)

Start the tag editor of the mailbox.

Parameters
mMailbox
tagsExisting tags
bufBuffer for the results
Return values
-1Error
0No valid user input
1Buffer set

Definition at line 1280 of file mx.c.

1281 {
1282  if (!m || !buf)
1283  return -1;
1284 
1285  if (m->mx_ops->tags_edit)
1286  return m->mx_ops->tags_edit(m, tags, buf);
1287 
1288  mutt_message(_("Folder doesn't support tagging, aborting"));
1289  return -1;
1290 }
int(* tags_edit)(struct Mailbox *m, const char *tags, struct Buffer *buf)
Definition: mxapi.h:342
+ Here is the caller graph for this function:

◆ mx_tags_commit()

int mx_tags_commit ( struct Mailbox m,
struct Email e,
const char *  tags 
)

Save tags to the Mailbox - Wrapper for MxOps::tags_commit()

Parameters
mMailbox
eEmail
tagsTags to save
Return values
0Success
-1Failure

Definition at line 1300 of file mx.c.

1301 {
1302  if (!m || !e || !tags)
1303  return -1;
1304 
1305  if (m->mx_ops->tags_commit)
1306  return m->mx_ops->tags_commit(m, e, tags);
1307 
1308  mutt_message(_("Folder doesn't support tagging, aborting"));
1309  return -1;
1310 }
int(* tags_commit)(struct Mailbox *m, struct Email *e, const char *buf)
Definition: mxapi.h:360
+ Here is the caller graph for this function:

◆ mx_tags_is_supported()

bool mx_tags_is_supported ( struct Mailbox m)

Return true if mailbox support tagging.

Parameters
mMailbox
Return values
trueTagging is supported

Definition at line 1317 of file mx.c.

1318 {
1319  return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1320 }
+ Here is the caller graph for this function:

◆ mx_path_probe()

enum MailboxType mx_path_probe ( const char *  path)

Find a mailbox that understands a path.

Parameters
pathPath to examine
Return values
numType, e.g. MUTT_IMAP

Definition at line 1317 of file mx.c.

1328 {
1329  if (!path)
1330  return MUTT_UNKNOWN;
1331 
1332  enum MailboxType rc = MUTT_UNKNOWN;
1333 
1334  // First, search the non-local Mailbox types (is_local == false)
1335  for (const struct MxOps **ops = MxOps; *ops; ops++)
1336  {
1337  if ((*ops)->is_local)
1338  continue;
1339  rc = (*ops)->path_probe(path, NULL);
1340  if (rc != MUTT_UNKNOWN)
1341  return rc;
1342  }
1343 
1344  struct stat st = { 0 };
1345  if (stat(path, &st) != 0)
1346  {
1347  mutt_debug(LL_DEBUG1, "unable to stat %s: %s (errno %d)\n", path, strerror(errno), errno);
1348  return MUTT_UNKNOWN;
1349  }
1350 
1351  if (S_ISFIFO(st.st_mode))
1352  {
1353  mutt_error(_("Can't open %s: it is a pipe"), path);
1354  return MUTT_UNKNOWN;
1355  }
1356 
1357  // Next, search the local Mailbox types (is_local == true)
1358  for (const struct MxOps **ops = MxOps; *ops; ops++)
1359  {
1360  if (!(*ops)->is_local)
1361  continue;
1362  rc = (*ops)->path_probe(path, &st);
1363  if (rc != MUTT_UNKNOWN)
1364  return rc;
1365  }
1366 
1367  return rc;
1368 }
+ Here is the caller graph for this function:

◆ mx_path_canon()

int mx_path_canon ( char *  buf,
size_t  buflen,
const char *  folder,
enum MailboxType type 
)

Canonicalise a mailbox path - Wrapper for MxOps::path_canon()

Definition at line 1373 of file mx.c.

1374 {
1375  if (!buf)
1376  return -1;
1377 
1378  for (size_t i = 0; i < 3; i++)
1379  {
1380  /* Look for !! ! - < > or ^ followed by / or NUL */
1381  if ((buf[0] == '!') && (buf[1] == '!'))
1382  {
1383  if (((buf[2] == '/') || (buf[2] == '\0')))
1384  {
1385  mutt_str_inline_replace(buf, buflen, 2, LastFolder);
1386  }
1387  }
1388  else if ((buf[0] == '+') || (buf[0] == '='))
1389  {
1390  size_t folder_len = mutt_str_len(folder);
1391  if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1392  {
1393  buf[0] = '/';
1394  mutt_str_inline_replace(buf, buflen, 0, folder);
1395  }
1396  else
1397  {
1398  mutt_str_inline_replace(buf, buflen, 1, folder);
1399  }
1400  }
1401  else if ((buf[1] == '/') || (buf[1] == '\0'))
1402  {
1403  if (buf[0] == '!')
1404  {
1405  const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1406  mutt_str_inline_replace(buf, buflen, 1, c_spool_file);
1407  }
1408  else if (buf[0] == '-')
1409  {
1410  mutt_str_inline_replace(buf, buflen, 1, LastFolder);
1411  }
1412  else if (buf[0] == '<')
1413  {
1414  const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
1415  mutt_str_inline_replace(buf, buflen, 1, c_record);
1416  }
1417  else if (buf[0] == '>')
1418  {
1419  const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
1420  mutt_str_inline_replace(buf, buflen, 1, c_mbox);
1421  }
1422  else if (buf[0] == '^')
1423  {
1424  mutt_str_inline_replace(buf, buflen, 1, CurrentFolder);
1425  }
1426  else if (buf[0] == '~')
1427  {
1428  mutt_str_inline_replace(buf, buflen, 1, HomeDir);
1429  }
1430  }
1431  else if (buf[0] == '@')
1432  {
1433  /* elm compatibility, @ expands alias to user name */
1434  struct AddressList *al = alias_lookup(buf + 1);
1435  if (!al || TAILQ_EMPTY(al))
1436  break;
1437 
1438  struct Email *e = email_new();
1439  e->env = mutt_env_new();
1440  mutt_addrlist_copy(&e->env->from, al, false);
1441  mutt_addrlist_copy(&e->env->to, al, false);
1442  mutt_default_save(buf, buflen, e);
1443  email_free(&e);
1444  break;
1445  }
1446  else
1447  {
1448  break;
1449  }
1450  }
1451 
1452  // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1453  // return -1;
1454 
1455  enum MailboxType type2 = mx_path_probe(buf);
1456  if (type)
1457  *type = type2;
1458  const struct MxOps *ops = mx_get_ops(type2);
1459  if (!ops || !ops->path_canon)
1460  return -1;
1461 
1462  if (ops->path_canon(buf, buflen) < 0)
1463  {
1464  mutt_path_canon(buf, buflen, HomeDir, true);
1465  }
1466 
1467  return 0;
1468 }
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:279
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:43
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:710
bool mutt_path_canon(char *buf, size_t buflen, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition: path.c:285
bool mutt_str_inline_replace(char *buf, size_t buflen, size_t xlen, const char *rstr)
Replace the beginning of a string.
Definition: string.c:926
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
#define TAILQ_EMPTY(head)
Definition: queue.h:721
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
int(* path_canon)(char *buf, size_t buflen)
Definition: mxapi.h:389
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_path_canon2()

int mx_path_canon2 ( struct Mailbox m,
const char *  folder 
)

Canonicalise the path to realpath.

Parameters
mMailbox
folderPath to canonicalise
Return values
0Success
-1Failure

Definition at line 1477 of file mx.c.

1478 {
1479  if (!m)
1480  return -1;
1481 
1482  char buf[PATH_MAX];
1483 
1484  if (m->realpath)
1485  mutt_str_copy(buf, m->realpath, sizeof(buf));
1486  else
1487  mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
1488 
1489  int rc = mx_path_canon(buf, sizeof(buf), folder, &m->type);
1490 
1491  mutt_str_replace(&m->realpath, buf);
1492 
1493  if (rc >= 0)
1494  {
1495  m->mx_ops = mx_get_ops(m->type);
1497  }
1498 
1499  return rc;
1500 }
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
#define PATH_MAX
Definition: mutt.h:40
int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition: mx.c:1373
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_path_pretty()

int mx_path_pretty ( char *  buf,
size_t  buflen,
const char *  folder 
)

Abbreviate a mailbox path - Wrapper for MxOps::path_pretty()

Definition at line 1505 of file mx.c.

1506 {
1507  if (!buf)
1508  return -1;
1509 
1510  enum MailboxType type = mx_path_probe(buf);
1511  const struct MxOps *ops = mx_get_ops(type);
1512  if (!ops)
1513  return -1;
1514 
1515  if (!ops->path_canon)
1516  return -1;
1517 
1518  if (ops->path_canon(buf, buflen) < 0)
1519  return -1;
1520 
1521  if (!ops->path_pretty)
1522  return -1;
1523 
1524  if (ops->path_pretty(buf, buflen, folder) < 0)
1525  return -1;
1526 
1527  return 0;
1528 }
int(* path_pretty)(char *buf, size_t buflen, const char *folder)
Definition: mxapi.h:405
+ Here is the call graph for this function:

◆ mx_path_parent()

int mx_path_parent ( char *  buf,
size_t  buflen 
)

Find the parent of a mailbox path - Wrapper for MxOps::path_parent()

Definition at line 1533 of file mx.c.

1534 {
1535  if (!buf)
1536  return -1;
1537 
1538  return 0;
1539 }

◆ mx_msg_padding_size()

int mx_msg_padding_size ( struct Mailbox m)

Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()

Parameters
mMailbox
Return values
numNumber of bytes of padding

mmdf and mbox add separators, which leads a small discrepancy when computing vsize for a limited view.

Definition at line 1549 of file mx.c.

1550 {
1551  if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1552  return 0;
1553 
1554  return m->mx_ops->msg_padding_size(m);
1555 }
int(* msg_padding_size)(struct Mailbox *m)
Definition: mxapi.h:308
+ Here is the caller graph for this function:

◆ mx_ac_find()

struct Account* mx_ac_find ( struct Mailbox m)

Find the Account owning a Mailbox.

Parameters
mMailbox
Return values
ptrAccount
NULLNone found

Definition at line 1563 of file mx.c.

1564 {
1565  if (!m || !m->mx_ops || !m->realpath)
1566  return NULL;
1567 
1568  struct Account *np = NULL;
1569  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1570  {
1571  if (np->type != m->type)
1572  continue;
1573 
1574  if (m->mx_ops->ac_owns_path(np, m->realpath))
1575  return np;
1576  }
1577 
1578  return NULL;
1579 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
bool(* ac_owns_path)(struct Account *a, const char *path)
Definition: mxapi.h:131
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
+ Here is the caller graph for this function:

◆ mx_mbox_find()

struct Mailbox* mx_mbox_find ( struct Account a,
const char *  path 
)

Find a Mailbox on an Account.

Parameters
aAccount to search
pathPath to find
Return values
ptrMailbox

Definition at line 1587 of file mx.c.

1588 {
1589  if (!a || !path)
1590  return NULL;
1591 
1592  struct MailboxNode *np = NULL;
1593  struct Url *url_p = NULL;
1594  struct Url *url_a = NULL;
1595 
1596  const bool use_url = (a->type == MUTT_IMAP);
1597  if (use_url)
1598  {
1599  url_p = url_parse(path);
1600  if (!url_p)
1601  goto done;
1602  }
1603 
1604  STAILQ_FOREACH(np, &a->mailboxes, entries)
1605  {
1606  if (!use_url)
1607  {
1608  if (mutt_str_equal(np->mailbox->realpath, path))
1609  return np->mailbox;
1610  continue;
1611  }
1612 
1613  url_free(&url_a);
1614  url_a = url_parse(np->mailbox->realpath);
1615  if (!url_a)
1616  continue;
1617 
1618  if (!mutt_istr_equal(url_a->host, url_p->host))
1619  continue;
1620  if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1621  continue;
1622  if (a->type == MUTT_IMAP)
1623  {
1624  if (imap_mxcmp(url_a->path, url_p->path) == 0)
1625  break;
1626  }
1627  else
1628  {
1629  if (mutt_str_equal(url_a->path, url_p->path))
1630  break;
1631  }
1632  }
1633 
1634 done:
1635  url_free(&url_p);
1636  url_free(&url_a);
1637 
1638  if (!np)
1639  return NULL;
1640  return np->mailbox;
1641 }
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:553
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
struct MailboxList mailboxes
List of Mailboxes.
Definition: account.h:41
List of Mailboxes.
Definition: mailbox.h:154
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:155
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_find2()

struct Mailbox* mx_mbox_find2 ( const char *  path)

Find a Mailbox on an Account.

Parameters
pathPath to find
Return values
ptrMailbox
NULLNo match

Definition at line 1649 of file mx.c.

1650 {
1651  if (!path)
1652  return NULL;
1653 
1654  char buf[PATH_MAX];
1655  mutt_str_copy(buf, path, sizeof(buf));
1656  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1657  mx_path_canon(buf, sizeof(buf), c_folder, NULL);
1658 
1659  struct Account *np = NULL;
1660  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1661  {
1662  struct Mailbox *m = mx_mbox_find(np, buf);
1663  if (m)
1664  return m;
1665  }
1666 
1667  return NULL;
1668 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_path_resolve()

struct Mailbox* mx_path_resolve ( const char *  path)

Get a Mailbox for a path.

Parameters
pathMailbox path
Return values
ptrMailbox

If there isn't a Mailbox for the path, one will be created.

Definition at line 1677 of file mx.c.

1678 {
1679  if (!path)
1680  return NULL;
1681 
1682  struct Mailbox *m = mx_mbox_find2(path);
1683  if (m)
1684  return m;
1685 
1686  m = mailbox_new();
1687  mutt_buffer_strcpy(&m->pathbuf, path);
1688  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1689  mx_path_canon2(m, c_folder);
1690 
1691  return m;
1692 }
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition: mailbox.c:68
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1649
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1477
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_find_by_name_ac()

static struct Mailbox* mx_mbox_find_by_name_ac ( struct Account a,
const char *  name 
)
static

Find a Mailbox with given name under an Account.

Parameters
aAccount to search
nameName to find
Return values
ptrMailbox

Definition at line 1700 of file mx.c.

1701 {
1702  if (!a || !name)
1703  return NULL;
1704 
1705  struct MailboxNode *np = NULL;
1706 
1707  STAILQ_FOREACH(np, &a->mailboxes, entries)
1708  {
1709  if (mutt_str_equal(np->mailbox->name, name))
1710  return np->mailbox;
1711  }
1712 
1713  return NULL;
1714 }
char * name
A short name for the Mailbox.
Definition: mailbox.h:82
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_find_by_name()

static struct Mailbox* mx_mbox_find_by_name ( const char *  name)
static

Find a Mailbox with given name.

Parameters
nameName to search
Return values
ptrMailbox

Definition at line 1721 of file mx.c.

1722 {
1723  if (!name)
1724  return NULL;
1725 
1726  struct Account *np = NULL;
1727  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1728  {
1729  struct Mailbox *m = mx_mbox_find_by_name_ac(np, name);
1730  if (m)
1731  return m;
1732  }
1733 
1734  return NULL;
1735 }
static struct Mailbox * mx_mbox_find_by_name_ac(struct Account *a, const char *name)
Find a Mailbox with given name under an Account.
Definition: mx.c:1700
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_resolve()

struct Mailbox* mx_resolve ( const char *  path_or_name)

Get a Mailbox from either a path or name.

Parameters
path_or_nameMailbox path or name
Return values
ptrMailbox

Order of resolving:

  1. Name
  2. Path

Definition at line 1746 of file mx.c.

1747 {
1748  if (!path_or_name)
1749  return NULL;
1750 
1751  // Order is name first because you can create a Mailbox from
1752  // a path, but can't from a name. So fallback behavior creates
1753  // a new Mailbox for us.
1754  struct Mailbox *m = mx_mbox_find_by_name(path_or_name);
1755  if (!m)
1756  m = mx_path_resolve(path_or_name);
1757 
1758  return m;
1759 }
static struct Mailbox * mx_mbox_find_by_name(const char *name)
Find a Mailbox with given name.
Definition: mx.c:1721
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_ac_add()

bool mx_ac_add ( struct Account a,
struct Mailbox m 
)

Add a Mailbox to an Account - Wrapper for MxOps::ac_add()

Definition at line 1764 of file mx.c.

1765 {
1766  if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1767  return false;
1768 
1769  return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1770 }
bool account_mailbox_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition: account.c:66
bool(* ac_add)(struct Account *a, struct Mailbox *m)
Definition: mxapi.h:147
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_ac_remove()

int mx_ac_remove ( struct Mailbox m,
bool  keep_account 
)

Remove a Mailbox from an Account and delete Account if empty.

Parameters
mMailbox to remove
keep_accountMake sure not to remove the mailbox's account
Return values
0Success
-1Error
Note
The mailbox is NOT free'd

Definition at line 1781 of file mx.c.

1782 {
1783  if (!m || !m->account)
1784  return -1;
1785 
1786  struct Account *a = m->account;
1788  if (!keep_account && STAILQ_EMPTY(&a->mailboxes))
1789  {
1791  }
1792  return 0;
1793 }
bool neomutt_account_remove(struct NeoMutt *n, struct Account *a)
Remove an Account from the global list.
Definition: neomutt.c:106
#define STAILQ_EMPTY(head)
Definition: queue.h:348
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_check_stats()

enum MxStatus mx_mbox_check_stats ( struct Mailbox m,
uint8_t  flags 
)

Check the statistics for a mailbox - Wrapper for MxOps::mbox_check_stats()

Note
Emits: NT_MAILBOX_CHANGE

Definition at line 1781 of file mx.c.

1801 {
1802  if (!m)
1803  return MX_STATUS_ERROR;
1804 
1805  enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1806  if (rc != MX_STATUS_ERROR)
1807  {
1808  struct EventMailbox ev_m = { m };
1810  }
1811 
1812  return rc;
1813 }
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:173
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:49
An Event that happened to a Mailbox.
Definition: mailbox.h:187
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition: mailbox.h:145
enum MxStatus(* mbox_check_stats)(struct Mailbox *m, CheckStatsFlags flags)
Definition: mxapi.h:202
+ Here is the caller graph for this function:

◆ mx_save_hcache()

int mx_save_hcache ( struct Mailbox m,
struct Email e 
)

Save message to the header cache - Wrapper for MxOps::msg_save_hcache()

Parameters
mMailbox
eEmail
Return values
0Success
-1Failure

Write a single header out to the header cache.

Definition at line 1824 of file mx.c.

1825 {
1826  if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1827  return 0;
1828 
1829  return m->mx_ops->msg_save_hcache(m, e);
1830 }
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Definition: mxapi.h:324
+ Here is the caller graph for this function:

◆ mx_type()

enum MailboxType mx_type ( struct Mailbox m)

Return the type of the Mailbox.

Parameters
mMailbox
Return values
enumMailboxType

Definition at line 1824 of file mx.c.

1838 {
1839  return m ? m->type : MUTT_MAILBOX_ERROR;
1840 }
+ Here is the caller graph for this function:

◆ mx_toggle_write()

int mx_toggle_write ( struct Mailbox m)

Toggle the mailbox's readonly flag.

Parameters
mMailbox
Return values
0Success
-1Error

Definition at line 1848 of file mx.c.

1849 {
1850  if (!m)
1851  return -1;
1852 
1853  if (m->readonly)
1854  {
1855  mutt_error(_("Can't toggle write on a readonly mailbox"));
1856  return -1;
1857  }
1858 
1859  if (m->dontwrite)
1860  {
1861  m->dontwrite = false;
1862  mutt_message(_("Changes to folder will be written on folder exit"));
1863  }
1864  else
1865  {
1866  m->dontwrite = true;
1867  mutt_message(_("Changes to folder will not be written"));
1868  }
1869 
1870  struct EventMailbox ev_m = { m };
1872  return 0;
1873 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ MboxTypeMap

const struct Mapping MboxTypeMap[]
static
Initial value:
= {
{ "mbox", MUTT_MBOX, },
{ "MMDF", MUTT_MMDF, },
{ "MH", MUTT_MH, },
{ "Maildir", MUTT_MAILDIR, },
{ NULL, 0, },
}

Definition at line 1 of file mx.c.

◆ MboxTypeDef

struct EnumDef MboxTypeDef
Initial value:
= {
"mbox_type",
4,
(struct Mapping *) &MboxTypeMap,
}
static const struct Mapping MboxTypeMap[]
Definition: mx.c:88
Mapping between user-readable string and a constant.
Definition: mapping.h:32

Definition at line 1 of file mx.c.

◆ MxOps

const struct MxOps* MxOps[]
Initial value:
= {
NULL,
}
struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps -.
Definition: maildir.c:1645
struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1254
struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition: compress.c:937
struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition: mbox.c:1872
struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps -.
Definition: nntp.c:2738
struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition: imap.c:2486
struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition: mbox.c:1840
struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition: notmuch.c:2469
struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1197

All the Mailbox backends.

Definition at line 107 of file mx.c.