NeoMutt  2025-12-11-596-g7cc1dd
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:87
+ 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:677
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
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:239
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:2546
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:338
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:213
@ 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:1323
#define MUTT_APPEND
Open mailbox for appending messages.
Definition mxapi.h:41
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition mxapi.h:45
bool append
Mailbox is opened in append mode.
Definition mailbox.h:108
const struct MxOps * mx_ops
MXAPI callback functions.
Definition mailbox.h:106
enum MailboxType type
Mailbox type.
Definition mailbox.h:101
int opened
Number of times mailbox is opened.
Definition mailbox.h:127
bool(* mbox_open_append)(struct Mailbox *m, OpenMailboxFlags flags)
Definition mxapi.h:146
+ 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:1737
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition mx.c:1521
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition neomutt.c:456
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:126
+ 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:72
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:405
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
#define MUTT_READONLY
Open in read-only mode.
Definition mxapi.h:42
#define MUTT_QUIET
Do not print any messages.
Definition mxapi.h:43
MxOpenReturns
Return values for mbox_open()
Definition mxapi.h:72
@ MX_OPEN_ABORT
Open was aborted.
Definition mxapi.h:75
@ MX_OPEN_OK
Open succeeded.
Definition mxapi.h:73
#define MUTT_PEEK
Revert atime back after taking a look (if applicable)
Definition mxapi.h:44
#define MUTT_NOSORT
Do not sort the mailbox after opening it.
Definition mxapi.h:40
int vcount
The number of virtual messages.
Definition mailbox.h:98
bool has_new
Mailbox has new mail.
Definition mailbox.h:84
int msg_new
Number of new messages.
Definition mailbox.h:91
int msg_count
Total number of messages.
Definition mailbox.h:87
AclFlags rights
ACL bits, see AclFlags.
Definition mailbox.h:118
int email_max
Size of emails array.
Definition mailbox.h:96
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
bool peekonly
Just taking a glance, revert atime.
Definition mailbox.h:113
int msg_deleted
Number of deleted messages.
Definition mailbox.h:92
off_t size
Size of the Mailbox.
Definition mailbox.h:83
int msg_flagged
Number of flagged messages.
Definition mailbox.h:89
bool readonly
Don't allow changes to the mailbox.
Definition mailbox.h:115
int msg_tagged
How many messages are tagged?
Definition mailbox.h:93
bool verbose
Display status messages?
Definition mailbox.h:116
int msg_unread
Number of unread messages.
Definition mailbox.h:88
enum MxOpenReturns(* mbox_open)(struct Mailbox *m)
Definition mxapi.h:132
+ 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:459
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:1754
struct HashTable * subj_hash
Hash Table: "subject" -> Email.
Definition mailbox.h:123
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
Definition mailbox.h:122
struct HashTable * label_hash
Hash Table: "x-labels" -> Email.
Definition mailbox.h:124
bool visible
True if a result of "mailboxes".
Definition mailbox.h:129
enum MxStatus(* mbox_close)(struct Mailbox *m)
Definition mxapi.h:195
+ 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:59
@ MX_STATUS_ERROR
An error occurred.
Definition mxapi.h:60
@ MX_STATUS_OK
No changes.
Definition mxapi.h:61
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition mxapi.h:183
+ 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_NO_FLAGS, CH_NO_FLAGS) == -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:992
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition copy_email.h:37
#define CH_NO_FLAGS
No flags are set.
Definition copy_email.h:55
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:1543
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition muttlib.c:689
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:1647
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:78
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, read_msgs = 0;
611 enum MxStatus rc = MX_STATUS_ERROR;
612 enum QuadOption move_messages = MUTT_NO;
613 enum QuadOption purge = MUTT_YES;
614 struct Buffer *mbox = NULL;
615 struct Buffer *buf = buf_pool_get();
616
617 if ((m->msg_unread != 0) && (m->type == MUTT_NNTP))
618 {
619 struct NntpMboxData *mdata = m->mdata;
620
621 if (mdata && mdata->adata && mdata->group)
622 {
623 enum QuadOption ans = query_quadoption(_("Mark all articles read?"),
624 NeoMutt->sub, "catchup_newsgroup");
625 if (ans == MUTT_ABORT)
626 goto cleanup;
627 if (ans == MUTT_YES)
628 mutt_newsgroup_catchup(m, mdata->adata, mdata->group);
629 }
630 }
631
632 const bool c_keep_flagged = cs_subset_bool(NeoMutt->sub, "keep_flagged");
633 for (i = 0; i < m->msg_count; i++)
634 {
635 struct Email *e = m->emails[i];
636 if (!e)
637 break;
638
639 if (!e->deleted && e->read && !(e->flagged && c_keep_flagged))
640 read_msgs++;
641 }
642
643 /* don't need to move articles from newsgroup */
644 if (m->type == MUTT_NNTP)
645 read_msgs = 0;
646
647 const enum QuadOption c_move = cs_subset_quad(NeoMutt->sub, "move");
648 if ((read_msgs != 0) && (c_move != MUTT_NO))
649 {
650 bool is_spool;
651 mbox = buf_pool_get();
652
654 if (p)
655 {
656 is_spool = true;
657 buf_strcpy(mbox, p);
658 }
659 else
660 {
661 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
662 buf_strcpy(mbox, c_mbox);
663 is_spool = mutt_is_spool(mailbox_path(m)) && !mutt_is_spool(buf_string(mbox));
664 }
665
666 if (is_spool && !buf_is_empty(mbox))
667 {
668 expand_path(mbox, false);
669 buf_printf(buf,
670 /* L10N: The first argument is the number of read messages to be
671 moved, the second argument is the target mailbox. */
672 ngettext("Move %d read message to %s?", "Move %d read messages to %s?", read_msgs),
673 read_msgs, buf_string(mbox));
674 move_messages = query_quadoption(buf_string(buf), NeoMutt->sub, "move");
675 if (move_messages == MUTT_ABORT)
676 goto cleanup;
677 }
678 }
679
680 /* There is no point in asking whether or not to purge if we are
681 * just marking messages as "trash". */
682 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
683 if ((m->msg_deleted != 0) && !((m->type == MUTT_MAILDIR) && c_maildir_trash))
684 {
685 buf_printf(buf, ngettext("Purge %d deleted message?", "Purge %d deleted messages?", m->msg_deleted),
686 m->msg_deleted);
687 purge = query_quadoption(buf_string(buf), NeoMutt->sub, "delete");
688 if (purge == MUTT_ABORT)
689 goto cleanup;
690 }
691
692 const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
693 if (c_mark_old && !m->peekonly)
694 {
695 for (i = 0; i < m->msg_count; i++)
696 {
697 struct Email *e = m->emails[i];
698 if (!e)
699 break;
700 if (!e->deleted && !e->old && !e->read)
701 mutt_set_flag(m, e, MUTT_OLD, true, true);
702 }
703 }
704
705 if (move_messages)
706 {
707 if (m->verbose)
708 mutt_message(_("Moving read messages to %s..."), buf_string(mbox));
709
710 /* try to use server-side copy first */
711 i = 1;
712
713 if ((m->type == MUTT_IMAP) && (imap_path_probe(buf_string(mbox), NULL) == MUTT_IMAP))
714 {
715 /* add messages for moving, and clear old tags, if any */
716 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
717 for (i = 0; i < m->msg_count; i++)
718 {
719 struct Email *e = m->emails[i];
720 if (!e)
721 break;
722
723 if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
724 {
725 e->tagged = true;
726 ARRAY_ADD(&ea, e);
727 }
728 else
729 {
730 e->tagged = false;
731 }
732 }
733
734 i = imap_copy_messages(m, &ea, buf_string(mbox), SAVE_MOVE);
735 if (i == 0)
736 {
737 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
738 if (c_delete_untag)
739 {
740 struct Email **ep = NULL;
741 ARRAY_FOREACH(ep, &ea)
742 {
743 mutt_set_flag(m, *ep, MUTT_TAG, false, true);
744 }
745 }
746 }
747 ARRAY_FREE(&ea);
748 }
749
750 if (i == 0) /* success */
751 {
753 }
754 else if (i == -1) /* horrible error, bail */
755 {
756 goto cleanup;
757 }
758 else /* use regular append-copy mode */
759 {
760 struct Mailbox *m_read = mx_path_resolve(buf_string(mbox));
761 if (!mx_mbox_open(m_read, MUTT_APPEND))
762 {
763 mailbox_free(&m_read);
764 goto cleanup;
765 }
766
767 for (i = 0; i < m->msg_count; i++)
768 {
769 struct Email *e = m->emails[i];
770 if (!e)
771 break;
772 if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
773 {
774 if (mutt_append_message(m_read, m, e, NULL, MUTT_CM_NO_FLAGS, CH_UPDATE_LEN) == 0)
775 {
776 mutt_set_flag(m, e, MUTT_DELETE, true, true);
777 mutt_set_flag(m, e, MUTT_PURGE, true, true);
778 }
779 else
780 {
781 mx_mbox_close(m_read);
782 goto cleanup;
783 }
784 }
785 }
786
787 mx_mbox_close(m_read);
788 }
789 }
790 else if (!m->changed && (m->msg_deleted == 0))
791 {
792 if (m->verbose)
793 mutt_message(_("Mailbox is unchanged"));
794 if ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF))
795 mbox_reset_atime(m, NULL);
796 mx_fastclose_mailbox(m, false);
797 rc = MX_STATUS_OK;
798 goto cleanup;
799 }
800
801 /* copy mails to the trash before expunging */
802 const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
803 const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
804 if (purge && (m->msg_deleted != 0) && (m != m_trash))
805 {
806 if (trash_append(m) != 0)
807 goto cleanup;
808 }
809
810 /* allow IMAP to preserve the deleted flag across sessions */
811 if (m->type == MUTT_IMAP)
812 {
813 const enum MxStatus check = imap_sync_mailbox(m, (purge != MUTT_NO), true);
814 if (check == MX_STATUS_ERROR)
815 {
816 rc = check;
817 goto cleanup;
818 }
819 }
820 else
821 {
822 if (purge == MUTT_NO)
823 {
824 for (i = 0; i < m->msg_count; i++)
825 {
826 struct Email *e = m->emails[i];
827 if (!e)
828 break;
829
830 e->deleted = false;
831 e->purge = false;
832 }
833 m->msg_deleted = 0;
834 }
835
836 if (m->changed || (m->msg_deleted != 0))
837 {
838 enum MxStatus check = sync_mailbox(m);
839 if (check != MX_STATUS_OK)
840 {
841 rc = check;
842 goto cleanup;
843 }
844 }
845 }
846
847 if (m->verbose)
848 {
849 if (move_messages)
850 {
851 mutt_message(_("%d kept, %d moved, %d deleted"),
852 m->msg_count - m->msg_deleted, read_msgs, m->msg_deleted);
853 }
854 else
855 {
856 mutt_message(_("%d kept, %d deleted"), m->msg_count - m->msg_deleted, m->msg_deleted);
857 }
858 }
859
860 const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
861 if ((m->msg_count == m->msg_deleted) &&
862 ((m->type == MUTT_MMDF) || (m->type == MUTT_MBOX)) &&
863 !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
864 {
866 }
867
868 if ((purge == MUTT_YES) && (m->msg_deleted != 0))
869 {
870 for (i = 0; i < m->msg_count; i++)
871 {
872 struct Email *e = m->emails[i];
873 if (!e)
874 break;
875 if (e->deleted && !e->read)
876 {
877 m->msg_unread--;
878 if (!e->old)
879 m->msg_new--;
880 }
881 if (e->deleted && e->flagged)
882 m->msg_flagged--;
883 }
884 }
885
886 mx_fastclose_mailbox(m, false);
887
888 rc = MX_STATUS_OK;
889
890cleanup:
891 buf_pool_release(&mbox);
892 buf_pool_release(&buf);
893 return rc;
894}
#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:161
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
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:93
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition helpers.c:192
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition copy_email.h:66
@ 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:1225
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:114
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:1710
enum MxStatus imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
Sync all the changes to the server.
Definition imap.c:1661
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition mbox.c:751
@ 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:121
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:1546
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition newsrc.c:1226
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:109
void * mdata
Driver specific data.
Definition mailbox.h:131
bool dontwrite
Don't write the mailbox on close.
Definition mailbox.h:110
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 903 of file mx.c.

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

1042{
1043 if (!m)
1044 return NULL;
1045
1046 struct Address *p = NULL;
1047 struct Message *msg = NULL;
1048
1049 if (!m->mx_ops || !m->mx_ops->msg_open_new)
1050 {
1051 mutt_debug(LL_DEBUG1, "function unimplemented for mailbox type %d\n", m->type);
1052 return NULL;
1053 }
1054
1055 msg = message_new();
1056 msg->write = true;
1057
1058 if (e)
1059 {
1060 msg->flags.flagged = e->flagged;
1061 msg->flags.replied = e->replied;
1062 msg->flags.read = e->read;
1063 msg->flags.draft = (flags & MUTT_SET_DRAFT);
1064 msg->received = e->received;
1065 }
1066
1067 if (msg->received == 0)
1068 msg->received = mutt_date_now();
1069
1070 if (m->mx_ops->msg_open_new(m, msg, e))
1071 {
1072 if (m->type == MUTT_MMDF)
1073 fputs(MMDF_SEP, msg->fp);
1074
1075 if (((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) && (flags & MUTT_ADD_FROM))
1076 {
1077 if (e)
1078 {
1079 p = TAILQ_FIRST(&e->env->return_path);
1080 if (!p)
1081 p = TAILQ_FIRST(&e->env->sender);
1082 if (!p)
1083 p = TAILQ_FIRST(&e->env->from);
1084 }
1085
1086 // Use C locale for the date, so that day/month names are in English
1087 char buf[64] = { 0 };
1088 mutt_date_localtime_format_locale(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y",
1090 fprintf(msg->fp, "From %s %s\n",
1091 p ? buf_string(p->mailbox) : NONULL(NeoMutt->username), buf);
1092 }
1093 }
1094 else
1095 {
1096 message_free(&msg);
1097 }
1098
1099 return msg;
1100}
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:970
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
#define MUTT_ADD_FROM
add a From_ line
Definition mx.h:39
#define MUTT_SET_DRAFT
set the message draft flag
Definition mx.h:40
#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:228
char * username
User's login name.
Definition neomutt.h:57
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 1107 of file mx.c.

1108{
1109 if (!m || !m->mx_ops)
1110 return MX_STATUS_ERROR;
1111
1112 const short c_mail_check = cs_subset_number(NeoMutt->sub, "mail_check");
1113
1114 time_t t = mutt_date_now();
1115 if ((t - m->last_checked) < c_mail_check)
1116 return MX_STATUS_OK;
1117
1118 m->last_checked = t;
1119
1120 enum MxStatus rc = m->mx_ops->mbox_check(m);
1121 if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1122 {
1124 }
1125
1126 return rc;
1127}
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:179
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:64
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:62
time_t last_checked
Last time we checked this mailbox for new mail.
Definition mailbox.h:104
enum MxStatus(* mbox_check)(struct Mailbox *m)
Definition mxapi.h:158
+ 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 1136 of file mx.c.

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

1162{
1163 if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1164 return -1;
1165
1166 if (!(msg->write && m->append))
1167 {
1168 mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1169 return -1;
1170 }
1171
1172 return m->mx_ops->msg_commit(m, msg);
1173}
int(* msg_commit)(struct Mailbox *m, struct Message *msg)
Definition mxapi.h:243
+ 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 1182 of file mx.c.

1183{
1184 if (!m || !ptr || !*ptr)
1185 return 0;
1186
1187 int rc = 0;
1188 struct Message *msg = *ptr;
1189
1190 if (m->mx_ops && m->mx_ops->msg_close)
1191 rc = m->mx_ops->msg_close(m, msg);
1192
1193 if (msg->path)
1194 {
1195 mutt_debug(LL_DEBUG1, "unlinking %s\n", msg->path);
1196 unlink(msg->path);
1197 }
1198
1199 message_free(ptr);
1200 return rc;
1201}
char * path
path to temp file
Definition message.h:36
int(* msg_close)(struct Mailbox *m, struct Message *msg)
Definition mxapi.h:258
+ 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 1208 of file mx.c.

1209{
1210 if ((req_size + 1) <= m->email_max)
1211 return;
1212
1213 // Step size to increase by
1214 // Larger mailboxes get a larger step (limited to 1000)
1215 const int grow = CLAMP(m->email_max, 25, 1000);
1216
1217 // Sanity checks
1218 req_size = ROUND_UP(req_size + 1, grow);
1219
1220 const size_t s = MAX(sizeof(struct Email *), sizeof(int));
1221 if ((req_size * s) < (m->email_max * s))
1222 {
1223 mutt_error("%s", strerror(ENOMEM));
1224 mutt_exit(1);
1225 }
1226
1227 if (m->emails)
1228 {
1229 MUTT_MEM_REALLOC(&m->emails, req_size, struct Email *);
1230 MUTT_MEM_REALLOC(&m->v2r, req_size, int);
1231 }
1232 else
1233 {
1234 m->emails = MUTT_MEM_CALLOC(req_size, struct Email *);
1235 m->v2r = MUTT_MEM_CALLOC(req_size, int);
1236 }
1237
1238 for (int i = m->email_max; i < req_size; i++)
1239 {
1240 m->emails[i] = NULL;
1241 m->v2r[i] = -1;
1242 }
1243
1244 m->email_max = req_size;
1245}
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:97
+ 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 1254 of file mx.c.

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

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

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

1314{
1315 return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1316}
+ 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 1323 of file mx.c.

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

1370{
1371 if (buf_is_empty(path))
1372 return -1;
1373
1374 for (size_t i = 0; i < 3; i++)
1375 {
1376 /* Look for !! ! - < > or ^ followed by / or NUL */
1377 if ((buf_at(path, 0) == '!') && (buf_at(path, 1) == '!'))
1378 {
1379 if (((buf_at(path, 2) == '/') || (buf_at(path, 2) == '\0')))
1380 {
1381 buf_inline_replace(path, 0, 2, LastFolder);
1382 }
1383 }
1384 else if ((buf_at(path, 0) == '+') || (buf_at(path, 0) == '='))
1385 {
1386 size_t folder_len = mutt_str_len(folder);
1387 if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1388 {
1389 path->data[0] = '/';
1390 buf_inline_replace(path, 0, 0, folder);
1391 }
1392 else
1393 {
1394 buf_inline_replace(path, 0, 1, folder);
1395 }
1396 }
1397 else if ((buf_at(path, 1) == '/') || (buf_at(path, 1) == '\0'))
1398 {
1399 if (buf_at(path, 0) == '!')
1400 {
1401 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1402 buf_inline_replace(path, 0, 1, c_spool_file);
1403 }
1404 else if (buf_at(path, 0) == '-')
1405 {
1406 buf_inline_replace(path, 0, 1, LastFolder);
1407 }
1408 else if (buf_at(path, 0) == '<')
1409 {
1410 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
1411 buf_inline_replace(path, 0, 1, c_record);
1412 }
1413 else if (buf_at(path, 0) == '>')
1414 {
1415 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
1416 buf_inline_replace(path, 0, 1, c_mbox);
1417 }
1418 else if (buf_at(path, 0) == '^')
1419 {
1420 buf_inline_replace(path, 0, 1, CurrentFolder);
1421 }
1422 else if (buf_at(path, 0) == '~')
1423 {
1424 buf_inline_replace(path, 0, 1, NeoMutt->home_dir);
1425 }
1426 }
1427 else if (buf_at(path, 0) == '@')
1428 {
1429 /* elm compatibility, @ expands alias to user name */
1430 struct AddressList *al = alias_lookup(buf_string(path));
1431 if (!al || TAILQ_EMPTY(al))
1432 break;
1433
1434 struct Email *e = email_new();
1435 e->env = mutt_env_new();
1436 mutt_addrlist_copy(&e->env->from, al, false);
1437 mutt_addrlist_copy(&e->env->to, al, false);
1439 email_free(&e);
1440 break;
1441 }
1442 else
1443 {
1444 break;
1445 }
1446 }
1447
1448 // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1449 // return -1;
1450
1452 if (type)
1453 *type = type2;
1454 const struct MxOps *ops = mx_get_ops(type2);
1455 if (!ops || !ops->path_canon)
1456 return -1;
1457
1458 if (ops->path_canon(path) < 0)
1459 {
1460 mutt_path_canon(path, NeoMutt->home_dir, true);
1461 }
1462
1463 return 0;
1464}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:774
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition alias.c:273
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:668
void buf_inline_replace(struct Buffer *buf, size_t pos, size_t len, const char *str)
Definition buffer.c:768
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:214
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:345
char * home_dir
User's home directory.
Definition neomutt.h:56
+ 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 1473 of file mx.c.

1474{
1475 if (!m)
1476 return -1;
1477
1478 struct Buffer *path = buf_pool_get();
1479
1480 if (m->realpath)
1481 buf_strcpy(path, m->realpath);
1482 else
1483 buf_strcpy(path, mailbox_path(m));
1484
1485 int rc = mx_path_canon(path, folder, &m->type);
1486
1488 buf_pool_release(&path);
1489
1490 if (rc >= 0)
1491 {
1492 m->mx_ops = mx_get_ops(m->type);
1493 buf_strcpy(&m->pathbuf, m->realpath);
1494 }
1495
1496 return rc;
1497}
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:1369
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition mailbox.h:80
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:79
+ 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 1507 of file mx.c.

1508{
1509 if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1510 return 0;
1511
1512 return m->mx_ops->msg_padding_size(m);
1513}
int(* msg_padding_size)(struct Mailbox *m)
Definition mxapi.h:270
+ 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 1521 of file mx.c.

1522{
1523 if (!m || !m->mx_ops || !m->realpath)
1524 return NULL;
1525
1526 struct Account **ap = NULL;
1528 {
1529 struct Account *a = *ap;
1530 if (a->type != m->type)
1531 continue;
1532
1533 if (m->mx_ops->ac_owns_path(a, m->realpath))
1534 return a;
1535 }
1536
1537 return NULL;
1538}
bool(* ac_owns_path)(struct Account *a, const char *path)
Definition mxapi.h:105
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 1546 of file mx.c.

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

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

1648{
1649 if (!path)
1650 return NULL;
1651
1652 struct Mailbox *m = mx_mbox_find2(path);
1653 if (m)
1654 return m;
1655
1656 m = mailbox_new();
1657 buf_strcpy(&m->pathbuf, path);
1658 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1659 mx_path_canon2(m, c_folder);
1660
1661 return m;
1662}
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:1615
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition mx.c:1473
+ 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 1670 of file mx.c.

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

1694{
1695 if (!name)
1696 return NULL;
1697
1698 struct Account **ap = NULL;
1700 {
1701 struct Account *a = *ap;
1702 struct Mailbox *m = mx_mbox_find_by_name_ac(a, name);
1703 if (m)
1704 return m;
1705 }
1706
1707 return NULL;
1708}
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:1670
+ 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 1719 of file mx.c.

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

1738{
1739 if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1740 return false;
1741
1742 return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1743}
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:120
+ 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 1754 of file mx.c.

1755{
1756 if (!m || !m->account)
1757 return -1;
1758
1759 struct Account *a = m->account;
1761 if (!keep_account && ARRAY_EMPTY(&a->mailboxes))
1762 {
1764 }
1765 return 0;
1766}
#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:476
+ 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 1773 of file mx.c.

1774{
1775 if (!m)
1776 return MX_STATUS_ERROR;
1777
1778 enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1779 if (rc != MX_STATUS_ERROR)
1780 {
1781 struct EventMailbox ev_m = { m };
1783 }
1784
1785 return rc;
1786}
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition mailbox.h:175
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:49
An Event that happened to a Mailbox.
Definition mailbox.h:189
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition mailbox.h:144
enum MxStatus(* mbox_check_stats)(struct Mailbox *m, CheckStatsFlags flags)
Definition mxapi.h:171
+ 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 1797 of file mx.c.

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

1811{
1812 return m ? m->type : MUTT_MAILBOX_ERROR;
1813}
+ 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 1821 of file mx.c.

1822{
1823 if (!m)
1824 return -1;
1825
1826 if (m->readonly)
1827 {
1828 mutt_error(_("Can't toggle write on a readonly mailbox"));
1829 return -1;
1830 }
1831
1832 if (m->dontwrite)
1833 {
1834 m->dontwrite = false;
1835 mutt_message(_("Changes to folder will be written on folder exit"));
1836 }
1837 else
1838 {
1839 m->dontwrite = true;
1840 mutt_message(_("Changes to folder will not be written"));
1841 }
1842
1843 struct EventMailbox ev_m = { m };
1845 return 0;
1846}
+ 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:2809
const struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition mbox.c:1716
const struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition notmuch.c:2535
const struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition mh.c:1241
const struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition pop.c:1183
const struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition imap.c:2604
const struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition compress.c:890
const struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition mbox.c:1746
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};