NeoMutt  2021-10-22-8-g9cb437
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)
 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, char *buf, size_t buflen)
 Start the tag editor of the mailbox. More...
 
int mx_tags_commit (struct Mailbox *m, struct Email *e, 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)
 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:104
+ 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 =
165  ua && ub && (ua->scheme == ub->scheme) &&
166  mutt_istr_equal(ua->host, ub->host) && 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:916
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
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:2402
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:474
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:53
+ 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:359
#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:215
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition: mailbox.h:46
@ MUTT_COMPRESSED
Compressed file Mailbox type.
Definition: mailbox.h:56
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:47
#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:1320
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND,.
Definition: mxapi.h:65
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:62
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition: mxapi.h:69
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:113
const struct MxOps * mx_ops
MXAPI callback functions.
Definition: mailbox.h:111
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
int opened
Number of times mailbox is opened.
Definition: mailbox.h:132
bool(* mbox_open_append)(struct Mailbox *m, OpenMailboxFlags flags)
Definition: mxapi.h:167
+ 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:139
bool mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1759
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1557
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:131
+ 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:
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:76
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition: mutt_header.c:367
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:267
void mx_fastclose_mailbox(struct Mailbox *m)
Free up memory associated with the Mailbox.
Definition: mx.c:429
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:63
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:64
MxOpenReturns
Return values for mbox_open()
Definition: mxapi.h:89
@ MX_OPEN_ABORT
Open was aborted.
Definition: mxapi.h:92
@ MX_OPEN_OK
Open succeeded.
Definition: mxapi.h:90
#define MUTT_PEEK
Revert atime back after taking a look (if applicable)
Definition: mxapi.h:68
#define MUTT_NOSORT
Do not sort the mailbox after opening it.
Definition: mxapi.h:61
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:102
bool has_new
Mailbox has new mail.
Definition: mailbox.h:88
int msg_new
Number of new messages.
Definition: mailbox.h:95
int msg_count
Total number of messages.
Definition: mailbox.h:91
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
bool peekonly
Just taking a glance, revert atime.
Definition: mailbox.h:117
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:96
off_t size
Size of the Mailbox.
Definition: mailbox.h:87
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:93
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:119
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:97
bool verbose
Display status messages?
Definition: mailbox.h:118
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
enum MxOpenReturns(* mbox_open)(struct Mailbox *m)
Definition: mxapi.h:152
+ 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)

Free up memory associated with the Mailbox.

Parameters
mMailbox

Definition at line 429 of file mx.c.

430 {
431  if (!m)
432  return;
433 
434  m->opened--;
435  if (m->opened != 0)
436  return;
437 
438  /* never announce that a mailbox we've just left has new mail.
439  * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
440  if (!m->peekonly)
442 
443  if (m->mx_ops)
444  m->mx_ops->mbox_close(m);
445 
447  mutt_hash_free(&m->id_hash);
449 
450  if (m->emails)
451  {
452  for (int i = 0; i < m->msg_count; i++)
453  {
454  if (!m->emails[i])
455  break;
456  email_free(&m->emails[i]);
457  }
458  }
459 
460  if (m->flags & MB_HIDDEN)
461  {
462  mx_ac_remove(m);
463  }
464 }
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:449
#define MB_HIDDEN
Definition: mailbox.h:38
void mutt_mailbox_set_notified(struct Mailbox *m)
Note when the user was last notified of new mail.
Definition: mutt_mailbox.c:318
int mx_ac_remove(struct Mailbox *m)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1775
struct HashTable * subj_hash
Hash Table by subject.
Definition: mailbox.h:128
struct HashTable * id_hash
Hash Table by msg id.
Definition: mailbox.h:127
struct HashTable * label_hash
Hash Table for x-labels.
Definition: mailbox.h:129
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
enum MxStatus(* mbox_close)(struct Mailbox *m)
Definition: mxapi.h:220
+ 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 429 of file mx.c.

472 {
473  if (!m || !m->mx_ops || !m->mx_ops->mbox_sync)
474  return MX_STATUS_ERROR;
475 
476  if (m->verbose)
477  {
478  /* L10N: Displayed before/as a mailbox is being synced */
479  mutt_message(_("Writing %s..."), mailbox_path(m));
480  }
481 
482  enum MxStatus rc = m->mx_ops->mbox_sync(m);
483  if (rc != MX_STATUS_OK)
484  {
485  mutt_debug(LL_DEBUG2, "mbox_sync returned: %d\n", rc);
486  if ((rc == MX_STATUS_ERROR) && m->verbose)
487  {
488  /* L10N: Displayed if a mailbox sync fails */
489  mutt_error(_("Unable to write %s"), mailbox_path(m));
490  }
491  }
492 
493  return rc;
494 }
#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:76
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:77
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:78
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition: mxapi.h:207

◆ 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 502 of file mx.c.

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

614 {
615  if (!m)
616  return MX_STATUS_ERROR;
617 
618  const bool c_mail_check_recent =
619  cs_subset_bool(NeoMutt->sub, "mail_check_recent");
620  if (c_mail_check_recent && !m->peekonly)
621  m->has_new = false;
622 
623  if (m->readonly || m->dontwrite || m->append || m->peekonly)
624  {
626  return 0;
627  }
628 
629  int i, read_msgs = 0;
630  enum MxStatus rc = MX_STATUS_ERROR;
631  enum QuadOption move_messages = MUTT_NO;
632  enum QuadOption purge = MUTT_YES;
633  struct Buffer *mbox = NULL;
634  struct Buffer *buf = mutt_buffer_pool_get();
635 
636 #ifdef USE_NNTP
637  if ((m->msg_unread != 0) && (m->type == MUTT_NNTP))
638  {
639  struct NntpMboxData *mdata = m->mdata;
640 
641  if (mdata && mdata->adata && mdata->group)
642  {
643  const enum QuadOption c_catchup_newsgroup =
644  cs_subset_quad(NeoMutt->sub, "catchup_newsgroup");
645  enum QuadOption ans =
646  query_quadoption(c_catchup_newsgroup, _("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);
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 
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:1318
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:576
#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:1642
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:49
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:52
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:48
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition: mbox.c:842
@ 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:322
static enum MxStatus sync_mailbox(struct Mailbox *m)
Save changes to disk.
Definition: mx.c:471
static int trash_append(struct Mailbox *m)
Move deleted mails to the trash folder.
Definition: mx.c:502
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:1581
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1308
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:66
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:349
#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:114
void * mdata
Driver specific data.
Definition: mailbox.h:136
bool dontwrite
Don't write the mailbox on close.
Definition: mailbox.h:115
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 502 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_MAIN, 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));
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:938
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:910
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:211
@ NT_MAILBOX_UNTAG
Clear the 'last-tagged' pointer.
Definition: mailbox.h:184
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:181
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:183
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:50
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:749
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1461
@ MENU_MAIN
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  locale_t loc = newlocale(LC_TIME_MASK, "C", 0);
1104  char buf[64] = { 0 };
1105  struct tm tm = mutt_date_localtime(msg->received);
1106  strftime_l(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", &tm, loc);
1107  freelocale(loc);
1108  fprintf(msg->fp, "From %s %s\n", p ? p->mailbox : NONULL(Username), buf);
1109  }
1110  }
1111  else
1112  FREE(&msg);
1113 
1114  return msg;
1115 }
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:54
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:42
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:43
#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:56
struct AddressList sender
Email's sender.
Definition: envelope.h:61
struct AddressList from
Email's 'From' list.
Definition: envelope.h:57
A local copy of an email.
Definition: mxapi.h:42
FILE * fp
pointer to the message data
Definition: mxapi.h:43
bool draft
Message has been read.
Definition: mxapi.h:52
bool replied
Message has been replied to.
Definition: mxapi.h:51
time_t received
Time at which this message was received.
Definition: mxapi.h:54
bool write
nonzero if message is open for writing
Definition: mxapi.h:46
bool flagged
Message is flagged.
Definition: mxapi.h:50
bool read
Message has been read.
Definition: mxapi.h:49
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:255
+ 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.

1123 {
1124  if (!m || !m->mx_ops)
1125  return MX_STATUS_ERROR;
1126 
1127  enum MxStatus rc = m->mx_ops->mbox_check(m);
1128  if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1129  {
1131  }
1132 
1133  return rc;
1134 }
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:180
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:81
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:79
enum MxStatus(* mbox_check)(struct Mailbox *m)
Definition: mxapi.h:180
+ 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 1143 of file mx.c.

1144 {
1145  if (!m || !m->emails || (msgno < 0) || (msgno >= m->msg_count))
1146  return NULL;
1147 
1148  if (!m->mx_ops || !m->mx_ops->msg_open)
1149  {
1150  mutt_debug(LL_DEBUG1, "function not implemented for mailbox type %d\n", m->type);
1151  return NULL;
1152  }
1153 
1154  struct Message *msg = mutt_mem_calloc(1, sizeof(struct Message));
1155  if (!m->mx_ops->msg_open(m, msg, msgno))
1156  FREE(&msg);
1157 
1158  return msg;
1159 }
bool(* msg_open)(struct Mailbox *m, struct Message *msg, int msgno)
Definition: mxapi.h:238
+ 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 1168 of file mx.c.

1169 {
1170  if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1171  return -1;
1172 
1173  if (!(msg->write && m->append))
1174  {
1175  mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1176  return -1;
1177  }
1178 
1179  return m->mx_ops->msg_commit(m, msg);
1180 }
int(* msg_commit)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:271
+ 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 1189 of file mx.c.

1190 {
1191  if (!m || !msg || !*msg)
1192  return 0;
1193 
1194  int rc = 0;
1195 
1196  if (m->mx_ops && m->mx_ops->msg_close)
1197  rc = m->mx_ops->msg_close(m, *msg);
1198 
1199  if ((*msg)->path)
1200  {
1201  mutt_debug(LL_DEBUG1, "unlinking %s\n", (*msg)->path);
1202  unlink((*msg)->path);
1203  FREE(&(*msg)->path);
1204  }
1205 
1206  FREE(&(*msg)->committed_path);
1207  FREE(msg);
1208  return rc;
1209 }
int(* msg_close)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:287
+ 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 1215 of file mx.c.

1216 {
1217  size_t s = MAX(sizeof(struct Email *), sizeof(int));
1218 
1219  if ((m->email_max + 25) * s < m->email_max * s)
1220  {
1221  mutt_error(_("Out of memory"));
1222  mutt_exit(1);
1223  }
1224 
1225  m->email_max += 25;
1226  if (m->emails)
1227  {
1228  mutt_mem_realloc(&m->emails, sizeof(struct Email *) * m->email_max);
1229  mutt_mem_realloc(&m->v2r, sizeof(int) * m->email_max);
1230  }
1231  else
1232  {
1233  m->emails = mutt_mem_calloc(m->email_max, sizeof(struct Email *));
1234  m->v2r = mutt_mem_calloc(m->email_max, sizeof(int));
1235  }
1236  for (int i = m->email_max - 25; i < m->email_max; i++)
1237  {
1238  m->emails[i] = NULL;
1239  m->v2r[i] = -1;
1240  }
1241 }
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:253
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:101
+ 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 1250 of file mx.c.

1251 {
1252  if (!path || (*path == '\0'))
1253  return -1;
1254 
1255  enum MailboxType type = mx_path_probe(path);
1256  const struct MxOps *ops = mx_get_ops(type);
1257  if (!ops || !ops->path_is_empty)
1258  return -1;
1259 
1260  return ops->path_is_empty(path);
1261 }
MailboxType
Supported mailbox formats.
Definition: mailbox.h:44
int(* path_is_empty)(const char *path)
Definition: mxapi.h:428
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mxapi.h:105
+ 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,
char *  buf,
size_t  buflen 
)

Start the tag editor of the mailbox.

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

Definition at line 1273 of file mx.c.

1274 {
1275  if (!m || !buf)
1276  return -1;
1277 
1278  if (m->mx_ops->tags_edit)
1279  return m->mx_ops->tags_edit(m, tags, buf, buflen);
1280 
1281  mutt_message(_("Folder doesn't support tagging, aborting"));
1282  return -1;
1283 }
int(* tags_edit)(struct Mailbox *m, const char *tags, char *buf, size_t buflen)
Definition: mxapi.h:335
+ Here is the caller graph for this function:

◆ mx_tags_commit()

int mx_tags_commit ( struct Mailbox m,
struct Email e,
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 1293 of file mx.c.

1294 {
1295  if (!m || !e || !tags)
1296  return -1;
1297 
1298  if (m->mx_ops->tags_commit)
1299  return m->mx_ops->tags_commit(m, e, tags);
1300 
1301  mutt_message(_("Folder doesn't support tagging, aborting"));
1302  return -1;
1303 }
int(* tags_commit)(struct Mailbox *m, struct Email *e, char *buf)
Definition: mxapi.h:353
+ 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 1310 of file mx.c.

1311 {
1312  return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1313 }
+ 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 1310 of file mx.c.

1321 {
1322  if (!path)
1323  return MUTT_UNKNOWN;
1324 
1325  enum MailboxType rc = MUTT_UNKNOWN;
1326 
1327  // First, search the non-local Mailbox types (is_local == false)
1328  for (const struct MxOps **ops = MxOps; *ops; ops++)
1329  {
1330  if ((*ops)->is_local)
1331  continue;
1332  rc = (*ops)->path_probe(path, NULL);
1333  if (rc != MUTT_UNKNOWN)
1334  return rc;
1335  }
1336 
1337  struct stat st = { 0 };
1338  if (stat(path, &st) != 0)
1339  {
1340  mutt_debug(LL_DEBUG1, "unable to stat %s: %s (errno %d)\n", path, strerror(errno), errno);
1341  return MUTT_UNKNOWN;
1342  }
1343 
1344  if (S_ISFIFO(st.st_mode))
1345  {
1346  mutt_error(_("Can't open %s: it is a pipe"), path);
1347  return MUTT_UNKNOWN;
1348  }
1349 
1350  // Next, search the local Mailbox types (is_local == true)
1351  for (const struct MxOps **ops = MxOps; *ops; ops++)
1352  {
1353  if (!(*ops)->is_local)
1354  continue;
1355  rc = (*ops)->path_probe(path, &st);
1356  if (rc != MUTT_UNKNOWN)
1357  return rc;
1358  }
1359 
1360  return rc;
1361 }
+ 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 1366 of file mx.c.

1367 {
1368  if (!buf)
1369  return -1;
1370 
1371  for (size_t i = 0; i < 3; i++)
1372  {
1373  /* Look for !! ! - < > or ^ followed by / or NUL */
1374  if ((buf[0] == '!') && (buf[1] == '!'))
1375  {
1376  if (((buf[2] == '/') || (buf[2] == '\0')))
1377  {
1378  mutt_str_inline_replace(buf, buflen, 2, LastFolder);
1379  }
1380  }
1381  else if ((buf[0] == '+') || (buf[0] == '='))
1382  {
1383  size_t folder_len = mutt_str_len(folder);
1384  if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1385  {
1386  buf[0] = '/';
1387  mutt_str_inline_replace(buf, buflen, 0, folder);
1388  }
1389  else
1390  {
1391  mutt_str_inline_replace(buf, buflen, 1, folder);
1392  }
1393  }
1394  else if ((buf[1] == '/') || (buf[1] == '\0'))
1395  {
1396  if (buf[0] == '!')
1397  {
1398  const char *const c_spool_file =
1399  cs_subset_string(NeoMutt->sub, "spool_file");
1400  mutt_str_inline_replace(buf, buflen, 1, c_spool_file);
1401  }
1402  else if (buf[0] == '-')
1403  {
1404  mutt_str_inline_replace(buf, buflen, 1, LastFolder);
1405  }
1406  else if (buf[0] == '<')
1407  {
1408  const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
1409  mutt_str_inline_replace(buf, buflen, 1, c_record);
1410  }
1411  else if (buf[0] == '>')
1412  {
1413  const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
1414  mutt_str_inline_replace(buf, buflen, 1, c_mbox);
1415  }
1416  else if (buf[0] == '^')
1417  {
1418  mutt_str_inline_replace(buf, buflen, 1, CurrentFolder);
1419  }
1420  else if (buf[0] == '~')
1421  {
1422  mutt_str_inline_replace(buf, buflen, 1, HomeDir);
1423  }
1424  }
1425  else if (buf[0] == '@')
1426  {
1427  /* elm compatibility, @ expands alias to user name */
1428  struct AddressList *al = alias_lookup(buf + 1);
1429  if (!al || TAILQ_EMPTY(al))
1430  break;
1431 
1432  struct Email *e = email_new();
1433  e->env = mutt_env_new();
1434  mutt_addrlist_copy(&e->env->from, al, false);
1435  mutt_addrlist_copy(&e->env->to, al, false);
1436  mutt_default_save(buf, buflen, e);
1437  email_free(&e);
1438  break;
1439  }
1440  else
1441  {
1442  break;
1443  }
1444  }
1445 
1446  // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1447  // return -1;
1448 
1449  enum MailboxType type2 = mx_path_probe(buf);
1450  if (type)
1451  *type = type2;
1452  const struct MxOps *ops = mx_get_ops(type2);
1453  if (!ops || !ops->path_canon)
1454  return -1;
1455 
1456  if (ops->path_canon(buf, buflen) < 0)
1457  {
1458  mutt_path_canon(buf, buflen, HomeDir, true);
1459  }
1460 
1461  return 0;
1462 }
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:282
char * HomeDir
User's home directory.
Definition: mutt_globals.h:51
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:42
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:676
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:1046
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:57
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:56
#define TAILQ_EMPTY(head)
Definition: queue.h:721
struct AddressList to
Email's 'To' list.
Definition: envelope.h:58
int(* path_canon)(char *buf, size_t buflen)
Definition: mxapi.h:382
+ 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 1471 of file mx.c.

1472 {
1473  if (!m)
1474  return -1;
1475 
1476  char buf[PATH_MAX];
1477 
1478  if (m->realpath)
1479  mutt_str_copy(buf, m->realpath, sizeof(buf));
1480  else
1481  mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
1482 
1483  int rc = mx_path_canon(buf, sizeof(buf), folder, &m->type);
1484 
1485  mutt_str_replace(&m->realpath, buf);
1486 
1487  if (rc >= 0)
1488  {
1489  m->mx_ops = mx_get_ops(m->type);
1491  }
1492 
1493  return rc;
1494 }
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
#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:1366
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:83
+ 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 1499 of file mx.c.

1500 {
1501  if (!buf)
1502  return -1;
1503 
1504  enum MailboxType type = mx_path_probe(buf);
1505  const struct MxOps *ops = mx_get_ops(type);
1506  if (!ops)
1507  return -1;
1508 
1509  if (!ops->path_canon)
1510  return -1;
1511 
1512  if (ops->path_canon(buf, buflen) < 0)
1513  return -1;
1514 
1515  if (!ops->path_pretty)
1516  return -1;
1517 
1518  if (ops->path_pretty(buf, buflen, folder) < 0)
1519  return -1;
1520 
1521  return 0;
1522 }
int(* path_pretty)(char *buf, size_t buflen, const char *folder)
Definition: mxapi.h:398
+ 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 1527 of file mx.c.

1528 {
1529  if (!buf)
1530  return -1;
1531 
1532  return 0;
1533 }

◆ 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 1543 of file mx.c.

1544 {
1545  if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1546  return 0;
1547 
1548  return m->mx_ops->msg_padding_size(m);
1549 }
int(* msg_padding_size)(struct Mailbox *m)
Definition: mxapi.h:300
+ 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 1557 of file mx.c.

1558 {
1559  if (!m || !m->mx_ops || !m->realpath)
1560  return NULL;
1561 
1562  struct Account *np = NULL;
1563  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1564  {
1565  if (np->type != m->type)
1566  continue;
1567 
1568  if (m->mx_ops->ac_owns_path(np, m->realpath))
1569  return np;
1570  }
1571 
1572  return NULL;
1573 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
bool(* ac_owns_path)(struct Account *a, const char *path)
Definition: mxapi.h:123
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 1581 of file mx.c.

1582 {
1583  if (!a || !path)
1584  return NULL;
1585 
1586  struct MailboxNode *np = NULL;
1587  struct Url *url_p = NULL;
1588  struct Url *url_a = NULL;
1589 
1590  const bool use_url = (a->type == MUTT_IMAP);
1591  if (use_url)
1592  {
1593  url_p = url_parse(path);
1594  if (!url_p)
1595  goto done;
1596  }
1597 
1598  STAILQ_FOREACH(np, &a->mailboxes, entries)
1599  {
1600  if (!use_url)
1601  {
1602  if (mutt_str_equal(np->mailbox->realpath, path))
1603  return np->mailbox;
1604  continue;
1605  }
1606 
1607  url_free(&url_a);
1608  url_a = url_parse(np->mailbox->realpath);
1609  if (!url_a)
1610  continue;
1611 
1612  if (!mutt_istr_equal(url_a->host, url_p->host))
1613  continue;
1614  if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1615  continue;
1616  if (a->type == MUTT_IMAP)
1617  {
1618  if (imap_mxcmp(url_a->path, url_p->path) == 0)
1619  break;
1620  }
1621  else
1622  {
1623  if (mutt_str_equal(url_a->path, url_p->path))
1624  break;
1625  }
1626  }
1627 
1628 done:
1629  url_free(&url_p);
1630  url_free(&url_a);
1631 
1632  if (!np)
1633  return NULL;
1634  return np->mailbox;
1635 }
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:554
#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:157
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:158
+ 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 1643 of file mx.c.

1644 {
1645  if (!path)
1646  return NULL;
1647 
1648  char buf[PATH_MAX];
1649  mutt_str_copy(buf, path, sizeof(buf));
1650  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1651  mx_path_canon(buf, sizeof(buf), c_folder, NULL);
1652 
1653  struct Account *np = NULL;
1654  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1655  {
1656  struct Mailbox *m = mx_mbox_find(np, buf);
1657  if (m)
1658  return m;
1659  }
1660 
1661  return NULL;
1662 }
+ 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 1671 of file mx.c.

1672 {
1673  if (!path)
1674  return NULL;
1675 
1676  struct Mailbox *m = mx_mbox_find2(path);
1677  if (m)
1678  return m;
1679 
1680  m = mailbox_new();
1681  m->flags = MB_HIDDEN;
1682  mutt_buffer_strcpy(&m->pathbuf, path);
1683  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1684  mx_path_canon2(m, c_folder);
1685 
1686  return m;
1687 }
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:1643
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1471
+ 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 1695 of file mx.c.

1696 {
1697  if (!a || !name)
1698  return NULL;
1699 
1700  struct MailboxNode *np = NULL;
1701 
1702  STAILQ_FOREACH(np, &a->mailboxes, entries)
1703  {
1704  if (mutt_str_equal(np->mailbox->name, name))
1705  return np->mailbox;
1706  }
1707 
1708  return NULL;
1709 }
char * name
A short name for the Mailbox.
Definition: mailbox.h:85
+ 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 1716 of file mx.c.

1717 {
1718  if (!name)
1719  return NULL;
1720 
1721  struct Account *np = NULL;
1722  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1723  {
1724  struct Mailbox *m = mx_mbox_find_by_name_ac(np, name);
1725  if (m)
1726  return m;
1727  }
1728 
1729  return NULL;
1730 }
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:1695
+ 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 1741 of file mx.c.

1742 {
1743  if (!path_or_name)
1744  return NULL;
1745 
1746  // Order is name first because you can create a Mailbox from
1747  // a path, but can't from a name. So fallback behavior creates
1748  // a new Mailbox for us.
1749  struct Mailbox *m = mx_mbox_find_by_name(path_or_name);
1750  if (!m)
1751  m = mx_path_resolve(path_or_name);
1752 
1753  return m;
1754 }
static struct Mailbox * mx_mbox_find_by_name(const char *name)
Find a Mailbox with given name.
Definition: mx.c:1716
+ 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 1759 of file mx.c.

1760 {
1761  if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1762  return false;
1763 
1764  return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1765 }
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:139
+ 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)

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

Parameters
mMailbox to remove
Return values
0Success
-1Error
Note
The mailbox is NOT free'd

Definition at line 1775 of file mx.c.

1776 {
1777  if (!m || !m->account)
1778  return -1;
1779 
1780  struct Account *a = m->account;
1782  if (STAILQ_EMPTY(&a->mailboxes))
1783  {
1785  }
1786  return 0;
1787 }
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 1775 of file mx.c.

1795 {
1796  if (!m)
1797  return MX_STATUS_ERROR;
1798 
1799  enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1800  if (rc != MX_STATUS_ERROR)
1801  {
1802  struct EventMailbox ev_m = { m };
1804  }
1805 
1806  return rc;
1807 }
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:176
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:48
An Event that happened to a Mailbox.
Definition: mailbox.h:191
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition: mailbox.h:148
enum MxStatus(* mbox_check_stats)(struct Mailbox *m, uint8_t flags)
Definition: mxapi.h:194
+ 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 1818 of file mx.c.

1819 {
1820  if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1821  return 0;
1822 
1823  return m->mx_ops->msg_save_hcache(m, e);
1824 }
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Definition: mxapi.h:316
+ 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 1818 of file mx.c.

1832 {
1833  return m ? m->type : MUTT_MAILBOX_ERROR;
1834 }
+ 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 1842 of file mx.c.

1843 {
1844  if (!m)
1845  return -1;
1846 
1847  if (m->readonly)
1848  {
1849  mutt_error(_("Can't toggle write on a readonly mailbox"));
1850  return -1;
1851  }
1852 
1853  if (m->dontwrite)
1854  {
1855  m->dontwrite = false;
1856  mutt_message(_("Changes to folder will be written on folder exit"));
1857  }
1858  else
1859  {
1860  m->dontwrite = true;
1861  mutt_message(_("Changes to folder will not be written"));
1862  }
1863 
1864  struct EventMailbox ev_m = { m };
1866  return 0;
1867 }
+ 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:1652
struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1258
struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition: compress.c:931
struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition: mbox.c:1864
struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps -.
Definition: nntp.c:2749
struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition: imap.c:2488
struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition: mbox.c:1832
struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition: notmuch.c:2485
struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1205

All the Mailbox backends.

Definition at line 107 of file mx.c.