NeoMutt  2025-01-09-41-g086358
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 "imap/lib.h"
#include "key/lib.h"
#include "maildir/lib.h"
#include "mbox/lib.h"
#include "menu/lib.h"
#include "mh/lib.h"
#include "nntp/lib.h"
#include "pop/lib.h"
#include "question/lib.h"
#include "copy.h"
#include "external.h"
#include "globals.h"
#include "hook.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "muttlib.h"
#include "nntp/mdata.h"
#include "protos.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 MxOpsMxOps []
 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 127 of file mx.c.

128{
129 for (const struct MxOps **ops = MxOps; *ops; ops++)
130 if ((*ops)->type == type)
131 return *ops;
132
133 return NULL;
134}
Definition: mxapi.h:88
+ 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 141 of file mx.c.

142{
143 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
144 if (mutt_str_equal(str, c_spool_file))
145 return true;
146
147 struct Url *ua = url_parse(str);
148 struct Url *ub = url_parse(c_spool_file);
149
150 const bool is_spool = ua && ub && (ua->scheme == ub->scheme) &&
151 mutt_istr_equal(ua->host, ub->host) &&
152 mutt_istr_equal(ua->path, ub->path) &&
153 (!ua->user || !ub->user || mutt_str_equal(ua->user, ub->user));
154
155 url_free(&ua);
156 url_free(&ub);
157 return is_spool;
158}
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:672
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
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 170 of file mx.c.

171{
172 if (imap_path_probe(path, NULL) == MUTT_IMAP)
173 return imap_access(path);
174
175 return access(path, flags);
176}
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2344
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:462
+ 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 185 of file mx.c.

186{
187 if (!m)
188 return false;
189
190 struct stat st = { 0 };
191
192 m->append = true;
193 if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR))
194 {
196
197 if (m->type == MUTT_UNKNOWN)
198 {
199 if (flags & MUTT_APPEND)
200 {
202 }
203 else
204 {
205 mutt_error(_("%s is not a mailbox"), mailbox_path(m));
206 return false;
207 }
208 }
209
210 if (m->type == MUTT_MAILBOX_ERROR)
211 {
212 if (stat(mailbox_path(m), &st) == -1)
213 {
214 if (errno == ENOENT)
215 {
218 else
219 m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
220 flags |= MUTT_APPENDNEW;
221 }
222 else
223 {
224 mutt_perror("%s", mailbox_path(m));
225 return false;
226 }
227 }
228 else
229 {
230 return false;
231 }
232 }
233
234 m->mx_ops = mx_get_ops(m->type);
235 }
236
237 if (!m->mx_ops || !m->mx_ops->mbox_open_append)
238 return false;
239
240 const bool rc = m->mx_ops->mbox_open_append(m, flags);
241 m->opened++;
242 return rc;
243}
bool mutt_comp_can_append(struct Mailbox *m)
Can we append to this path?
Definition: compress.c:332
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:223
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition: mailbox.h:43
@ MUTT_COMPRESSED
Compressed file Mailbox type.
Definition: mailbox.h:53
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_perror(...)
Definition: logging2.h:93
#define _(a)
Definition: message.h:28
const struct MxOps * mx_get_ops(enum MailboxType type)
Get mailbox operations.
Definition: mx.c:127
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1325
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:42
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition: mxapi.h:46
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:109
const struct MxOps * mx_ops
MXAPI callback functions.
Definition: mailbox.h:107
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
int opened
Number of times mailbox is opened.
Definition: mailbox.h:128
bool(* mbox_open_append)(struct Mailbox *m, OpenMailboxFlags flags)
Definition: mxapi.h:147
+ 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 251 of file mx.c.

252{
253 if (!m)
254 return false;
255
256 if (m->account)
257 return true;
258
259 struct Account *a = mx_ac_find(m);
260 const bool new_account = !a;
261 if (new_account)
262 {
263 a = account_new(NULL, NeoMutt->sub);
264 a->type = m->type;
265 }
266 if (!mx_ac_add(a, m))
267 {
268 if (new_account)
269 {
270 account_free(&a);
271 }
272 return false;
273 }
274 if (new_account)
275 {
277 }
278 return true;
279}
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:143
bool mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1727
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1523
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition: neomutt.c:110
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:127
+ 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 288 of file mx.c.

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

415{
416 if (!m)
417 return;
418
419 m->opened--;
420 if (m->opened != 0)
421 return;
422
423 /* never announce that a mailbox we've just left has new mail.
424 * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
425 if (!m->peekonly)
427
428 if (m->mx_ops)
429 m->mx_ops->mbox_close(m);
430
434
435 if (m->emails)
436 {
437 for (int i = 0; i < m->msg_count; i++)
438 {
439 if (!m->emails[i])
440 break;
441 email_free(&m->emails[i]);
442 }
443 }
444
445 if (!m->visible)
446 {
447 mx_ac_remove(m, keep_account);
448 }
449}
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
void mutt_mailbox_set_notified(struct Mailbox *m)
Note when the user was last notified of new mail.
Definition: mutt_mailbox.c:304
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1744
struct HashTable * subj_hash
Hash Table: "subject" -> Email.
Definition: mailbox.h:124
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
Definition: mailbox.h:123
struct HashTable * label_hash
Hash Table: "x-labels" -> Email.
Definition: mailbox.h:125
bool visible
True if a result of "mailboxes".
Definition: mailbox.h:130
enum MxStatus(* mbox_close)(struct Mailbox *m)
Definition: mxapi.h:196
+ 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 456 of file mx.c.

457{
458 if (!m || !m->mx_ops || !m->mx_ops->mbox_sync)
459 return MX_STATUS_ERROR;
460
461 if (m->verbose)
462 {
463 /* L10N: Displayed before/as a mailbox is being synced */
464 mutt_message(_("Writing %s..."), mailbox_path(m));
465 }
466
467 enum MxStatus rc = m->mx_ops->mbox_sync(m);
468 if (rc != MX_STATUS_OK)
469 {
470 mutt_debug(LL_DEBUG2, "mbox_sync returned: %d\n", rc);
471 if ((rc == MX_STATUS_ERROR) && m->verbose)
472 {
473 /* L10N: Displayed if a mailbox sync fails */
474 mutt_error(_("Unable to write %s"), mailbox_path(m));
475 }
476 }
477
478 return rc;
479}
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition: mxapi.h:60
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:61
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:62
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition: mxapi.h:184
+ 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 487 of file mx.c.

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

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

907{
908 if (!m)
909 return MX_STATUS_ERROR;
910
911 enum MxStatus rc = MX_STATUS_OK;
912 int purge = 1;
913 int msgcount, deleted;
914
915 if (m->dontwrite)
916 {
917 struct Buffer *buf = buf_pool_get();
918 struct Buffer *tmp = buf_pool_get();
919
920 if (km_expand_key(km_find_func(MENU_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:226
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:233
@ NT_MAILBOX_UNTAG
Clear the 'last-tagged' pointer.
Definition: mailbox.h:192
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:190
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:191
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:47
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function's mapping in a Menu.
Definition: lib.c:483
bool km_expand_key(struct Keymap *map, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition: lib.c:451
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:842
@ MENU_INDEX
Index panel (list of emails)
Definition: type.h:51
+ 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", p ? buf_string(p->mailbox) : NONULL(Username), buf);
1094 }
1095 }
1096 else
1097 {
1098 message_free(&msg);
1099 }
1100
1101 return msg;
1102}
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
char * Username
User's login name.
Definition: globals.c:40
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define MMDF_SEP
Definition: lib.h:62
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:969
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:456
#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:37
An email address.
Definition: address.h:36
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
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
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
struct Message::@0 flags
Flags for the Message.
bool(* msg_open_new)(struct Mailbox *m, struct Message *msg, const struct Email *e)
Definition: mxapi.h:229
locale_t time_c_locale
Current locale but LC_TIME=C.
Definition: neomutt.h:48
+ 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 1109 of file mx.c.

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

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

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

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

1211{
1212 if ((req_size + 1) <= m->email_max)
1213 return;
1214
1215 // Step size to increase by
1216 // Larger mailboxes get a larger step (limited to 1000)
1217 const int grow = CLAMP(m->email_max, 25, 1000);
1218
1219 // Sanity checks
1220 req_size = ROUND_UP(req_size + 1, grow);
1221
1222 const size_t s = MAX(sizeof(struct Email *), sizeof(int));
1223 if ((req_size * s) < (m->email_max * s))
1224 {
1225 mutt_error("%s", strerror(ENOMEM));
1226 mutt_exit(1);
1227 }
1228
1229 if (m->emails)
1230 {
1231 MUTT_MEM_REALLOC(&m->emails, req_size, struct Email *);
1232 MUTT_MEM_REALLOC(&m->v2r, req_size, int);
1233 }
1234 else
1235 {
1236 m->emails = MUTT_MEM_CALLOC(req_size, struct Email *);
1237 m->v2r = MUTT_MEM_CALLOC(req_size, int);
1238 }
1239
1240 for (int i = m->email_max; i < req_size; i++)
1241 {
1242 m->emails[i] = NULL;
1243 m->v2r[i] = -1;
1244 }
1245
1246 m->email_max = req_size;
1247}
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:266
#define ROUND_UP(NUM, STEP)
Definition: memory.h:36
#define MUTT_MEM_CALLOC(n, type)
Definition: memory.h:40
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition: memory.h:43
#define MAX(a, b)
Definition: memory.h:31
#define CLAMP(val, lo, hi)
Definition: memory.h:33
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:98
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_path_is_empty()

int mx_path_is_empty ( struct Buffer path)

Is the mailbox empty.

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

Definition at line 1256 of file mx.c.

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

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

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

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

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

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

1476{
1477 if (!m)
1478 return -1;
1479
1480 struct Buffer *path = buf_pool_get();
1481
1482 if (m->realpath)
1483 buf_strcpy(path, m->realpath);
1484 else
1485 buf_strcpy(path, mailbox_path(m));
1486
1487 int rc = mx_path_canon(path, folder, &m->type);
1488
1490 buf_pool_release(&path);
1491
1492 if (rc >= 0)
1493 {
1494 m->mx_ops = mx_get_ops(m->type);
1495 buf_strcpy(&m->pathbuf, m->realpath);
1496 }
1497
1498 return rc;
1499}
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
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:1371
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

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

1524{
1525 if (!m || !m->mx_ops || !m->realpath)
1526 return NULL;
1527
1528 struct Account *np = NULL;
1529 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1530 {
1531 if (np->type != m->type)
1532 continue;
1533
1534 if (m->mx_ops->ac_owns_path(np, m->realpath))
1535 return np;
1536 }
1537
1538 return NULL;
1539}
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:782
bool(* ac_owns_path)(struct Account *a, const char *path)
Definition: mxapi.h:106
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:47
+ 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 1547 of file mx.c.

1548{
1549 if (!a || !path)
1550 return NULL;
1551
1552 struct MailboxNode *np = 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 STAILQ_FOREACH(np, &a->mailboxes, entries)
1565 {
1566 if (!use_url)
1567 {
1569 return np->mailbox;
1570 continue;
1571 }
1572
1573 url_free(&url_a);
1574 url_a = url_parse(np->mailbox->realpath);
1575 if (!url_a)
1576 continue;
1577
1578 if (!mutt_istr_equal(url_a->host, url_p->host))
1579 continue;
1580 if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1581 continue;
1582 if (a->type == MUTT_IMAP)
1583 {
1584 if (imap_mxcmp(url_a->path, url_p->path) == 0)
1585 break;
1586 }
1587 else
1588 {
1589 if (mutt_str_equal(url_a->path, url_p->path))
1590 break;
1591 }
1592 }
1593
1594done:
1595 url_free(&url_p);
1596 url_free(&url_a);
1597
1598 if (!np)
1599 return NULL;
1600 return np->mailbox;
1601}
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:548
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:390
struct MailboxList mailboxes
List of Mailboxes.
Definition: account.h:40
List of Mailboxes.
Definition: mailbox.h:166
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:167
+ 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 1609 of file mx.c.

1610{
1611 if (!path)
1612 return NULL;
1613
1614 struct Buffer *buf = buf_new(path);
1615 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1616 mx_path_canon(buf, c_folder, NULL);
1617
1618 struct Account *np = NULL;
1619 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1620 {
1621 struct Mailbox *m = mx_mbox_find(np, buf_string(buf));
1622 if (m)
1623 {
1624 buf_free(&buf);
1625 return m;
1626 }
1627 }
1628
1629 buf_free(&buf);
1630 return NULL;
1631}
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 1640 of file mx.c.

1641{
1642 if (!path)
1643 return NULL;
1644
1645 struct Mailbox *m = mx_mbox_find2(path);
1646 if (m)
1647 return m;
1648
1649 m = mailbox_new();
1650 buf_strcpy(&m->pathbuf, path);
1651 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1652 mx_path_canon2(m, c_folder);
1653
1654 return m;
1655}
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition: mailbox.c:68
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1609
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1475
+ 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 1663 of file mx.c.

1664{
1665 if (!a || !name)
1666 return NULL;
1667
1668 struct MailboxNode *np = NULL;
1669
1670 STAILQ_FOREACH(np, &a->mailboxes, entries)
1671 {
1672 if (mutt_str_equal(np->mailbox->name, name))
1673 return np->mailbox;
1674 }
1675
1676 return NULL;
1677}
char * name
A short name for the Mailbox.
Definition: mailbox.h:82
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_find_by_name()

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

Find a Mailbox with given name.

Parameters
nameName to search
Return values
ptrMailbox

Definition at line 1684 of file mx.c.

1685{
1686 if (!name)
1687 return NULL;
1688
1689 struct Account *np = NULL;
1690 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1691 {
1692 struct Mailbox *m = mx_mbox_find_by_name_ac(np, name);
1693 if (m)
1694 return m;
1695 }
1696
1697 return NULL;
1698}
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:1663
+ 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 1709 of file mx.c.

1710{
1711 if (!path_or_name)
1712 return NULL;
1713
1714 // Order is name first because you can create a Mailbox from
1715 // a path, but can't from a name. So fallback behavior creates
1716 // a new Mailbox for us.
1717 struct Mailbox *m = mx_mbox_find_by_name(path_or_name);
1718 if (!m)
1719 m = mx_path_resolve(path_or_name);
1720
1721 return m;
1722}
static struct Mailbox * mx_mbox_find_by_name(const char *name)
Find a Mailbox with given name.
Definition: mx.c:1684
+ 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 1727 of file mx.c.

1728{
1729 if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1730 return false;
1731
1732 return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1733}
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:121
+ 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 1744 of file mx.c.

1745{
1746 if (!m || !m->account)
1747 return -1;
1748
1749 struct Account *a = m->account;
1751 if (!keep_account && STAILQ_EMPTY(&a->mailboxes))
1752 {
1754 }
1755 return 0;
1756}
bool neomutt_account_remove(struct NeoMutt *n, const struct Account *a)
Remove an Account from the global list.
Definition: neomutt.c:133
#define STAILQ_EMPTY(head)
Definition: queue.h:382
+ 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 1763 of file mx.c.

1764{
1765 if (!m)
1766 return MX_STATUS_ERROR;
1767
1768 enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1769 if (rc != MX_STATUS_ERROR)
1770 {
1771 struct EventMailbox ev_m = { m };
1773 }
1774
1775 return rc;
1776}
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:185
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:199
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition: mailbox.h:145
enum MxStatus(* mbox_check_stats)(struct Mailbox *m, CheckStatsFlags flags)
Definition: mxapi.h:172
+ 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 1787 of file mx.c.

1788{
1789 if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1790 return 0;
1791
1792 return m->mx_ops->msg_save_hcache(m, e);
1793}
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Definition: mxapi.h:286
+ 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 1800 of file mx.c.

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

1812{
1813 if (!m)
1814 return -1;
1815
1816 if (m->readonly)
1817 {
1818 mutt_error(_("Can't toggle write on a readonly mailbox"));
1819 return -1;
1820 }
1821
1822 if (m->dontwrite)
1823 {
1824 m->dontwrite = false;
1825 mutt_message(_("Changes to folder will be written on folder exit"));
1826 }
1827 else
1828 {
1829 m->dontwrite = true;
1830 mutt_message(_("Changes to folder will not be written"));
1831 }
1832
1833 struct EventMailbox ev_m = { m };
1835 return 0;
1836}
+ 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 81 of file mx.c.

◆ 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:81
Mapping between user-readable string and a constant.
Definition: mapping.h:33

Data for the $mbox_type enumeration.

Definition at line 92 of file mx.c.

◆ MxOps

const struct MxOps* MxOps[]
static
Initial value:
= {
NULL,
}
const struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps -.
Definition: nntp.c:2808
const struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition: mbox.c:1712
const struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition: notmuch.c:2495
const struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1239
const struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1178
const struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition: imap.c:2402
const struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition: compress.c:884
const struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition: mbox.c:1742
const struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps -.
Definition: maildir.c:44

All the Mailbox backends.

Definition at line 101 of file mx.c.