NeoMutt  2023-05-17-33-gce4425
Teaching an old dog new tricks
DOXYGEN
mx.c File Reference

Mailbox multiplexor. More...

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

Go to the source code of this file.

Functions

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

Variables

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

Detailed Description

Mailbox multiplexor.

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

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

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

Definition in file mx.c.

Function Documentation

◆ mx_get_ops()

const struct MxOps * mx_get_ops ( enum MailboxType  type)

Get mailbox operations.

Parameters
typeMailbox type
Return values
ptrMailbox function
NULLError

Definition at line 142 of file mx.c.

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

◆ mutt_is_spool()

static bool mutt_is_spool ( const char *  str)
static

Is this the spool_file?

Parameters
strName to check
Return values
trueIt is the spool_file

Definition at line 156 of file mx.c.

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

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

◆ mx_open_mailbox_append()

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

Open a mailbox for appending.

Parameters
mMailbox
flagsFlags, see OpenMailboxFlags
Return values
trueSuccess
falseFailure

Definition at line 202 of file mx.c.

203{
204 if (!m)
205 return false;
206
207 struct stat st = { 0 };
208
209 m->append = true;
210 if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR))
211 {
213
214 if (m->type == MUTT_UNKNOWN)
215 {
216 if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
217 {
219 }
220 else
221 {
222 mutt_error(_("%s is not a mailbox"), mailbox_path(m));
223 return false;
224 }
225 }
226
227 if (m->type == MUTT_MAILBOX_ERROR)
228 {
229 if (stat(mailbox_path(m), &st) == -1)
230 {
231 if (errno == ENOENT)
232 {
233#ifdef USE_COMP_MBOX
236 else
237#endif
238 m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
239 flags |= MUTT_APPENDNEW;
240 }
241 else
242 {
244 return false;
245 }
246 }
247 else
248 {
249 return false;
250 }
251 }
252
253 m->mx_ops = mx_get_ops(m->type);
254 }
255
256 if (!m->mx_ops || !m->mx_ops->mbox_open_append)
257 return false;
258
259 const bool rc = m->mx_ops->mbox_open_append(m, flags);
260 m->opened++;
261 return rc;
262}
bool mutt_comp_can_append(struct Mailbox *m)
Can we append to this path?
Definition: compress.c:366
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:97
#define mutt_error(...)
Definition: logging2.h:87
#define mutt_perror(...)
Definition: logging2.h:88
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:209
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition: mailbox.h:43
@ MUTT_COMPRESSED
Compressed file Mailbox type.
Definition: mailbox.h:53
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
#define _(a)
Definition: message.h:28
const struct MxOps * mx_get_ops(enum MailboxType type)
Get mailbox operations.
Definition: mx.c:142
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1344
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND, but uses mutt_file_fopen() with mode "w" for mbox-style fo...
Definition: mxapi.h:66
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:63
#define MUTT_APPENDNEW
Set in mx_open_mailbox_append if the mailbox doesn't exist.
Definition: mxapi.h:70
bool append
Mailbox is opened in append mode.
Definition: mailbox.h: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:171
+ 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 270 of file mx.c.

271{
272 if (!m)
273 return false;
274
275 if (m->account)
276 return true;
277
278 struct Account *a = mx_ac_find(m);
279 const bool new_account = !a;
280 if (new_account)
281 {
282 a = account_new(NULL, NeoMutt->sub);
283 a->type = m->type;
284 }
285 if (!mx_ac_add(a, m))
286 {
287 if (new_account)
288 {
289 account_free(&a);
290 }
291 return false;
292 }
293 if (new_account)
294 {
296 }
297 return true;
298}
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:43
void account_free(struct Account **ptr)
Free an Account.
Definition: account.c:141
bool mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1781
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1580
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition: neomutt.c:84
A group of associated Mailboxes.
Definition: account.h:37
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:38
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h: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 307 of file mx.c.

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

434{
435 if (!m)
436 return;
437
438 m->opened--;
439 if (m->opened != 0)
440 return;
441
442 /* never announce that a mailbox we've just left has new mail.
443 * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
444 if (!m->peekonly)
446
447 if (m->mx_ops)
448 m->mx_ops->mbox_close(m);
449
453
454 if (m->emails)
455 {
456 for (int i = 0; i < m->msg_count; i++)
457 {
458 if (!m->emails[i])
459 break;
460 email_free(&m->emails[i]);
461 }
462 }
463
464 if (!m->visible)
465 {
466 mx_ac_remove(m, keep_account);
467 }
468}
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
void mutt_mailbox_set_notified(struct Mailbox *m)
Note when the user was last notified of new mail.
Definition: mutt_mailbox.c:312
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1798
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:220
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sync_mailbox()

static enum MxStatus sync_mailbox ( struct Mailbox m)
static

Save changes to disk.

Parameters
mMailbox
Return values
enumMxStatus

Definition at line 475 of file mx.c.

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

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

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

◆ mx_mbox_sync()

enum MxStatus mx_mbox_sync ( struct Mailbox m)

Save changes to mailbox.

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

Definition at line 934 of file mx.c.

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

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

1144{
1145 if (!m || !m->mx_ops)
1146 return MX_STATUS_ERROR;
1147
1148 enum MxStatus rc = m->mx_ops->mbox_check(m);
1149 if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1150 {
1152 }
1153
1154 return rc;
1155}
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:175
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:89
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:87
enum MxStatus(* mbox_check)(struct Mailbox *m)
Definition: mxapi.h:183
+ 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 1164 of file mx.c.

1165{
1166 if (!m || !e)
1167 return NULL;
1168
1169 if (!m->mx_ops || !m->mx_ops->msg_open)
1170 {
1171 mutt_debug(LL_DEBUG1, "function not implemented for mailbox type %d\n", m->type);
1172 return NULL;
1173 }
1174
1175 struct Message *msg = mutt_mem_calloc(1, sizeof(struct Message));
1176 if (!m->mx_ops->msg_open(m, msg, e))
1177 FREE(&msg);
1178
1179 return msg;
1180}
bool(* msg_open)(struct Mailbox *m, struct Message *msg, struct Email *e)
Definition: mxapi.h:237
+ 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 1189 of file mx.c.

1190{
1191 if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1192 return -1;
1193
1194 if (!(msg->write && m->append))
1195 {
1196 mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1197 return -1;
1198 }
1199
1200 return m->mx_ops->msg_commit(m, msg);
1201}
int(* msg_commit)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:268
+ Here is the caller graph for this function:

◆ mx_msg_close()

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

Close a message.

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

Definition at line 1210 of file mx.c.

1211{
1212 if (!m || !msg || !*msg)
1213 return 0;
1214
1215 int rc = 0;
1216
1217 if (m->mx_ops && m->mx_ops->msg_close)
1218 rc = m->mx_ops->msg_close(m, *msg);
1219
1220 if ((*msg)->path)
1221 {
1222 mutt_debug(LL_DEBUG1, "unlinking %s\n", (*msg)->path);
1223 unlink((*msg)->path);
1224 FREE(&(*msg)->path);
1225 }
1226
1227 FREE(&(*msg)->committed_path);
1228 FREE(msg);
1229 return rc;
1230}
int(* msg_close)(struct Mailbox *m, struct Message *msg)
Definition: mxapi.h:283
+ Here is the caller graph for this function:

◆ mx_alloc_memory()

void mx_alloc_memory ( struct Mailbox m)

Create storage for the emails.

Parameters
mMailbox

Definition at line 1236 of file mx.c.

1237{
1238 const int grow = 25;
1239 size_t s = MAX(sizeof(struct Email *), sizeof(int));
1240
1241 if (((m->email_max + grow) * s) < (m->email_max * s))
1242 {
1243 mutt_error(_("Out of memory"));
1244 mutt_exit(1);
1245 }
1246
1247 m->email_max += grow;
1248 if (m->emails)
1249 {
1250 mutt_mem_realloc(&m->emails, m->email_max * sizeof(struct Email *));
1251 mutt_mem_realloc(&m->v2r, m->email_max * sizeof(int));
1252 }
1253 else
1254 {
1255 m->emails = mutt_mem_calloc(m->email_max, sizeof(struct Email *));
1256 m->v2r = mutt_mem_calloc(m->email_max, sizeof(int));
1257 }
1258 for (int i = m->email_max - grow; i < m->email_max; i++)
1259 {
1260 if (i < m->email_max)
1261 {
1262 m->emails[i] = NULL;
1263 m->v2r[i] = -1;
1264 }
1265 }
1266}
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:241
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define MAX(a, b)
Definition: memory.h:30
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:98
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_path_is_empty()

int mx_path_is_empty ( const char *  path)

Is the mailbox empty.

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

Definition at line 1275 of file mx.c.

1276{
1277 if (!path || (*path == '\0'))
1278 return -1;
1279
1280 enum MailboxType type = mx_path_probe(path);
1281 const struct MxOps *ops = mx_get_ops(type);
1282 if (!ops || !ops->path_is_empty)
1283 return -1;
1284
1285 return ops->path_is_empty(path);
1286}
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
int(* path_is_empty)(const char *path)
Definition: mxapi.h:414
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mxapi.h:113
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_tags_edit()

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

Start the tag editor of the mailbox.

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

Definition at line 1297 of file mx.c.

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

1318{
1319 if (!m || !e || !tags)
1320 return -1;
1321
1322 if (m->mx_ops->tags_commit)
1323 return m->mx_ops->tags_commit(m, e, tags);
1324
1325 mutt_message(_("Folder doesn't support tagging, aborting"));
1326 return -1;
1327}
int(* tags_commit)(struct Mailbox *m, struct Email *e, const char *buf)
Definition: mxapi.h:344
+ 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 1334 of file mx.c.

1335{
1336 return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1337}
+ Here is the caller graph for this function:

◆ mx_path_probe()

enum MailboxType mx_path_probe ( const char *  path)

Find a mailbox that understands a path.

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

Definition at line 1344 of file mx.c.

1345{
1346 if (!path)
1347 return MUTT_UNKNOWN;
1348
1349 enum MailboxType rc = MUTT_UNKNOWN;
1350
1351 // First, search the non-local Mailbox types (is_local == false)
1352 for (const struct MxOps **ops = MxOps; *ops; ops++)
1353 {
1354 if ((*ops)->is_local)
1355 continue;
1356 rc = (*ops)->path_probe(path, NULL);
1357 if (rc != MUTT_UNKNOWN)
1358 return rc;
1359 }
1360
1361 struct stat st = { 0 };
1362 if (stat(path, &st) != 0)
1363 {
1364 mutt_debug(LL_DEBUG1, "unable to stat %s: %s (errno %d)\n", path, strerror(errno), errno);
1365 return MUTT_UNKNOWN;
1366 }
1367
1368 if (S_ISFIFO(st.st_mode))
1369 {
1370 mutt_error(_("Can't open %s: it is a pipe"), path);
1371 return MUTT_UNKNOWN;
1372 }
1373
1374 // Next, search the local Mailbox types (is_local == true)
1375 for (const struct MxOps **ops = MxOps; *ops; ops++)
1376 {
1377 if (!(*ops)->is_local)
1378 continue;
1379 rc = (*ops)->path_probe(path, &st);
1380 if (rc != MUTT_UNKNOWN)
1381 return rc;
1382 }
1383
1384 return rc;
1385}
+ Here is the caller graph for this function:

◆ mx_path_canon()

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

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

Definition at line 1390 of file mx.c.

1391{
1392 if (!buf)
1393 return -1;
1394
1395 for (size_t i = 0; i < 3; i++)
1396 {
1397 /* Look for !! ! - < > or ^ followed by / or NUL */
1398 if ((buf[0] == '!') && (buf[1] == '!'))
1399 {
1400 if (((buf[2] == '/') || (buf[2] == '\0')))
1401 {
1402 mutt_str_inline_replace(buf, buflen, 2, LastFolder);
1403 }
1404 }
1405 else if ((buf[0] == '+') || (buf[0] == '='))
1406 {
1407 size_t folder_len = mutt_str_len(folder);
1408 if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1409 {
1410 buf[0] = '/';
1411 mutt_str_inline_replace(buf, buflen, 0, folder);
1412 }
1413 else
1414 {
1415 mutt_str_inline_replace(buf, buflen, 1, folder);
1416 }
1417 }
1418 else if ((buf[1] == '/') || (buf[1] == '\0'))
1419 {
1420 if (buf[0] == '!')
1421 {
1422 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1423 mutt_str_inline_replace(buf, buflen, 1, c_spool_file);
1424 }
1425 else if (buf[0] == '-')
1426 {
1427 mutt_str_inline_replace(buf, buflen, 1, LastFolder);
1428 }
1429 else if (buf[0] == '<')
1430 {
1431 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
1432 mutt_str_inline_replace(buf, buflen, 1, c_record);
1433 }
1434 else if (buf[0] == '>')
1435 {
1436 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
1437 mutt_str_inline_replace(buf, buflen, 1, c_mbox);
1438 }
1439 else if (buf[0] == '^')
1440 {
1441 mutt_str_inline_replace(buf, buflen, 1, CurrentFolder);
1442 }
1443 else if (buf[0] == '~')
1444 {
1445 mutt_str_inline_replace(buf, buflen, 1, HomeDir);
1446 }
1447 }
1448 else if (buf[0] == '@')
1449 {
1450 /* elm compatibility, @ expands alias to user name */
1451 struct AddressList *al = alias_lookup(buf + 1);
1452 if (!al || TAILQ_EMPTY(al))
1453 break;
1454
1455 struct Email *e = email_new();
1456 e->env = mutt_env_new();
1457 mutt_addrlist_copy(&e->env->from, al, false);
1458 mutt_addrlist_copy(&e->env->to, al, false);
1459 mutt_default_save(buf, buflen, e);
1460 email_free(&e);
1461 break;
1462 }
1463 else
1464 {
1465 break;
1466 }
1467 }
1468
1469 // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1470 // return -1;
1471
1472 enum MailboxType type2 = mx_path_probe(buf);
1473 if (type)
1474 *type = type2;
1475 const struct MxOps *ops = mx_get_ops(type2);
1476 if (!ops || !ops->path_canon)
1477 return -1;
1478
1479 if (ops->path_canon(buf, buflen) < 0)
1480 {
1481 mutt_path_canon(buf, buflen, HomeDir, true);
1482 }
1483
1484 return 0;
1485}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:752
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:279
char * HomeDir
User's home directory.
Definition: globals.c:39
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:43
char * LastFolder
Previously selected mailbox.
Definition: globals.c:45
char * CurrentFolder
Currently selected mailbox.
Definition: globals.c:44
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:737
bool mutt_path_canon(char *buf, size_t buflen, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition: path.c:285
bool mutt_str_inline_replace(char *buf, size_t buflen, size_t xlen, const char *rstr)
Replace the beginning of a string.
Definition: string.c:940
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
#define TAILQ_EMPTY(head)
Definition: queue.h:721
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
int(* path_canon)(char *buf, size_t buflen)
Definition: mxapi.h:371
+ 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 1494 of file mx.c.

1495{
1496 if (!m)
1497 return -1;
1498
1499 char buf[PATH_MAX] = { 0 };
1500
1501 if (m->realpath)
1502 mutt_str_copy(buf, m->realpath, sizeof(buf));
1503 else
1504 mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
1505
1506 int rc = mx_path_canon(buf, sizeof(buf), folder, &m->type);
1507
1508 mutt_str_replace(&m->realpath, buf);
1509
1510 if (rc >= 0)
1511 {
1512 m->mx_ops = mx_get_ops(m->type);
1513 buf_strcpy(&m->pathbuf, m->realpath);
1514 }
1515
1516 return rc;
1517}
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
#define PATH_MAX
Definition: mutt.h:41
int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition: mx.c:1390
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_path_pretty()

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

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

Definition at line 1522 of file mx.c.

1523{
1524 if (!buf)
1525 return -1;
1526
1527 enum MailboxType type = mx_path_probe(buf);
1528 const struct MxOps *ops = mx_get_ops(type);
1529 if (!ops)
1530 return -1;
1531
1532 if (!ops->path_canon)
1533 return -1;
1534
1535 if (ops->path_canon(buf, buflen) < 0)
1536 return -1;
1537
1538 if (!ops->path_pretty)
1539 return -1;
1540
1541 if (ops->path_pretty(buf, buflen, folder) < 0)
1542 return -1;
1543
1544 return 0;
1545}
int(* path_pretty)(char *buf, size_t buflen, const char *folder)
Definition: mxapi.h:386
+ Here is the call graph for this function:

◆ mx_path_parent()

int mx_path_parent ( const char *  buf,
size_t  buflen 
)

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

Definition at line 1550 of file mx.c.

1551{
1552 if (!buf)
1553 return -1;
1554
1555 return 0;
1556}

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

1567{
1568 if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1569 return 0;
1570
1571 return m->mx_ops->msg_padding_size(m);
1572}
int(* msg_padding_size)(struct Mailbox *m)
Definition: mxapi.h:295
+ 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 1580 of file mx.c.

1581{
1582 if (!m || !m->mx_ops || !m->realpath)
1583 return NULL;
1584
1585 struct Account *np = NULL;
1586 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1587 {
1588 if (np->type != m->type)
1589 continue;
1590
1591 if (m->mx_ops->ac_owns_path(np, m->realpath))
1592 return np;
1593 }
1594
1595 return NULL;
1596}
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
bool(* ac_owns_path)(struct Account *a, const char *path)
Definition: mxapi.h:130
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
+ Here is the caller graph for this function:

◆ mx_mbox_find()

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

Find a Mailbox on an Account.

Parameters
aAccount to search
pathPath to find
Return values
ptrMailbox

Definition at line 1604 of file mx.c.

1605{
1606 if (!a || !path)
1607 return NULL;
1608
1609 struct MailboxNode *np = NULL;
1610 struct Url *url_p = NULL;
1611 struct Url *url_a = NULL;
1612
1613 const bool use_url = (a->type == MUTT_IMAP);
1614 if (use_url)
1615 {
1616 url_p = url_parse(path);
1617 if (!url_p)
1618 goto done;
1619 }
1620
1621 STAILQ_FOREACH(np, &a->mailboxes, entries)
1622 {
1623 if (!use_url)
1624 {
1626 return np->mailbox;
1627 continue;
1628 }
1629
1630 url_free(&url_a);
1631 url_a = url_parse(np->mailbox->realpath);
1632 if (!url_a)
1633 continue;
1634
1635 if (!mutt_istr_equal(url_a->host, url_p->host))
1636 continue;
1637 if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1638 continue;
1639 if (a->type == MUTT_IMAP)
1640 {
1641 if (imap_mxcmp(url_a->path, url_p->path) == 0)
1642 break;
1643 }
1644 else
1645 {
1646 if (mutt_str_equal(url_a->path, url_p->path))
1647 break;
1648 }
1649 }
1650
1651done:
1652 url_free(&url_p);
1653 url_free(&url_a);
1654
1655 if (!np)
1656 return NULL;
1657 return np->mailbox;
1658}
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:544
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
struct MailboxList mailboxes
List of Mailboxes.
Definition: account.h:41
List of Mailboxes.
Definition: mailbox.h:152
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:153
+ 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 1666 of file mx.c.

1667{
1668 if (!path)
1669 return NULL;
1670
1671 char buf[PATH_MAX] = { 0 };
1672 mutt_str_copy(buf, path, sizeof(buf));
1673 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1674 mx_path_canon(buf, sizeof(buf), c_folder, NULL);
1675
1676 struct Account *np = NULL;
1677 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1678 {
1679 struct Mailbox *m = mx_mbox_find(np, buf);
1680 if (m)
1681 return m;
1682 }
1683
1684 return NULL;
1685}
+ 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 1694 of file mx.c.

1695{
1696 if (!path)
1697 return NULL;
1698
1699 struct Mailbox *m = mx_mbox_find2(path);
1700 if (m)
1701 return m;
1702
1703 m = mailbox_new();
1704 buf_strcpy(&m->pathbuf, path);
1705 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1706 mx_path_canon2(m, c_folder);
1707
1708 return m;
1709}
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:1666
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1494
+ 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 1717 of file mx.c.

1718{
1719 if (!a || !name)
1720 return NULL;
1721
1722 struct MailboxNode *np = NULL;
1723
1724 STAILQ_FOREACH(np, &a->mailboxes, entries)
1725 {
1726 if (mutt_str_equal(np->mailbox->name, name))
1727 return np->mailbox;
1728 }
1729
1730 return NULL;
1731}
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 1738 of file mx.c.

1739{
1740 if (!name)
1741 return NULL;
1742
1743 struct Account *np = NULL;
1744 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1745 {
1746 struct Mailbox *m = mx_mbox_find_by_name_ac(np, name);
1747 if (m)
1748 return m;
1749 }
1750
1751 return NULL;
1752}
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:1717
+ 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 1763 of file mx.c.

1764{
1765 if (!path_or_name)
1766 return NULL;
1767
1768 // Order is name first because you can create a Mailbox from
1769 // a path, but can't from a name. So fallback behavior creates
1770 // a new Mailbox for us.
1771 struct Mailbox *m = mx_mbox_find_by_name(path_or_name);
1772 if (!m)
1773 m = mx_path_resolve(path_or_name);
1774
1775 return m;
1776}
static struct Mailbox * mx_mbox_find_by_name(const char *name)
Find a Mailbox with given name.
Definition: mx.c:1738
+ 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 1781 of file mx.c.

1782{
1783 if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1784 return false;
1785
1786 return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1787}
bool account_mailbox_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition: account.c:66
bool(* ac_add)(struct Account *a, struct Mailbox *m)
Definition: mxapi.h:145
+ 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 1798 of file mx.c.

1799{
1800 if (!m || !m->account)
1801 return -1;
1802
1803 struct Account *a = m->account;
1805 if (!keep_account && STAILQ_EMPTY(&a->mailboxes))
1806 {
1808 }
1809 return 0;
1810}
bool neomutt_account_remove(struct NeoMutt *n, const struct Account *a)
Remove an Account from the global list.
Definition: neomutt.c:106
#define STAILQ_EMPTY(head)
Definition: queue.h:348
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_check_stats()

enum MxStatus mx_mbox_check_stats ( struct Mailbox m,
uint8_t  flags 
)

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

Note
Emits: NT_MAILBOX_CHANGE

Definition at line 1817 of file mx.c.

1818{
1819 if (!m)
1820 return MX_STATUS_ERROR;
1821
1822 enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1823 if (rc != MX_STATUS_ERROR)
1824 {
1825 struct EventMailbox ev_m = { m };
1827 }
1828
1829 return rc;
1830}
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:171
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:49
An Event that happened to a Mailbox.
Definition: mailbox.h:185
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition: mailbox.h:143
enum MxStatus(* mbox_check_stats)(struct Mailbox *m, CheckStatsFlags flags)
Definition: mxapi.h:196
+ 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 1841 of file mx.c.

1842{
1843 if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1844 return 0;
1845
1846 return m->mx_ops->msg_save_hcache(m, e);
1847}
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Definition: mxapi.h:310
+ 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 1854 of file mx.c.

1855{
1856 return m ? m->type : MUTT_MAILBOX_ERROR;
1857}
+ 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 1865 of file mx.c.

1866{
1867 if (!m)
1868 return -1;
1869
1870 if (m->readonly)
1871 {
1872 mutt_error(_("Can't toggle write on a readonly mailbox"));
1873 return -1;
1874 }
1875
1876 if (m->dontwrite)
1877 {
1878 m->dontwrite = false;
1879 mutt_message(_("Changes to folder will be written on folder exit"));
1880 }
1881 else
1882 {
1883 m->dontwrite = true;
1884 mutt_message(_("Changes to folder will not be written"));
1885 }
1886
1887 struct EventMailbox ev_m = { m };
1889 return 0;
1890}
+ 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 88 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:88
Mapping between user-readable string and a constant.
Definition: mapping.h:32

Data for the $mbox_type enumeration.

Definition at line 99 of file mx.c.

◆ MxOps

const struct MxOps* MxOps[]
static
Initial value:
= {
NULL,
}
const struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps -.
Definition: nntp.c:2784
const struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition: mbox.c:1856
const struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition: notmuch.c:2487
const struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1240
const struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1197
const struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition: imap.c:2340
const struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition: compress.c:943
const struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition: mbox.c:1888
const struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps -.
Definition: maildir.c:1649

All the Mailbox backends.

Definition at line 108 of file mx.c.