NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mx.c File Reference

Mailbox multiplexor. More...

#include "config.h"
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "mx.h"
#include "compmbox/lib.h"
#include "hooks/lib.h"
#include "imap/lib.h"
#include "index/lib.h"
#include "key/lib.h"
#include "maildir/lib.h"
#include "mbox/lib.h"
#include "mh/lib.h"
#include "nntp/lib.h"
#include "pop/lib.h"
#include "question/lib.h"
#include "external.h"
#include "globals.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "muttlib.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.
 
static bool mutt_is_spool (const char *str)
 Is this the spool_file?
 
int mx_access (const char *path, int flags)
 Wrapper for access, checks permissions on a given mailbox.
 
static bool mx_open_mailbox_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a mailbox for appending.
 
bool mx_mbox_ac_link (struct Mailbox *m)
 Link a Mailbox to an existing or new Account.
 
bool mx_mbox_open (struct Mailbox *m, OpenMailboxFlags flags)
 Open a mailbox and parse it.
 
void mx_fastclose_mailbox (struct Mailbox *m, bool keep_account)
 Free up memory associated with the Mailbox.
 
static enum MxStatus sync_mailbox (struct Mailbox *m)
 Save changes to disk.
 
static int trash_append (struct Mailbox *m)
 Move deleted mails to the trash folder.
 
enum MxStatus mx_mbox_close (struct Mailbox *m)
 Save changes and close mailbox.
 
enum MxStatus mx_mbox_sync (struct Mailbox *m)
 Save changes to mailbox.
 
struct Messagemx_msg_open_new (struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
 Open a new message.
 
enum MxStatus mx_mbox_check (struct Mailbox *m)
 Check for new mail - Wrapper for MxOps::mbox_check()
 
struct Messagemx_msg_open (struct Mailbox *m, struct Email *e)
 Return a stream pointer for a message.
 
int mx_msg_commit (struct Mailbox *m, struct Message *msg)
 Commit a message to a folder - Wrapper for MxOps::msg_commit()
 
int mx_msg_close (struct Mailbox *m, struct Message **ptr)
 Close a message.
 
void mx_alloc_memory (struct Mailbox *m, int req_size)
 Create storage for the emails.
 
int mx_path_is_empty (struct Buffer *path)
 Is the mailbox empty.
 
int mx_tags_edit (struct Mailbox *m, const char *tags, struct Buffer *buf)
 Start the tag editor of the mailbox.
 
int mx_tags_commit (struct Mailbox *m, struct Email *e, const char *tags)
 Save tags to the Mailbox - Wrapper for MxOps::tags_commit()
 
bool mx_tags_is_supported (struct Mailbox *m)
 Return true if mailbox support tagging.
 
enum MailboxType mx_path_probe (const char *path)
 Find a mailbox that understands a path.
 
int mx_path_canon (struct Buffer *path, const char *folder, enum MailboxType *type)
 Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
 
int mx_path_canon2 (struct Mailbox *m, const char *folder)
 Canonicalise the path to realpath.
 
int mx_msg_padding_size (struct Mailbox *m)
 Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
 
struct Accountmx_ac_find (struct Mailbox *m)
 Find the Account owning a Mailbox.
 
struct Mailboxmx_mbox_find (struct Account *a, const char *path)
 Find a Mailbox on an Account.
 
struct Mailboxmx_mbox_find2 (const char *path)
 Find a Mailbox on an Account.
 
struct Mailboxmx_path_resolve (const char *path)
 Get a Mailbox for a path.
 
static struct Mailboxmx_mbox_find_by_name_ac (struct Account *a, const char *name)
 Find a Mailbox with given name under an Account.
 
static struct Mailboxmx_mbox_find_by_name (const char *name)
 Find a Mailbox with given name.
 
struct Mailboxmx_resolve (const char *path_or_name)
 Get a Mailbox from either a path or name.
 
bool mx_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
 
int mx_ac_remove (struct Mailbox *m, bool keep_account)
 Remove a Mailbox from an Account and delete Account if empty.
 
enum MxStatus mx_mbox_check_stats (struct Mailbox *m, uint8_t flags)
 Check the statistics for a mailbox - Wrapper for MxOps::mbox_check_stats()
 
int mx_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Wrapper for MxOps::msg_save_hcache()
 
enum MailboxType mx_type (struct Mailbox *m)
 Return the type of the Mailbox.
 
int mx_toggle_write (struct Mailbox *m)
 Toggle the mailbox's readonly flag.
 

Variables

static const struct Mapping MboxTypeMap []
 Lookup table of mailbox types.
 
const struct EnumDef MboxTypeDef
 Data for the $mbox_type enumeration.
 
static const struct MxOps * MxOps []
 All the Mailbox backends.
 

Detailed Description

Mailbox multiplexor.

Authors
  • Michael R. Elkins
  • Thomas Roessler
  • Richard Russon
  • Mehdi Abaakouk
  • Pietro Cerutti
  • Austin Ray
  • Reto Brunner
  • Dennis Schön

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file 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 124 of file mx.c.

125{
126 for (const struct MxOps **ops = MxOps; *ops; ops++)
127 if ((*ops)->type == type)
128 return *ops;
129
130 return NULL;
131}
Definition mxapi.h:98
+ 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 138 of file mx.c.

139{
140 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
141 if (mutt_str_equal(str, c_spool_file))
142 return true;
143
144 struct Url *ua = url_parse(str);
145 struct Url *ub = url_parse(c_spool_file);
146
147 const bool is_spool = ua && ub && (ua->scheme == ub->scheme) &&
148 mutt_istr_equal(ua->host, ub->host) &&
149 mutt_istr_equal(ua->path, ub->path) &&
150 (!ua->user || !ub->user || mutt_str_equal(ua->user, ub->user));
151
152 url_free(&ua);
153 url_free(&ub);
154 return is_spool;
155}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
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:242
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition url.c:124
+ Here is the call graph for this function:
+ Here is the caller 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 167 of file mx.c.

168{
169 if (imap_path_probe(path, NULL) == MUTT_IMAP)
170 return imap_access(path);
171
172 return access(path, flags);
173}
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2683
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition imap.c:569
+ 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 182 of file mx.c.

183{
184 if (!m)
185 return false;
186
187 struct stat st = { 0 };
188
189 m->append = true;
190 if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR))
191 {
193
194 if (m->type == MUTT_UNKNOWN)
195 {
196 if (flags & MUTT_APPEND)
197 {
199 }
200 else
201 {
202 mutt_error(_("%s is not a mailbox"), mailbox_path(m));
203 return false;
204 }
205 }
206
207 if (m->type == MUTT_MAILBOX_ERROR)
208 {
209 if (stat(mailbox_path(m), &st) == -1)
210 {
211 if (errno == ENOENT)
212 {
215 else
216 m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
217 flags |= MUTT_APPENDNEW;
218 }
219 else
220 {
221 mutt_perror("%s", mailbox_path(m));
222 return false;
223 }
224 }
225 else
226 {
227 return false;
228 }
229 }
230
231 m->mx_ops = mx_get_ops(m->type);
232 }
233
234 if (!m->mx_ops || !m->mx_ops->mbox_open_append)
235 return false;
236
237 const bool rc = m->mx_ops->mbox_open_append(m, flags);
238 m->opened++;
239 return rc;
240}
bool mutt_comp_can_append(struct Mailbox *m)
Can we append to this path?
Definition compress.c:337
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition helpers.c:71
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:216
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition mailbox.h:42
@ MUTT_COMPRESSED
Compressed file Mailbox type.
Definition mailbox.h:52
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition mailbox.h:43
#define mutt_error(...)
Definition logging2.h:94
#define mutt_perror(...)
Definition logging2.h:95
#define _(a)
Definition message.h:28
const struct MxOps * mx_get_ops(enum MailboxType type)
Get mailbox operations.
Definition mx.c:124
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition mx.c:1326
@ MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition mxapi.h:48
@ MUTT_APPEND
Open mailbox for appending messages.
Definition mxapi.h:44
bool append
Mailbox is opened in append mode.
Definition mailbox.h:111
const struct MxOps * mx_ops
MXAPI callback functions.
Definition mailbox.h:109
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
int opened
Number of times mailbox is opened.
Definition mailbox.h:130
bool(* mbox_open_append)(struct Mailbox *m, OpenMailboxFlags flags)
Definition mxapi.h:157
+ 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 248 of file mx.c.

249{
250 if (!m)
251 return false;
252
253 if (m->account)
254 return true;
255
256 struct Account *a = mx_ac_find(m);
257 const bool new_account = !a;
258 if (new_account)
259 {
260 a = account_new(NULL, NeoMutt->sub);
261 a->type = m->type;
262 }
263 if (!mx_ac_add(a, m))
264 {
265 if (new_account)
266 {
267 account_free(&a);
268 }
269 return false;
270 }
271 if (new_account)
272 {
274 }
275 return true;
276}
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition account.c:44
void account_free(struct Account **ptr)
Free an Account.
Definition account.c:148
bool mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition mx.c:1740
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition mx.c:1524
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition neomutt.c:537
A group of associated Mailboxes.
Definition account.h:36
enum MailboxType type
Type of Mailboxes this Account contains.
Definition account.h:37
struct Account * account
Account that owns this Mailbox.
Definition mailbox.h:129
+ 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 285 of file mx.c.

286{
287 if (!m)
288 return false;
289
290 if ((m->type == MUTT_UNKNOWN) && (flags & MUTT_APPEND))
291 {
292 m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
293 m->mx_ops = mx_get_ops(m->type);
294 }
295
296 const bool newly_linked_account = !m->account;
297 if (newly_linked_account)
298 {
299 if (!mx_mbox_ac_link(m))
300 {
301 return false;
302 }
303 }
304
305 m->verbose = !(flags & MUTT_QUIET);
306 m->readonly = (flags & MUTT_READONLY);
307 m->peekonly = (flags & MUTT_PEEK);
308
309 if (flags & MUTT_APPEND)
310 {
311 if (!mx_open_mailbox_append(m, flags))
312 {
313 goto error;
314 }
315 return true;
316 }
317
318 if (m->opened > 0)
319 {
320 m->opened++;
321 return true;
322 }
323
324 m->size = 0;
325 m->msg_unread = 0;
326 m->msg_flagged = 0;
327 m->rights = MUTT_ACL_ALL;
328
329 if (m->type == MUTT_UNKNOWN)
330 {
332 m->mx_ops = mx_get_ops(m->type);
333 }
334
335 if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR) || !m->mx_ops)
336 {
337 if (m->type == MUTT_MAILBOX_ERROR)
338 mutt_perror("%s", mailbox_path(m));
339 else if ((m->type == MUTT_UNKNOWN) || !m->mx_ops)
340 mutt_error(_("%s is not a mailbox"), mailbox_path(m));
341 goto error;
342 }
343
345
346 /* if the user has a 'push' command in their .neomuttrc, or in a folder-hook,
347 * it will cause the progress messages not to be displayed because
348 * mutt_refresh() will think we are in the middle of a macro. so set a
349 * flag to indicate that we should really refresh the screen. */
350 OptForceRefresh = true;
351
352 if (m->verbose)
353 mutt_message(_("Reading %s..."), mailbox_path(m));
354
355 // Clear out any existing emails
356 for (int i = 0; i < m->email_max; i++)
357 {
358 email_free(&m->emails[i]);
359 }
360
361 m->msg_count = 0;
362 m->msg_unread = 0;
363 m->msg_flagged = 0;
364 m->msg_new = 0;
365 m->msg_deleted = 0;
366 m->msg_tagged = 0;
367 m->vcount = 0;
368
369 enum MxOpenReturns rc = m->mx_ops->mbox_open(m);
370 m->opened++;
371
372 if ((rc == MX_OPEN_OK) || (rc == MX_OPEN_ABORT))
373 {
374 if ((flags & MUTT_NOSORT) == 0)
375 {
376 /* avoid unnecessary work since the mailbox is completely unthreaded
377 * to begin with */
378 OptSortSubthreads = false;
379 OptNeedRescore = false;
380 }
381 if (m->verbose)
383 if (rc == MX_OPEN_ABORT)
384 {
385 mutt_error(_("Reading from %s interrupted..."), mailbox_path(m));
386 }
387 }
388 else
389 {
390 goto error;
391 }
392
393 if (!m->peekonly)
394 m->has_new = false;
395 OptForceRefresh = false;
396
397 return true;
398
399error:
400 mx_fastclose_mailbox(m, newly_linked_account);
401 if (newly_linked_account)
403 return false;
404}
void account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition account.c:94
#define MUTT_ACL_ALL
All permissions.
Definition mailbox.h:75
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition header.c:406
bool OptNeedRescore
(pseudo) set when the 'score' command is used
Definition globals.c:51
bool OptForceRefresh
(pseudo) refresh even during macros
Definition globals.c:47
bool OptSortSubthreads
(pseudo) used when $sort_aux changes
Definition globals.c:57
#define mutt_message(...)
Definition logging2.h:93
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition mx.c:411
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition mx.c:248
static bool mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox for appending.
Definition mx.c:182
@ MUTT_QUIET
Do not print any messages.
Definition mxapi.h:46
@ MUTT_READONLY
Open in read-only mode.
Definition mxapi.h:45
@ MUTT_NOSORT
Do not sort the mailbox after opening it.
Definition mxapi.h:43
@ MUTT_PEEK
Revert atime back after taking a look (if applicable)
Definition mxapi.h:47
MxOpenReturns
Return values for mbox_open()
Definition mxapi.h:83
@ MX_OPEN_ABORT
Open was aborted.
Definition mxapi.h:86
@ MX_OPEN_OK
Open succeeded.
Definition mxapi.h:84
int vcount
The number of virtual messages.
Definition mailbox.h:101
bool has_new
Mailbox has new mail.
Definition mailbox.h:87
int msg_new
Number of new messages.
Definition mailbox.h:94
int msg_count
Total number of messages.
Definition mailbox.h:90
AclFlags rights
ACL bits, see AclFlags.
Definition mailbox.h:121
int email_max
Size of emails array.
Definition mailbox.h:99
struct Email ** emails
Array of Emails.
Definition mailbox.h:98
bool peekonly
Just taking a glance, revert atime.
Definition mailbox.h:116
int msg_deleted
Number of deleted messages.
Definition mailbox.h:95
off_t size
Size of the Mailbox.
Definition mailbox.h:86
int msg_flagged
Number of flagged messages.
Definition mailbox.h:92
bool readonly
Don't allow changes to the mailbox.
Definition mailbox.h:118
int msg_tagged
How many messages are tagged?
Definition mailbox.h:96
bool verbose
Display status messages?
Definition mailbox.h:119
int msg_unread
Number of unread messages.
Definition mailbox.h:91
enum MxOpenReturns(* mbox_open)(struct Mailbox *m)
Definition mxapi.h:143
+ 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 411 of file mx.c.

412{
413 if (!m)
414 return;
415
416 m->opened--;
417 if (m->opened != 0)
418 return;
419
420 /* never announce that a mailbox we've just left has new mail.
421 * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
422 if (!m->peekonly)
424
425 if (m->mx_ops)
426 m->mx_ops->mbox_close(m);
427
431
432 if (m->emails)
433 {
434 for (int i = 0; i < m->msg_count; i++)
435 {
436 if (!m->emails[i])
437 break;
438 email_free(&m->emails[i]);
439 }
440 }
441
442 if (!m->visible)
443 {
444 mx_ac_remove(m, keep_account);
445 }
446}
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition hash.c:460
void mutt_mailbox_set_notified(struct Mailbox *m)
Note when the user was last notified of new mail.
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition mx.c:1757
struct HashTable * subj_hash
Hash Table: "Subject" -> Email.
Definition mailbox.h:126
struct HashTable * id_hash
Hash Table: "Message-ID" -> Email.
Definition mailbox.h:125
struct HashTable * label_hash
Hash Table: "X-Label" -> Email.
Definition mailbox.h:127
bool visible
True if a result of "mailboxes".
Definition mailbox.h:132
enum MxStatus(* mbox_close)(struct Mailbox *m)
Definition mxapi.h:206
+ 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 453 of file mx.c.

454{
455 if (!m || !m->mx_ops || !m->mx_ops->mbox_sync)
456 return MX_STATUS_ERROR;
457
458 if (m->verbose)
459 {
460 /* L10N: Displayed before/as a mailbox is being synced */
461 mutt_message(_("Writing %s..."), mailbox_path(m));
462 }
463
464 enum MxStatus rc = m->mx_ops->mbox_sync(m);
465 if (rc != MX_STATUS_OK)
466 {
467 mutt_debug(LL_DEBUG2, "mbox_sync returned: %d\n", rc);
468 if ((rc == MX_STATUS_ERROR) && m->verbose)
469 {
470 /* L10N: Displayed if a mailbox sync fails */
471 mutt_error(_("Unable to write %s"), mailbox_path(m));
472 }
473 }
474
475 return rc;
476}
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h:70
@ MX_STATUS_ERROR
An error occurred.
Definition mxapi.h:71
@ MX_STATUS_OK
No changes.
Definition mxapi.h:72
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition mxapi.h:194
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

485{
486 if (!m)
487 return -1;
488
489 struct stat st = { 0 };
490 struct stat stc = { 0 };
491 int rc;
492
493 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
494 const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
495 if (!c_trash || (m->msg_deleted == 0) || ((m->type == MUTT_MAILDIR) && c_maildir_trash))
496 {
497 return 0;
498 }
499
500 int delmsgcount = 0;
501 int first_del = -1;
502 for (int i = 0; i < m->msg_count; i++)
503 {
504 struct Email *e = m->emails[i];
505 if (!e)
506 break;
507
508 if (e->deleted && !e->purge)
509 {
510 if (first_del < 0)
511 first_del = i;
512 delmsgcount++;
513 }
514 }
515
516 if (delmsgcount == 0)
517 return 0; /* nothing to be done */
518
519 /* avoid the "append messages" prompt */
520 const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
521 cs_subset_str_native_set(NeoMutt->sub, "confirm_append", false, NULL);
522 rc = mutt_save_confirm(c_trash, &st);
523 cs_subset_str_native_set(NeoMutt->sub, "confirm_append", c_confirm_append, NULL);
524 if (rc != 0)
525 {
526 /* L10N: Although we know the precise number of messages, we do not show it to the user.
527 So feel free to use a "generic plural" as plural translation if your language has one. */
528 mutt_error(ngettext("message not deleted", "messages not deleted", delmsgcount));
529 return -1;
530 }
531
532 if ((lstat(mailbox_path(m), &stc) == 0) && (stc.st_ino == st.st_ino) &&
533 (stc.st_dev == st.st_dev) && (stc.st_rdev == st.st_rdev))
534 {
535 return 0; /* we are in the trash folder: simple sync */
536 }
537
538 if ((m->type == MUTT_IMAP) && (imap_path_probe(c_trash, NULL) == MUTT_IMAP))
539 {
540 if (imap_fast_trash(m, c_trash) == 0)
541 return 0;
542 }
543
544 struct Mailbox *m_trash = mx_path_resolve(c_trash);
545 const bool old_append = m_trash->append;
546 if (!mx_mbox_open(m_trash, MUTT_APPEND))
547 {
548 mutt_error(_("Can't open trash folder"));
549 mailbox_free(&m_trash);
550 return -1;
551 }
552
553 /* continue from initial scan above */
554 for (int i = first_del; i < m->msg_count; i++)
555 {
556 struct Email *e = m->emails[i];
557 if (!e)
558 break;
559
560 if (e->deleted && !e->purge)
561 {
562 if (mutt_append_message(m_trash, m, e, NULL, MUTT_CM_NONE, CH_NONE) == -1)
563 {
564 mx_mbox_close(m_trash);
565 // L10N: Displayed if appending to $trash fails when syncing or closing a mailbox
566 mutt_error(_("Unable to append to trash folder"));
567 m_trash->append = old_append;
568 mailbox_free(&m_trash);
569 return -1;
570 }
571 }
572 }
573
574 mx_mbox_close(m_trash);
575 m_trash->append = old_append;
576 mailbox_free(&m_trash);
577
578 return 0;
579}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
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_email.c:995
@ MUTT_CM_NONE
No flags are set.
Definition copy_email.h:41
@ CH_NONE
No flags are set.
Definition copy_email.h:65
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition mailbox.c:90
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition mailbox.h:47
int imap_fast_trash(struct Mailbox *m, const char *dest)
Use server COPY command to copy deleted messages to trash.
Definition imap.c:1551
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition muttlib.c:690
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition mx.c:285
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1650
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
The envelope/body of an email.
Definition email.h:39
bool purge
Skip trash folder when deleting.
Definition email.h:79
bool deleted
Email is deleted.
Definition email.h:78
A mailbox.
Definition mailbox.h:81
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:303
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

596{
597 if (!m)
598 return MX_STATUS_ERROR;
599
600 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
601 if (c_mail_check_recent && !m->peekonly)
602 m->has_new = false;
603
604 if (m->readonly || m->dontwrite || m->append || m->peekonly)
605 {
606 mx_fastclose_mailbox(m, false);
607 return 0;
608 }
609
610 int i;
611 int read_msgs = 0;
612 enum MxStatus rc = MX_STATUS_ERROR;
613 enum QuadOption move_messages = MUTT_NO;
614 enum QuadOption purge = MUTT_YES;
615 struct Buffer *mbox = NULL;
616 struct Buffer *buf = buf_pool_get();
617
618 if ((m->msg_unread != 0) && (m->type == MUTT_NNTP))
619 {
620 struct NntpMboxData *mdata = m->mdata;
621
622 if (mdata && mdata->adata && mdata->group)
623 {
624 enum QuadOption ans = query_quadoption(_("Mark all articles read?"),
625 NeoMutt->sub, "catchup_newsgroup");
626 if (ans == MUTT_ABORT)
627 goto cleanup;
628 if (ans == MUTT_YES)
629 mutt_newsgroup_catchup(m, mdata->adata, mdata->group);
630 }
631 }
632
633 const bool c_keep_flagged = cs_subset_bool(NeoMutt->sub, "keep_flagged");
634 for (i = 0; i < m->msg_count; i++)
635 {
636 struct Email *e = m->emails[i];
637 if (!e)
638 break;
639
640 if (!e->deleted && e->read && !(e->flagged && c_keep_flagged))
641 read_msgs++;
642 }
643
644 /* don't need to move articles from newsgroup */
645 if (m->type == MUTT_NNTP)
646 read_msgs = 0;
647
648 const enum QuadOption c_move = cs_subset_quad(NeoMutt->sub, "move");
649 if ((read_msgs != 0) && (c_move != MUTT_NO))
650 {
651 bool is_spool;
652 mbox = buf_pool_get();
653
655 if (p)
656 {
657 is_spool = true;
658 buf_strcpy(mbox, p);
659 }
660 else
661 {
662 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
663 buf_strcpy(mbox, c_mbox);
664 is_spool = mutt_is_spool(mailbox_path(m)) && !mutt_is_spool(buf_string(mbox));
665 }
666
667 if (is_spool && !buf_is_empty(mbox))
668 {
669 expand_path(mbox, false);
670 buf_printf(buf,
671 /* L10N: The first argument is the number of read messages to be
672 moved, the second argument is the target mailbox. */
673 ngettext("Move %d read message to %s?", "Move %d read messages to %s?", read_msgs),
674 read_msgs, buf_string(mbox));
675 move_messages = query_quadoption(buf_string(buf), NeoMutt->sub, "move");
676 if (move_messages == MUTT_ABORT)
677 goto cleanup;
678 }
679 }
680
681 /* There is no point in asking whether or not to purge if we are
682 * just marking messages as "trash". */
683 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
684 if ((m->msg_deleted != 0) && !((m->type == MUTT_MAILDIR) && c_maildir_trash))
685 {
686 buf_printf(buf, ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
687 m->msg_deleted);
688 purge = query_quadoption(buf_string(buf), NeoMutt->sub, "delete");
689 if (purge == MUTT_ABORT)
690 goto cleanup;
691 }
692
693 const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
694 if (c_mark_old && !m->peekonly)
695 {
696 for (i = 0; i < m->msg_count; i++)
697 {
698 struct Email *e = m->emails[i];
699 if (!e)
700 break;
701 if (!e->deleted && !e->old && !e->read)
702 mutt_set_flag(m, e, MUTT_OLD, true, true);
703 }
704 }
705
706 if (move_messages)
707 {
708 if (m->verbose)
709 mutt_message(_("Moving read messages to %s..."), buf_string(mbox));
710
711 /* try to use server-side copy first */
712 i = 1;
713
714 if ((m->type == MUTT_IMAP) && (imap_path_probe(buf_string(mbox), NULL) == MUTT_IMAP))
715 {
716 /* add messages for moving, and clear old tags, if any */
717 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
718 for (i = 0; i < m->msg_count; i++)
719 {
720 struct Email *e = m->emails[i];
721 if (!e)
722 break;
723
724 if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
725 {
726 e->tagged = true;
727 ARRAY_ADD(&ea, e);
728 }
729 else
730 {
731 e->tagged = false;
732 }
733 }
734
735 i = imap_copy_messages(m, &ea, buf_string(mbox), SAVE_MOVE);
736 if (i == 0)
737 {
738 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
739 if (c_delete_untag)
740 {
741 struct Email **ep = NULL;
742 ARRAY_FOREACH(ep, &ea)
743 {
744 mutt_set_flag(m, *ep, MUTT_TAG, false, true);
745 }
746 }
747 }
748 ARRAY_FREE(&ea);
749 }
750
751 if (i == 0) /* success */
752 {
754 }
755 else if (i == -1) /* horrible error, bail */
756 {
757 goto cleanup;
758 }
759 else /* use regular append-copy mode */
760 {
761 struct Mailbox *m_read = mx_path_resolve(buf_string(mbox));
762 if (!mx_mbox_open(m_read, MUTT_APPEND))
763 {
764 mailbox_free(&m_read);
765 goto cleanup;
766 }
767
768 for (i = 0; i < m->msg_count; i++)
769 {
770 struct Email *e = m->emails[i];
771 if (!e)
772 break;
773 if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
774 {
775 if (mutt_append_message(m_read, m, e, NULL, MUTT_CM_NONE, CH_UPDATE_LEN) == 0)
776 {
777 mutt_set_flag(m, e, MUTT_DELETE, true, true);
778 mutt_set_flag(m, e, MUTT_PURGE, true, true);
779 }
780 else
781 {
782 mx_mbox_close(m_read);
783 goto cleanup;
784 }
785 }
786 }
787
788 mx_mbox_close(m_read);
789 }
790 }
791 else if (!m->changed && (m->msg_deleted == 0))
792 {
793 if (m->verbose)
794 mutt_message(_("Mailbox is unchanged"));
795 if ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF))
796 mbox_reset_atime(m, NULL);
797 mx_fastclose_mailbox(m, false);
798 rc = MX_STATUS_OK;
799 goto cleanup;
800 }
801
802 /* copy mails to the trash before expunging */
803 const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
804 const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
805 if (purge && (m->msg_deleted != 0) && (m != m_trash))
806 {
807 if (trash_append(m) != 0)
808 goto cleanup;
809 }
810
811 /* allow IMAP to preserve the deleted flag across sessions */
812 if (m->type == MUTT_IMAP)
813 {
814 const enum MxStatus check = imap_sync_mailbox(m, (purge != MUTT_NO), true);
815 if (check == MX_STATUS_ERROR)
816 {
817 rc = check;
818 goto cleanup;
819 }
820 }
821 else
822 {
823 if (purge == MUTT_NO)
824 {
825 for (i = 0; i < m->msg_count; i++)
826 {
827 struct Email *e = m->emails[i];
828 if (!e)
829 break;
830
831 e->deleted = false;
832 e->purge = false;
833 }
834 m->msg_deleted = 0;
835 }
836
837 if (m->changed || (m->msg_deleted != 0))
838 {
839 enum MxStatus check = sync_mailbox(m);
840 if (check != MX_STATUS_OK)
841 {
842 rc = check;
843 goto cleanup;
844 }
845 }
846 }
847
848 if (m->verbose)
849 {
850 if (move_messages)
851 {
852 mutt_message(_("%d kept, %d moved, %d deleted"),
853 m->msg_count - m->msg_deleted, read_msgs, m->msg_deleted);
854 }
855 else
856 {
857 mutt_message(_("%d kept, %d deleted"), m->msg_count - m->msg_deleted, m->msg_deleted);
858 }
859 }
860
861 const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
862 if ((m->msg_count == m->msg_deleted) &&
863 ((m->type == MUTT_MMDF) || (m->type == MUTT_MBOX)) &&
864 !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
865 {
867 }
868
869 if ((purge == MUTT_YES) && (m->msg_deleted != 0))
870 {
871 for (i = 0; i < m->msg_count; i++)
872 {
873 struct Email *e = m->emails[i];
874 if (!e)
875 break;
876 if (e->deleted && !e->read)
877 {
878 m->msg_unread--;
879 if (!e->old)
880 m->msg_new--;
881 }
882 if (e->deleted && e->flagged)
883 m->msg_flagged--;
884 }
885 }
886
887 mx_fastclose_mailbox(m, false);
888
889 rc = MX_STATUS_OK;
890
891cleanup:
892 buf_pool_release(&mbox);
893 buf_pool_release(&buf);
894 return rc;
895}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
@ CMD_MBOX_HOOK
:mbox-hook
Definition command.h:96
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition helpers.c:192
@ CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition copy_email.h:76
@ MUTT_MMDF
'mmdf' Mailbox type
Definition mailbox.h:45
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:48
@ MUTT_MBOX
'mbox' Mailbox type
Definition mailbox.h:44
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition external.h:54
void mutt_file_unlink_empty(const char *path)
Delete a file if it's empty.
Definition file.c:1222
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:54
char * mutt_find_hook(enum CommandId id, const char *pat)
Find a matching hook.
Definition exec.c:115
int imap_copy_messages(struct Mailbox *m, struct EmailArray *ea, const char *dest, enum MessageSaveOpt save_opt)
Server COPY messages to another folder.
Definition message.c:1717
enum MxStatus imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
Sync all the changes to the server.
Definition imap.c:1679
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition mbox.c:776
@ MUTT_OLD
Old messages.
Definition mutt.h:90
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition mutt.h:96
@ MUTT_TAG
Tagged messages.
Definition mutt.h:99
@ MUTT_DELETE
Messages to be deleted.
Definition mutt.h:94
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
static enum MxStatus sync_mailbox(struct Mailbox *m)
Save changes to disk.
Definition mx.c:453
static int trash_append(struct Mailbox *m)
Move deleted mails to the trash folder.
Definition mx.c:484
static bool mutt_is_spool(const char *str)
Is this the spool_file?
Definition mx.c:138
struct Mailbox * mx_mbox_find(struct Account *a, const char *path)
Find a Mailbox on an Account.
Definition mx.c:1549
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition newsrc.c:1239
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
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(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
String manipulation buffer.
Definition buffer.h:36
bool read
Email is read.
Definition email.h:50
bool old
Email is seen, but unread.
Definition email.h:49
bool flagged
Marked important?
Definition email.h:47
bool tagged
Email is tagged.
Definition email.h:107
bool changed
Mailbox has been modified.
Definition mailbox.h:112
void * mdata
Driver specific data.
Definition mailbox.h:134
bool dontwrite
Don't write the mailbox on close.
Definition mailbox.h:113
NNTP-specific Mailbox data -.
Definition mdata.h:34
+ 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 904 of file mx.c.

905{
906 if (!m)
907 return MX_STATUS_ERROR;
908
909 enum MxStatus rc = MX_STATUS_OK;
910 int purge = 1;
911 int msgcount;
912 int deleted;
913
914 if (m->dontwrite)
915 {
916 struct Buffer *buf = buf_pool_get();
917 struct Buffer *tmp = buf_pool_get();
918
919 const struct MenuDefinition *md_index = index_get_menu_definition();
920 if (keymap_expand_key(km_find_func(md_index, OP_TOGGLE_WRITE), buf))
921 buf_printf(tmp, _(" Press '%s' to toggle write"), buf_string(buf));
922 else
923 buf_addstr(tmp, _("Use 'toggle-write' to re-enable write"));
924
925 mutt_error(_("Mailbox is marked unwritable. %s"), buf_string(tmp));
926
927 buf_pool_release(&buf);
928 buf_pool_release(&tmp);
929 return MX_STATUS_ERROR;
930 }
931 else if (m->readonly)
932 {
933 mutt_error(_("Mailbox is read-only"));
934 return MX_STATUS_ERROR;
935 }
936
937 if (!m->changed && (m->msg_deleted == 0))
938 {
939 if (m->verbose)
940 mutt_message(_("Mailbox is unchanged"));
941 return MX_STATUS_OK;
942 }
943
944 if (m->msg_deleted != 0)
945 {
946 char buf[128] = { 0 };
947
948 snprintf(buf, sizeof(buf),
949 ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
950 m->msg_deleted);
951 purge = query_quadoption(buf, NeoMutt->sub, "delete");
952 if (purge == MUTT_ABORT)
953 return MX_STATUS_ERROR;
954 if (purge == MUTT_NO)
955 {
956 if (!m->changed)
957 return MX_STATUS_OK; /* nothing to do! */
958 /* let IMAP servers hold on to D flags */
959 if (m->type != MUTT_IMAP)
960 {
961 for (int i = 0; i < m->msg_count; i++)
962 {
963 struct Email *e = m->emails[i];
964 if (!e)
965 break;
966 e->deleted = false;
967 e->purge = false;
968 }
969 m->msg_deleted = 0;
970 }
971 }
973 }
974
975 /* really only for IMAP - imap_sync_mailbox results in a call to
976 * ctx_update_tables, so m->msg_deleted is 0 when it comes back */
977 msgcount = m->msg_count;
978 deleted = m->msg_deleted;
979
980 const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
981 const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
982 if (purge && (m->msg_deleted != 0) && (m != m_trash))
983 {
984 if (trash_append(m) != 0)
985 return MX_STATUS_OK;
986 }
987
988 if (m->type == MUTT_IMAP)
989 rc = imap_sync_mailbox(m, purge, false);
990 else
991 rc = sync_mailbox(m);
992 if (rc != MX_STATUS_ERROR)
993 {
994 if ((m->type == MUTT_IMAP) && !purge)
995 {
996 if (m->verbose)
997 mutt_message(_("Mailbox checkpointed"));
998 }
999 else
1000 {
1001 if (m->verbose)
1002 mutt_message(_("%d kept, %d deleted"), msgcount - deleted, deleted);
1003 }
1004
1005 mutt_sleep(0);
1006
1007 const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
1008 if ((m->msg_count == m->msg_deleted) &&
1009 ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) &&
1010 !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
1011 {
1012 unlink(mailbox_path(m));
1013 mx_fastclose_mailbox(m, false);
1014 return MX_STATUS_OK;
1015 }
1016
1017 /* if we haven't deleted any messages, we don't need to resort
1018 * ... except for certain folder formats which need "unsorted"
1019 * sort order in order to synchronize folders.
1020 *
1021 * MH and maildir are safe. mbox-style seems to need re-sorting,
1022 * at least with the new threading code. */
1023 if (purge || ((m->type != MUTT_MAILDIR) && (m->type != MUTT_MH)))
1024 {
1025 /* IMAP does this automatically after handling EXPUNGE */
1026 if (m->type != MUTT_IMAP)
1027 {
1030 }
1031 }
1032 }
1033
1034 return rc;
1035}
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition mailbox.c:232
@ NT_MAILBOX_UNTAG
Clear the 'last-tagged' pointer.
Definition mailbox.h:185
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition mailbox.h:183
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition mailbox.h:184
@ MUTT_MH
'MH' Mailbox type
Definition mailbox.h:46
struct MenuDefinition * index_get_menu_definition(void)
Get the Index Menu Definition.
Definition functions.c:4089
bool keymap_expand_key(struct Keymap *km, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition keymap.c:247
struct Keymap * km_find_func(const struct MenuDefinition *md, int func)
Find a function's mapping in a Menu.
Definition menu.c:141
void mutt_sleep(short s)
Sleep for a while.
Definition muttlib.c:787
Functions for a Dialog or Window.
Definition menudef.h:44
+ Here is the call graph for this function:
+ 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 1044 of file mx.c.

1045{
1046 if (!m)
1047 return NULL;
1048
1049 struct Address *p = NULL;
1050 struct Message *msg = NULL;
1051
1052 if (!m->mx_ops || !m->mx_ops->msg_open_new)
1053 {
1054 mutt_debug(LL_DEBUG1, "function unimplemented for mailbox type %d\n", m->type);
1055 return NULL;
1056 }
1057
1058 msg = message_new();
1059 msg->write = true;
1060
1061 if (e)
1062 {
1063 msg->flags.flagged = e->flagged;
1064 msg->flags.replied = e->replied;
1065 msg->flags.read = e->read;
1066 msg->flags.draft = (flags & MUTT_SET_DRAFT);
1067 msg->received = e->received;
1068 }
1069
1070 if (msg->received == 0)
1071 msg->received = mutt_date_now();
1072
1073 if (m->mx_ops->msg_open_new(m, msg, e))
1074 {
1075 if (m->type == MUTT_MMDF)
1076 fputs(MMDF_SEP, msg->fp);
1077
1078 if (((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) && (flags & MUTT_ADD_FROM))
1079 {
1080 if (e)
1081 {
1082 p = TAILQ_FIRST(&e->env->return_path);
1083 if (!p)
1084 p = TAILQ_FIRST(&e->env->sender);
1085 if (!p)
1086 p = TAILQ_FIRST(&e->env->from);
1087 }
1088
1089 // Use C locale for the date, so that day/month names are in English
1090 char buf[64] = { 0 };
1091 mutt_date_localtime_format_locale(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y",
1093 fprintf(msg->fp, "From %s %s\n",
1094 p ? buf_string(p->mailbox) : NONULL(NeoMutt->username), buf);
1095 }
1096 }
1097 else
1098 {
1099 message_free(&msg);
1100 }
1101
1102 return msg;
1103}
struct Message * message_new(void)
Create a new Message.
Definition message.c:53
void message_free(struct Message **ptr)
Free a Message.
Definition message.c:37
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define MMDF_SEP
Definition lib.h:63
size_t mutt_date_localtime_format_locale(char *buf, size_t buflen, const char *format, time_t t, locale_t loc)
Format localtime using a given locale.
Definition date.c:975
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:459
@ MUTT_ADD_FROM
add a From_ line
Definition mx.h:43
@ MUTT_SET_DRAFT
set the message draft flag
Definition mx.h:44
#define TAILQ_FIRST(head)
Definition queue.h:780
#define NONULL(x)
Definition string2.h:44
An email address.
Definition address.h:35
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
struct Envelope * env
Envelope information.
Definition email.h:68
bool replied
Email has been replied to.
Definition email.h:51
time_t received
Time when the message was placed in the mailbox.
Definition email.h:61
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 message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
struct Message::@264267271004327071125374067057142037276212342100 flags
Flags for the Message.
bool draft
Message has been read.
Definition message.h:44
bool replied
Message has been replied to.
Definition message.h:43
time_t received
Time at which this message was received.
Definition message.h:46
bool write
nonzero if message is open for writing
Definition message.h:38
bool flagged
Message is flagged.
Definition message.h:42
bool read
Message has been read.
Definition message.h:41
bool(* msg_open_new)(struct Mailbox *m, struct Message *msg, const struct Email *e)
Definition mxapi.h:239
char * username
User's login name.
Definition neomutt.h:56
locale_t time_c_locale
Current locale but LC_TIME=C.
Definition neomutt.h:51
+ Here is the call graph for this function:
+ 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 1110 of file mx.c.

1111{
1112 if (!m || !m->mx_ops)
1113 return MX_STATUS_ERROR;
1114
1115 const short c_mail_check = cs_subset_number(NeoMutt->sub, "mail_check");
1116
1117 time_t t = mutt_date_now();
1118 if ((t - m->last_checked) < c_mail_check)
1119 return MX_STATUS_OK;
1120
1121 m->last_checked = t;
1122
1123 enum MxStatus rc = m->mx_ops->mbox_check(m);
1124 if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1125 {
1127 }
1128
1129 return rc;
1130}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
@ NT_MAILBOX_INVALID
Email list was changed.
Definition mailbox.h:182
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:75
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:73
time_t last_checked
Last time we checked this mailbox for new mail.
Definition mailbox.h:107
enum MxStatus(* mbox_check)(struct Mailbox *m)
Definition mxapi.h:169
+ 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,
struct Email * e )

Return a stream pointer for a message.

Parameters
mMailbox
eEmail
Return values
ptrMessage
NULLError

Definition at line 1139 of file mx.c.

1140{
1141 if (!m || !e)
1142 return NULL;
1143
1144 if (!m->mx_ops || !m->mx_ops->msg_open)
1145 {
1146 mutt_debug(LL_DEBUG1, "function not implemented for mailbox type %d\n", m->type);
1147 return NULL;
1148 }
1149
1150 struct Message *msg = message_new();
1151 if (!m->mx_ops->msg_open(m, msg, e))
1152 message_free(&msg);
1153
1154 return msg;
1155}
bool(* msg_open)(struct Mailbox *m, struct Message *msg, struct Email *e)
Definition mxapi.h:223
+ 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 1164 of file mx.c.

1165{
1166 if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1167 return -1;
1168
1169 if (!(msg->write && m->append))
1170 {
1171 mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1172 return -1;
1173 }
1174
1175 return m->mx_ops->msg_commit(m, msg);
1176}
int(* msg_commit)(struct Mailbox *m, struct Message *msg)
Definition mxapi.h:254
+ Here is the caller graph for this function:

◆ mx_msg_close()

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

Close a message.

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

Definition at line 1185 of file mx.c.

1186{
1187 if (!m || !ptr || !*ptr)
1188 return 0;
1189
1190 int rc = 0;
1191 struct Message *msg = *ptr;
1192
1193 if (m->mx_ops && m->mx_ops->msg_close)
1194 rc = m->mx_ops->msg_close(m, msg);
1195
1196 if (msg->path)
1197 {
1198 mutt_debug(LL_DEBUG1, "unlinking %s\n", msg->path);
1199 unlink(msg->path);
1200 }
1201
1202 message_free(ptr);
1203 return rc;
1204}
char * path
path to temp file
Definition message.h:36
int(* msg_close)(struct Mailbox *m, struct Message *msg)
Definition mxapi.h:269
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_alloc_memory()

void mx_alloc_memory ( struct Mailbox * m,
int req_size )

Create storage for the emails.

Parameters
mMailbox
req_sizeSpace required

Definition at line 1211 of file mx.c.

1212{
1213 if ((req_size + 1) <= m->email_max)
1214 return;
1215
1216 // Step size to increase by
1217 // Larger mailboxes get a larger step (limited to 1000)
1218 const int grow = CLAMP(m->email_max, 25, 1000);
1219
1220 // Sanity checks
1221 req_size = ROUND_UP(req_size + 1, grow);
1222
1223 const size_t s = MAX(sizeof(struct Email *), sizeof(int));
1224 if ((req_size * s) < (m->email_max * s))
1225 {
1226 mutt_error("%s", strerror(ENOMEM));
1227 mutt_exit(1);
1228 }
1229
1230 if (m->emails)
1231 {
1232 MUTT_MEM_REALLOC(&m->emails, req_size, struct Email *);
1233 MUTT_MEM_REALLOC(&m->v2r, req_size, int);
1234 }
1235 else
1236 {
1237 m->emails = MUTT_MEM_CALLOC(req_size, struct Email *);
1238 m->v2r = MUTT_MEM_CALLOC(req_size, int);
1239 }
1240
1241 for (int i = m->email_max; i < req_size; i++)
1242 {
1243 m->emails[i] = NULL;
1244 m->v2r[i] = -1;
1245 }
1246
1247 m->email_max = req_size;
1248}
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition exit.c:41
#define ROUND_UP(NUM, STEP)
Round up NUM to the nearest multiple of STEP.
Definition memory.h:46
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
#define MAX(a, b)
Return the maximum of two values.
Definition memory.h:38
#define CLAMP(val, lo, hi)
Clamp a value between a lower and upper bound.
Definition memory.h:42
int * v2r
Mapping from virtual to real msgno.
Definition mailbox.h:100
+ 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 ( struct Buffer * path)

Is the mailbox empty.

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

Definition at line 1257 of file mx.c.

1258{
1259 if (buf_is_empty(path))
1260 return -1;
1261
1262 enum MailboxType type = mx_path_probe(buf_string(path));
1263 const struct MxOps *ops = mx_get_ops(type);
1264 if (!ops || !ops->path_is_empty)
1265 return -1;
1266
1267 return ops->path_is_empty(path);
1268}
MailboxType
Supported mailbox formats.
Definition mailbox.h:40
int(* path_is_empty)(struct Buffer *path)
Definition mxapi.h:370
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition mxapi.h:99
+ 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 1279 of file mx.c.

1280{
1281 if (!m || !buf)
1282 return -1;
1283
1284 if (m->mx_ops->tags_edit)
1285 return m->mx_ops->tags_edit(m, tags, buf);
1286
1287 mutt_message(_("Folder doesn't support tagging, aborting"));
1288 return -1;
1289}
int(* tags_edit)(struct Mailbox *m, const char *tags, struct Buffer *buf)
Definition mxapi.h:313
+ 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 1299 of file mx.c.

1300{
1301 if (!m || !e || !tags)
1302 return -1;
1303
1304 if (m->mx_ops->tags_commit)
1305 return m->mx_ops->tags_commit(m, e, tags);
1306
1307 mutt_message(_("Folder doesn't support tagging, aborting"));
1308 return -1;
1309}
int(* tags_commit)(struct Mailbox *m, struct Email *e, const char *buf)
Definition mxapi.h:330
+ 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 1316 of file mx.c.

1317{
1318 return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1319}
+ 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
enumMailboxType, e.g. MUTT_IMAP

Definition at line 1326 of file mx.c.

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

◆ mx_path_canon()

int mx_path_canon ( struct Buffer * path,
const char * folder,
enum MailboxType * type )

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

Definition at line 1372 of file mx.c.

1373{
1374 if (buf_is_empty(path))
1375 return -1;
1376
1377 for (size_t i = 0; i < 3; i++)
1378 {
1379 /* Look for !! ! - < > or ^ followed by / or NUL */
1380 if ((buf_at(path, 0) == '!') && (buf_at(path, 1) == '!'))
1381 {
1382 if (((buf_at(path, 2) == '/') || (buf_at(path, 2) == '\0')))
1383 {
1384 buf_inline_replace(path, 0, 2, LastFolder);
1385 }
1386 }
1387 else if ((buf_at(path, 0) == '+') || (buf_at(path, 0) == '='))
1388 {
1389 size_t folder_len = mutt_str_len(folder);
1390 if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1391 {
1392 path->data[0] = '/';
1393 buf_inline_replace(path, 0, 0, folder);
1394 }
1395 else
1396 {
1397 buf_inline_replace(path, 0, 1, folder);
1398 }
1399 }
1400 else if ((buf_at(path, 1) == '/') || (buf_at(path, 1) == '\0'))
1401 {
1402 if (buf_at(path, 0) == '!')
1403 {
1404 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1405 buf_inline_replace(path, 0, 1, c_spool_file);
1406 }
1407 else if (buf_at(path, 0) == '-')
1408 {
1409 buf_inline_replace(path, 0, 1, LastFolder);
1410 }
1411 else if (buf_at(path, 0) == '<')
1412 {
1413 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
1414 buf_inline_replace(path, 0, 1, c_record);
1415 }
1416 else if (buf_at(path, 0) == '>')
1417 {
1418 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
1419 buf_inline_replace(path, 0, 1, c_mbox);
1420 }
1421 else if (buf_at(path, 0) == '^')
1422 {
1423 buf_inline_replace(path, 0, 1, CurrentFolder);
1424 }
1425 else if (buf_at(path, 0) == '~')
1426 {
1427 buf_inline_replace(path, 0, 1, NeoMutt->home_dir);
1428 }
1429 }
1430 else if (buf_at(path, 0) == '@')
1431 {
1432 /* elm compatibility, @ expands alias to user name */
1433 struct AddressList *al = alias_lookup(buf_string(path));
1434 if (!al || TAILQ_EMPTY(al))
1435 break;
1436
1437 struct Email *e = email_new();
1438 e->env = mutt_env_new();
1439 mutt_addrlist_copy(&e->env->from, al, false);
1440 mutt_addrlist_copy(&e->env->to, al, false);
1442 email_free(&e);
1443 break;
1444 }
1445 else
1446 {
1447 break;
1448 }
1449 }
1450
1451 // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1452 // return -1;
1453
1455 if (type)
1456 *type = type2;
1457 const struct MxOps *ops = mx_get_ops(type2);
1458 if (!ops || !ops->path_canon)
1459 return -1;
1460
1461 if (ops->path_canon(path) < 0)
1462 {
1463 mutt_path_canon(path, NeoMutt->home_dir, true);
1464 }
1465
1466 return 0;
1467}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:776
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition alias.c:274
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:674
void buf_inline_replace(struct Buffer *buf, size_t pos, size_t len, const char *str)
Replace part of a string.
Definition buffer.c:774
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
char * LastFolder
Previously selected mailbox.
Definition globals.c:39
char * CurrentFolder
Currently selected mailbox.
Definition globals.c:38
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition exec.c:218
bool mutt_path_canon(struct Buffer *path, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition path.c:248
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
#define TAILQ_EMPTY(head)
Definition queue.h:778
char * data
Pointer to data.
Definition buffer.h:37
char * path
Path of Email (for local Mailboxes)
Definition email.h:70
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
int(* path_canon)(struct Buffer *path)
Definition mxapi.h:356
char * home_dir
User's home directory.
Definition neomutt.h:55
+ 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 1476 of file mx.c.

1477{
1478 if (!m)
1479 return -1;
1480
1481 struct Buffer *path = buf_pool_get();
1482
1483 if (m->realpath)
1484 buf_strcpy(path, m->realpath);
1485 else
1486 buf_strcpy(path, mailbox_path(m));
1487
1488 int rc = mx_path_canon(path, folder, &m->type);
1489
1491 buf_pool_release(&path);
1492
1493 if (rc >= 0)
1494 {
1495 m->mx_ops = mx_get_ops(m->type);
1496 buf_strcpy(&m->pathbuf, m->realpath);
1497 }
1498
1499 return rc;
1500}
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
int mx_path_canon(struct Buffer *path, const char *folder, enum MailboxType *type)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition mx.c:1372
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition mailbox.h:83
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:82
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

1511{
1512 if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1513 return 0;
1514
1515 return m->mx_ops->msg_padding_size(m);
1516}
int(* msg_padding_size)(struct Mailbox *m)
Definition mxapi.h:281
+ 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 1524 of file mx.c.

1525{
1526 if (!m || !m->mx_ops || !m->realpath)
1527 return NULL;
1528
1529 struct Account **ap = NULL;
1531 {
1532 struct Account *a = *ap;
1533 if (a->type != m->type)
1534 continue;
1535
1536 if (m->mx_ops->ac_owns_path(a, m->realpath))
1537 return a;
1538 }
1539
1540 return NULL;
1541}
bool(* ac_owns_path)(struct Account *a, const char *path)
Definition mxapi.h:116
struct AccountArray accounts
All Accounts.
Definition neomutt.h:50
+ 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 1549 of file mx.c.

1550{
1551 if (!a || !path)
1552 return NULL;
1553
1554 struct Mailbox *m_match = NULL;
1555 struct Mailbox **mp = NULL;
1556 struct Url *url_p = NULL;
1557 struct Url *url_a = NULL;
1558
1559 const bool use_url = (a->type == MUTT_IMAP);
1560 if (use_url)
1561 {
1562 url_p = url_parse(path);
1563 if (!url_p)
1564 goto done;
1565 }
1566
1567 ARRAY_FOREACH(mp, &a->mailboxes)
1568 {
1569 struct Mailbox *m = *mp;
1570
1571 if (!use_url)
1572 {
1573 if (mutt_str_equal(m->realpath, path))
1574 return m;
1575 continue;
1576 }
1577
1578 url_free(&url_a);
1579 url_a = url_parse(m->realpath);
1580 if (!url_a)
1581 continue;
1582
1583 if (!mutt_istr_equal(url_a->host, url_p->host))
1584 continue;
1585 if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1586 continue;
1587 if (a->type == MUTT_IMAP)
1588 {
1589 if (imap_mxcmp(url_a->path, url_p->path) == 0)
1590 {
1591 m_match = *mp;
1592 break;
1593 }
1594 }
1595 else
1596 {
1597 if (mutt_str_equal(url_a->path, url_p->path))
1598 {
1599 m_match = *mp;
1600 break;
1601 }
1602 }
1603 }
1604
1605done:
1606 url_free(&url_p);
1607 url_free(&url_a);
1608
1609 return m_match;
1610}
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition util.c:556
struct MailboxArray mailboxes
All Mailboxes.
Definition account.h:40
+ 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 1618 of file mx.c.

1619{
1620 if (!path)
1621 return NULL;
1622
1623 struct Buffer *buf = buf_new(path);
1624 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1625 mx_path_canon(buf, c_folder, NULL);
1626
1627 struct Account **ap = NULL;
1629 {
1630 struct Account *a = *ap;
1631 struct Mailbox *m = mx_mbox_find(a, buf_string(buf));
1632 if (m)
1633 {
1634 buf_free(&buf);
1635 return m;
1636 }
1637 }
1638
1639 buf_free(&buf);
1640 return NULL;
1641}
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition buffer.c:326
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition buffer.c:311
+ 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 1650 of file mx.c.

1651{
1652 if (!path)
1653 return NULL;
1654
1655 struct Mailbox *m = mx_mbox_find2(path);
1656 if (m)
1657 return m;
1658
1659 m = mailbox_new();
1660 buf_strcpy(&m->pathbuf, path);
1661 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1662 mx_path_canon2(m, c_folder);
1663
1664 return m;
1665}
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition mailbox.c:69
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition mx.c:1618
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition mx.c:1476
+ 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 1673 of file mx.c.

1674{
1675 if (!a || !name)
1676 return NULL;
1677
1678 struct Mailbox **mp = NULL;
1679
1680 ARRAY_FOREACH(mp, &a->mailboxes)
1681 {
1682 struct Mailbox *m = *mp;
1683
1684 if (mutt_str_equal(m->name, name))
1685 return m;
1686 }
1687
1688 return NULL;
1689}
char * name
A short name for the Mailbox.
Definition mailbox.h:84
+ 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 1696 of file mx.c.

1697{
1698 if (!name)
1699 return NULL;
1700
1701 struct Account **ap = NULL;
1703 {
1704 struct Account *a = *ap;
1705 struct Mailbox *m = mx_mbox_find_by_name_ac(a, name);
1706 if (m)
1707 return m;
1708 }
1709
1710 return NULL;
1711}
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:1673
+ 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 1722 of file mx.c.

1723{
1724 if (!path_or_name)
1725 return NULL;
1726
1727 // Order is name first because you can create a Mailbox from
1728 // a path, but can't from a name. So fallback behavior creates
1729 // a new Mailbox for us.
1730 struct Mailbox *m = mx_mbox_find_by_name(path_or_name);
1731 if (!m)
1732 m = mx_path_resolve(path_or_name);
1733
1734 return m;
1735}
static struct Mailbox * mx_mbox_find_by_name(const char *name)
Find a Mailbox with given name.
Definition mx.c:1696
+ 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 1740 of file mx.c.

1741{
1742 if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1743 return false;
1744
1745 return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1746}
bool account_mailbox_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition account.c:67
bool(* ac_add)(struct Account *a, struct Mailbox *m)
Definition mxapi.h:131
+ 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 1757 of file mx.c.

1758{
1759 if (!m || !m->account)
1760 return -1;
1761
1762 struct Account *a = m->account;
1764 if (!keep_account && ARRAY_EMPTY(&a->mailboxes))
1765 {
1767 }
1768 return 0;
1769}
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
void neomutt_account_remove(struct NeoMutt *n, struct Account *a)
Remove an Account from the global list.
Definition neomutt.c:557
+ 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 1776 of file mx.c.

1777{
1778 if (!m)
1779 return MX_STATUS_ERROR;
1780
1781 enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1782 if (rc != MX_STATUS_ERROR)
1783 {
1784 struct EventMailbox ev_m = { m };
1786 }
1787
1788 return rc;
1789}
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition mailbox.h:178
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition notify.c:173
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition notify_type.h:50
An Event that happened to a Mailbox.
Definition mailbox.h:192
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition mailbox.h:147
enum MxStatus(* mbox_check_stats)(struct Mailbox *m, CheckStatsFlags flags)
Definition mxapi.h:182
+ Here is the call graph for this function:
+ 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 1800 of file mx.c.

1801{
1802 if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1803 return 0;
1804
1805 return m->mx_ops->msg_save_hcache(m, e);
1806}
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Definition mxapi.h:296
+ 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 1813 of file mx.c.

1814{
1815 return m ? m->type : MUTT_MAILBOX_ERROR;
1816}
+ 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 1824 of file mx.c.

1825{
1826 if (!m)
1827 return -1;
1828
1829 if (m->readonly)
1830 {
1831 mutt_error(_("Can't toggle write on a readonly mailbox"));
1832 return -1;
1833 }
1834
1835 if (m->dontwrite)
1836 {
1837 m->dontwrite = false;
1838 mutt_message(_("Changes to folder will be written on folder exit"));
1839 }
1840 else
1841 {
1842 m->dontwrite = true;
1843 mutt_message(_("Changes to folder will not be written"));
1844 }
1845
1846 struct EventMailbox ev_m = { m };
1848 return 0;
1849}
+ 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, },
}

Lookup table of mailbox types.

Definition at line 78 of file mx.c.

78 {
79 // clang-format off
80 { "mbox", MUTT_MBOX, },
81 { "mmdf", MUTT_MMDF, },
82 { "mh", MUTT_MH, },
83 { "maildir", MUTT_MAILDIR, },
84 { NULL, 0, },
85 // clang-format on
86};

◆ MboxTypeDef

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

Data for the $mbox_type enumeration.

Definition at line 89 of file mx.c.

89 {
90 "mbox_type",
91 4,
92 (struct Mapping *) &MboxTypeMap,
93};

◆ MxOps

const struct MxOps* MxOps[]
static
Initial value:
= {
NULL,
}
const struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps -.
Definition nntp.c:2819
const struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition mbox.c:1741
const struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition notmuch.c:2497
const struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition mh.c:1243
const struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition pop.c:1199
const struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition imap.c:2741
const struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition compress.c:889
const struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition mbox.c:1771
const struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps -.
Definition maildir.c:44

All the Mailbox backends.

Definition at line 98 of file mx.c.

98 {
99 /* These mailboxes can be recognised by their Url scheme */
100 &MxImapOps,
101#ifdef USE_NOTMUCH
103#endif
104 &MxPopOps,
105 &MxNntpOps,
106
107 /* Local mailboxes */
109 &MxMboxOps,
110 &MxMhOps,
111 &MxMmdfOps,
112
113 /* If everything else fails... */
114 &MxCompOps,
115 NULL,
116};