NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
mx.c File Reference

Mailbox multiplexor. More...

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

Go to the source code of this file.

Functions

const struct MxOpsmx_get_ops (enum MailboxType type)
 Get mailbox operations. More...
 
static bool mutt_is_spool (const char *str)
 Is this the spool_file? More...
 
int mx_access (const char *path, int flags)
 Wrapper for access, checks permissions on a given mailbox. More...
 
static bool mx_open_mailbox_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a mailbox for appending. More...
 
bool mx_mbox_ac_link (struct Mailbox *m)
 Link a Mailbox to an existing or new Account. More...
 
bool mx_mbox_open (struct Mailbox *m, OpenMailboxFlags flags)
 Open a mailbox and parse it. More...
 
void mx_fastclose_mailbox (struct Mailbox *m, 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, int msgno)
 Return a stream pointer for a message. More...
 
int mx_msg_commit (struct Mailbox *m, struct Message *msg)
 Commit a message to a folder - Wrapper for MxOps::msg_commit() More...
 
int mx_msg_close (struct Mailbox *m, struct Message **msg)
 Close a message. More...
 
void mx_alloc_memory (struct Mailbox *m)
 Create storage for the emails. More...
 
int mx_path_is_empty (const char *path)
 Is the mailbox empty. More...
 
int mx_tags_edit (struct Mailbox *m, const char *tags, 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 []
 
struct EnumDef MboxTypeDef
 
const struct MxOpsMxOps []
 All the Mailbox backends. More...
 

Detailed Description

Mailbox multiplexor.

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

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

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

Definition in file mx.c.

Function Documentation

◆ mx_get_ops()

const struct MxOps * mx_get_ops ( enum MailboxType  type)

Get mailbox operations.

Parameters
typeMailbox type
Return values
ptrMailbox function
NULLError

Definition at line 141 of file mx.c.

142{
143 for (const struct MxOps **ops = MxOps; *ops; ops++)
144 if ((*ops)->type == type)
145 return *ops;
146
147 return NULL;
148}
Definition: mxapi.h: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 155 of file mx.c.

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

185{
186#ifdef USE_IMAP
187 if (imap_path_probe(path, NULL) == MUTT_IMAP)
188 return imap_access(path);
189#endif
190
191 return access(path, flags);
192}
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2400
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:473
@ 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 201 of file mx.c.

202{
203 if (!m)
204 return false;
205
206 struct stat st = { 0 };
207
208 m->append = true;
209 if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR))
210 {
212
213 if (m->type == MUTT_UNKNOWN)
214 {
215 if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
216 {
218 }
219 else
220 {
221 mutt_error(_("%s is not a mailbox"), mailbox_path(m));
222 return false;
223 }
224 }
225
226 if (m->type == MUTT_MAILBOX_ERROR)
227 {
228 if (stat(mailbox_path(m), &st) == -1)
229 {
230 if (errno == ENOENT)
231 {
232#ifdef USE_COMP_MBOX
235 else
236#endif
237 m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
238 flags |= MUTT_APPENDNEW;
239 }
240 else
241 {
243 return false;
244 }
245 }
246 else
247 return false;
248 }
249
250 m->mx_ops = mx_get_ops(m->type);
251 }
252
253 if (!m->mx_ops || !m->mx_ops->mbox_open_append)
254 return false;
255
256 const bool rc = m->mx_ops->mbox_open_append(m, flags);
257 m->opened++;
258 return rc;
259}
bool mutt_comp_can_append(struct Mailbox *m)
Can we append to this path?
Definition: compress.c:362
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: logging.h:87
#define mutt_perror(...)
Definition: logging.h:88
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
@ 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:141
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1327
#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:175
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_ac_link()

bool mx_mbox_ac_link ( struct Mailbox m)

Link a Mailbox to an existing or new Account.

Parameters
mMailbox to link
Return values
trueSuccess
falseFailure

Definition at line 267 of file mx.c.

268{
269 if (!m)
270 return false;
271
272 if (m->account)
273 return true;
274
275 struct Account *a = mx_ac_find(m);
276 const bool new_account = !a;
277 if (new_account)
278 {
279 a = account_new(NULL, NeoMutt->sub);
280 a->type = m->type;
281 }
282 if (!mx_ac_add(a, m))
283 {
284 if (new_account)
285 {
286 account_free(&a);
287 }
288 return false;
289 }
290 if (new_account)
291 {
293 }
294 return true;
295}
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:43
void account_free(struct Account **ptr)
Free an Account.
Definition: account.c: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:1764
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1563
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 304 of file mx.c.

305{
306 if (!m)
307 return false;
308
309 if ((m->type == MUTT_UNKNOWN) && (flags & (MUTT_NEWFOLDER | MUTT_APPEND)))
310 {
311 m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
312 m->mx_ops = mx_get_ops(m->type);
313 }
314
315 const bool newly_linked_account = !m->account;
316 if (newly_linked_account)
317 {
318 if (!mx_mbox_ac_link(m))
319 {
320 return false;
321 }
322 }
323
324 m->verbose = !(flags & MUTT_QUIET);
325 m->readonly = (flags & MUTT_READONLY);
326 m->peekonly = (flags & MUTT_PEEK);
327
328 if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
329 {
330 if (!mx_open_mailbox_append(m, flags))
331 {
332 goto error;
333 }
334 return true;
335 }
336
337 if (m->opened > 0)
338 {
339 m->opened++;
340 return true;
341 }
342
343 m->size = 0;
344 m->msg_unread = 0;
345 m->msg_flagged = 0;
346 m->rights = MUTT_ACL_ALL;
347
348 if (m->type == MUTT_UNKNOWN)
349 {
351 m->mx_ops = mx_get_ops(m->type);
352 }
353
354 if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR) || !m->mx_ops)
355 {
356 if (m->type == MUTT_MAILBOX_ERROR)
358 else if ((m->type == MUTT_UNKNOWN) || !m->mx_ops)
359 mutt_error(_("%s is not a mailbox"), mailbox_path(m));
360 goto error;
361 }
362
364
365 /* if the user has a 'push' command in their .neomuttrc, or in a folder-hook,
366 * it will cause the progress messages not to be displayed because
367 * mutt_refresh() will think we are in the middle of a macro. so set a
368 * flag to indicate that we should really refresh the screen. */
369 OptForceRefresh = true;
370
371 if (m->verbose)
372 mutt_message(_("Reading %s..."), mailbox_path(m));
373
374 // Clear out any existing emails
375 for (int i = 0; i < m->email_max; i++)
376 {
377 email_free(&m->emails[i]);
378 }
379
380 m->msg_count = 0;
381 m->msg_unread = 0;
382 m->msg_flagged = 0;
383 m->msg_new = 0;
384 m->msg_deleted = 0;
385 m->msg_tagged = 0;
386 m->vcount = 0;
387
388 enum MxOpenReturns rc = m->mx_ops->mbox_open(m);
389 m->opened++;
390
391 if ((rc == MX_OPEN_OK) || (rc == MX_OPEN_ABORT))
392 {
393 if ((flags & MUTT_NOSORT) == 0)
394 {
395 /* avoid unnecessary work since the mailbox is completely unthreaded
396 * to begin with */
397 OptSortSubthreads = false;
398 OptNeedRescore = false;
399 }
400 if (m->verbose)
402 if (rc == MX_OPEN_ABORT)
403 {
404 mutt_error(_("Reading from %s interrupted..."), mailbox_path(m));
405 }
406 }
407 else
408 {
409 goto error;
410 }
411
412 if (!m->peekonly)
413 m->has_new = false;
414 OptForceRefresh = false;
415
416 return true;
417
418error:
419 mx_fastclose_mailbox(m, newly_linked_account);
420 if (newly_linked_account)
422 return false;
423}
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:96
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
#define mutt_message(...)
Definition: logging.h:86
#define MUTT_ACL_ALL
Definition: mailbox.h:73
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition: mutt_header.c:371
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:430
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:267
static bool mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox for appending.
Definition: mx.c:201
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h: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
bool OptNeedRescore
(pseudo) set when the 'score' command is used
Definition: options.h:47
bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:42
bool OptSortSubthreads
(pseudo) used when $sort_aux changes
Definition: options.h:59
int vcount
The number of virtual messages.
Definition: mailbox.h: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:160
+ 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 430 of file mx.c.

431{
432 if (!m)
433 return;
434
435 m->opened--;
436 if (m->opened != 0)
437 return;
438
439 /* never announce that a mailbox we've just left has new mail.
440 * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
441 if (!m->peekonly)
443
444 if (m->mx_ops)
445 m->mx_ops->mbox_close(m);
446
450
451 if (m->emails)
452 {
453 for (int i = 0; i < m->msg_count; i++)
454 {
455 if (!m->emails[i])
456 break;
457 email_free(&m->emails[i]);
458 }
459 }
460
461 if (!m->visible)
462 {
463 mx_ac_remove(m, keep_account);
464 }
465}
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:1781
struct HashTable * subj_hash
Hash Table by subject.
Definition: mailbox.h:124
struct HashTable * id_hash
Hash Table by msg id.
Definition: mailbox.h:123
struct HashTable * label_hash
Hash Table for x-labels.
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:228
+ 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 472 of file mx.c.

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

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

616{
617 if (!m)
618 return MX_STATUS_ERROR;
619
620 const bool c_mail_check_recent = cs_subset_bool(NeoMutt->sub, "mail_check_recent");
621 if (c_mail_check_recent && !m->peekonly)
622 m->has_new = false;
623
624 if (m->readonly || m->dontwrite || m->append || m->peekonly)
625 {
626 mx_fastclose_mailbox(m, false);
627 return 0;
628 }
629
630 int i, read_msgs = 0;
631 enum MxStatus rc = MX_STATUS_ERROR;
632 enum QuadOption move_messages = MUTT_NO;
633 enum QuadOption purge = MUTT_YES;
634 struct Buffer *mbox = NULL;
635 struct Buffer *buf = mutt_buffer_pool_get();
636
637#ifdef USE_NNTP
638 if ((m->msg_unread != 0) && (m->type == MUTT_NNTP))
639 {
640 struct NntpMboxData *mdata = m->mdata;
641
642 if (mdata && mdata->adata && mdata->group)
643 {
644 const enum QuadOption c_catchup_newsgroup = cs_subset_quad(NeoMutt->sub, "catchup_newsgroup");
645 enum QuadOption ans = query_quadoption(c_catchup_newsgroup,
646 _("Mark all articles read?"));
647 if (ans == MUTT_ABORT)
648 goto cleanup;
649 if (ans == MUTT_YES)
650 mutt_newsgroup_catchup(m, mdata->adata, mdata->group);
651 }
652 }
653#endif
654
655 const bool c_keep_flagged = cs_subset_bool(NeoMutt->sub, "keep_flagged");
656 for (i = 0; i < m->msg_count; i++)
657 {
658 struct Email *e = m->emails[i];
659 if (!e)
660 break;
661
662 if (!e->deleted && e->read && !(e->flagged && c_keep_flagged))
663 read_msgs++;
664 }
665
666#ifdef USE_NNTP
667 /* don't need to move articles from newsgroup */
668 if (m->type == MUTT_NNTP)
669 read_msgs = 0;
670#endif
671
672 const enum QuadOption c_move = cs_subset_quad(NeoMutt->sub, "move");
673 if ((read_msgs != 0) && (c_move != MUTT_NO))
674 {
675 bool is_spool;
676 mbox = mutt_buffer_pool_get();
677
679 if (p)
680 {
681 is_spool = true;
682 mutt_buffer_strcpy(mbox, p);
683 }
684 else
685 {
686 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
687 mutt_buffer_strcpy(mbox, c_mbox);
688 is_spool = mutt_is_spool(mailbox_path(m)) &&
690 }
691
692 if (is_spool && !mutt_buffer_is_empty(mbox))
693 {
696 /* L10N: The first argument is the number of read messages to be
697 moved, the second argument is the target mailbox. */
698 ngettext("Move %d read message to %s?",
699 "Move %d read messages to %s?", read_msgs),
700 read_msgs, mutt_buffer_string(mbox));
701 move_messages = query_quadoption(c_move, mutt_buffer_string(buf));
702 if (move_messages == MUTT_ABORT)
703 goto cleanup;
704 }
705 }
706
707 /* There is no point in asking whether or not to purge if we are
708 * just marking messages as "trash". */
709 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
710 if ((m->msg_deleted != 0) && !((m->type == MUTT_MAILDIR) && c_maildir_trash))
711 {
713 ngettext("Purge %d deleted message?",
714 "Purge %d deleted messages?", m->msg_deleted),
715 m->msg_deleted);
716 const enum QuadOption c_delete = cs_subset_quad(NeoMutt->sub, "delete");
717 purge = query_quadoption(c_delete, mutt_buffer_string(buf));
718 if (purge == MUTT_ABORT)
719 goto cleanup;
720 }
721
722 const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
723 if (c_mark_old && !m->peekonly)
724 {
725 for (i = 0; i < m->msg_count; i++)
726 {
727 struct Email *e = m->emails[i];
728 if (!e)
729 break;
730 if (!e->deleted && !e->old && !e->read)
731 mutt_set_flag(m, e, MUTT_OLD, true);
732 }
733 }
734
735 if (move_messages)
736 {
737 if (m->verbose)
738 mutt_message(_("Moving read messages to %s..."), mutt_buffer_string(mbox));
739
740#ifdef USE_IMAP
741 /* try to use server-side copy first */
742 i = 1;
743
744 if ((m->type == MUTT_IMAP) && (imap_path_probe(mutt_buffer_string(mbox), NULL) == MUTT_IMAP))
745 {
746 /* add messages for moving, and clear old tags, if any */
747 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
748 for (i = 0; i < m->msg_count; i++)
749 {
750 struct Email *e = m->emails[i];
751 if (!e)
752 break;
753
754 if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
755 {
756 e->tagged = true;
757 emaillist_add_email(&el, e);
758 }
759 else
760 e->tagged = false;
761 }
762
764 emaillist_clear(&el);
765 }
766
767 if (i == 0) /* success */
769 else if (i == -1) /* horrible error, bail */
770 goto cleanup;
771 else /* use regular append-copy mode */
772#endif
773 {
774 struct Mailbox *m_read = mx_path_resolve(mutt_buffer_string(mbox));
775 if (!mx_mbox_open(m_read, MUTT_APPEND))
776 {
777 mailbox_free(&m_read);
778 goto cleanup;
779 }
780
781 for (i = 0; i < m->msg_count; i++)
782 {
783 struct Email *e = m->emails[i];
784 if (!e)
785 break;
786 if (e->read && !e->deleted && !(e->flagged && c_keep_flagged))
787 {
788 if (mutt_append_message(m_read, m, e, NULL, MUTT_CM_NO_FLAGS, CH_UPDATE_LEN) == 0)
789 {
790 mutt_set_flag(m, e, MUTT_DELETE, true);
791 mutt_set_flag(m, e, MUTT_PURGE, true);
792 }
793 else
794 {
795 mx_mbox_close(m_read);
796 goto cleanup;
797 }
798 }
799 }
800
801 mx_mbox_close(m_read);
802 }
803 }
804 else if (!m->changed && (m->msg_deleted == 0))
805 {
806 if (m->verbose)
807 mutt_message(_("Mailbox is unchanged"));
808 if ((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF))
809 mbox_reset_atime(m, NULL);
810 mx_fastclose_mailbox(m, false);
811 rc = MX_STATUS_OK;
812 goto cleanup;
813 }
814
815 /* copy mails to the trash before expunging */
816 const char *const c_trash = cs_subset_string(NeoMutt->sub, "trash");
817 const struct Mailbox *m_trash = mx_mbox_find(m->account, c_trash);
818 if (purge && (m->msg_deleted != 0) && (m != m_trash))
819 {
820 if (trash_append(m) != 0)
821 goto cleanup;
822 }
823
824#ifdef USE_IMAP
825 /* allow IMAP to preserve the deleted flag across sessions */
826 if (m->type == MUTT_IMAP)
827 {
828 const enum MxStatus check = imap_sync_mailbox(m, (purge != MUTT_NO), true);
829 if (check == MX_STATUS_ERROR)
830 {
831 rc = check;
832 goto cleanup;
833 }
834 }
835 else
836#endif
837 {
838 if (purge == MUTT_NO)
839 {
840 for (i = 0; i < m->msg_count; i++)
841 {
842 struct Email *e = m->emails[i];
843 if (!e)
844 break;
845
846 e->deleted = false;
847 e->purge = false;
848 }
849 m->msg_deleted = 0;
850 }
851
852 if (m->changed || (m->msg_deleted != 0))
853 {
854 enum MxStatus check = sync_mailbox(m);
855 if (check != MX_STATUS_OK)
856 {
857 rc = check;
858 goto cleanup;
859 }
860 }
861 }
862
863 if (m->verbose)
864 {
865 if (move_messages)
866 {
867 mutt_message(_("%d kept, %d moved, %d deleted"),
868 m->msg_count - m->msg_deleted, read_msgs, m->msg_deleted);
869 }
870 else
871 mutt_message(_("%d kept, %d deleted"), m->msg_count - m->msg_deleted, m->msg_deleted);
872 }
873
874 const bool c_save_empty = cs_subset_bool(NeoMutt->sub, "save_empty");
875 if ((m->msg_count == m->msg_deleted) &&
876 ((m->type == MUTT_MMDF) || (m->type == MUTT_MBOX)) &&
877 !mutt_is_spool(mailbox_path(m)) && !c_save_empty)
878 {
880 }
881
882#ifdef USE_SIDEBAR
883 if ((purge == MUTT_YES) && (m->msg_deleted != 0))
884 {
885 for (i = 0; i < m->msg_count; i++)
886 {
887 struct Email *e = m->emails[i];
888 if (!e)
889 break;
890 if (e->deleted && !e->read)
891 {
892 m->msg_unread--;
893 if (!e->old)
894 m->msg_new--;
895 }
896 if (e->deleted && e->flagged)
897 m->msg_flagged--;
898 }
899 }
900#endif
901
902 mx_fastclose_mailbox(m, false);
903
904 rc = MX_STATUS_OK;
905
906cleanup:
909 return rc;
910}
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: commands.h:51
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
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:159
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:138
void mutt_file_unlink_empty(const char *path)
Delete a file if it's empty.
Definition: file.c:1367
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 EmailList *el, const char *dest, enum MessageSaveOpt save_opt)
Server COPY messages to another folder.
Definition: message.c:1683
enum MxStatus imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
Sync all the changes to the server.
Definition: imap.c:1534
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h: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:843
@ MUTT_OLD
Old messages.
Definition: mutt.h:91
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:97
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:95
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
static enum MxStatus sync_mailbox(struct Mailbox *m)
Save changes to disk.
Definition: mx.c:472
static int trash_append(struct Mailbox *m)
Move deleted mails to the trash folder.
Definition: mx.c:503
static bool mutt_is_spool(const char *str)
Is this the spool_file?
Definition: mx.c:155
struct Mailbox * mx_mbox_find(struct Account *a, const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1587
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1323
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:63
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
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
String manipulation buffer.
Definition: buffer.h:34
bool read
Email is read.
Definition: email.h:48
bool old
Email is seen, but unread.
Definition: email.h:47
bool flagged
Marked important?
Definition: email.h:45
bool tagged
Email is tagged.
Definition: email.h:107
bool changed
Mailbox has been modified.
Definition: mailbox.h: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 919 of file mx.c.

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

1058{
1059 if (!m)
1060 return NULL;
1061
1062 struct Address *p = NULL;
1063 struct Message *msg = NULL;
1064
1065 if (!m->mx_ops || !m->mx_ops->msg_open_new)
1066 {
1067 mutt_debug(LL_DEBUG1, "function unimplemented for mailbox type %d\n", m->type);
1068 return NULL;
1069 }
1070
1071 msg = mutt_mem_calloc(1, sizeof(struct Message));
1072 msg->write = true;
1073
1074 if (e)
1075 {
1076 msg->flags.flagged = e->flagged;
1077 msg->flags.replied = e->replied;
1078 msg->flags.read = e->read;
1079 msg->flags.draft = (flags & MUTT_SET_DRAFT);
1080 msg->received = e->received;
1081 }
1082
1083 if (msg->received == 0)
1084 msg->received = mutt_date_epoch();
1085
1086 if (m->mx_ops->msg_open_new(m, msg, e))
1087 {
1088 if (m->type == MUTT_MMDF)
1089 fputs(MMDF_SEP, msg->fp);
1090
1091 if (((m->type == MUTT_MBOX) || (m->type == MUTT_MMDF)) && (flags & MUTT_ADD_FROM))
1092 {
1093 if (e)
1094 {
1095 p = TAILQ_FIRST(&e->env->return_path);
1096 if (!p)
1097 p = TAILQ_FIRST(&e->env->sender);
1098 if (!p)
1099 p = TAILQ_FIRST(&e->env->from);
1100 }
1101
1102 // Force a 'C' locale for the date, so that day/month names are in English
1103 char buf[64] = { 0 };
1104 struct tm tm = mutt_date_localtime(msg->received);
1105#ifdef LC_TIME_MASK
1106 locale_t loc = newlocale(LC_TIME_MASK, "C", 0);
1107 strftime_l(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", &tm, loc);
1108 freelocale(loc);
1109#else /* !LC_TIME_MASK */
1110 strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", &tm);
1111#endif /* LC_TIME_MASK */
1112 fprintf(msg->fp, "From %s %s\n", p ? p->mailbox : NONULL(Username), buf);
1113 }
1114 }
1115 else
1116 FREE(&msg);
1117
1118 return msg;
1119}
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:655
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.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
char * Username
User's login name.
Definition: mutt_globals.h:52
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:43
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:44
#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:263
+ 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 1126 of file mx.c.

1127{
1128 if (!m || !m->mx_ops)
1129 return MX_STATUS_ERROR;
1130
1131 enum MxStatus rc = m->mx_ops->mbox_check(m);
1132 if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1133 {
1135 }
1136
1137 return rc;
1138}
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:176
@ 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:188
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_msg_open()

struct Message * mx_msg_open ( struct Mailbox m,
int  msgno 
)

Return a stream pointer for a message.

Parameters
mMailbox
msgnoMessage number
Return values
ptrMessage
NULLError

Definition at line 1147 of file mx.c.

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

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

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

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

1259{
1260 if (!path || (*path == '\0'))
1261 return -1;
1262
1263 enum MailboxType type = mx_path_probe(path);
1264 const struct MxOps *ops = mx_get_ops(type);
1265 if (!ops || !ops->path_is_empty)
1266 return -1;
1267
1268 return ops->path_is_empty(path);
1269}
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
int(* path_is_empty)(const char *path)
Definition: mxapi.h:435
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 1280 of file mx.c.

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

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

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

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

1374{
1375 if (!buf)
1376 return -1;
1377
1378 for (size_t i = 0; i < 3; i++)
1379 {
1380 /* Look for !! ! - < > or ^ followed by / or NUL */
1381 if ((buf[0] == '!') && (buf[1] == '!'))
1382 {
1383 if (((buf[2] == '/') || (buf[2] == '\0')))
1384 {
1385 mutt_str_inline_replace(buf, buflen, 2, LastFolder);
1386 }
1387 }
1388 else if ((buf[0] == '+') || (buf[0] == '='))
1389 {
1390 size_t folder_len = mutt_str_len(folder);
1391 if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1392 {
1393 buf[0] = '/';
1394 mutt_str_inline_replace(buf, buflen, 0, folder);
1395 }
1396 else
1397 {
1398 mutt_str_inline_replace(buf, buflen, 1, folder);
1399 }
1400 }
1401 else if ((buf[1] == '/') || (buf[1] == '\0'))
1402 {
1403 if (buf[0] == '!')
1404 {
1405 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1406 mutt_str_inline_replace(buf, buflen, 1, c_spool_file);
1407 }
1408 else if (buf[0] == '-')
1409 {
1410 mutt_str_inline_replace(buf, buflen, 1, LastFolder);
1411 }
1412 else if (buf[0] == '<')
1413 {
1414 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
1415 mutt_str_inline_replace(buf, buflen, 1, c_record);
1416 }
1417 else if (buf[0] == '>')
1418 {
1419 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
1420 mutt_str_inline_replace(buf, buflen, 1, c_mbox);
1421 }
1422 else if (buf[0] == '^')
1423 {
1424 mutt_str_inline_replace(buf, buflen, 1, CurrentFolder);
1425 }
1426 else if (buf[0] == '~')
1427 {
1428 mutt_str_inline_replace(buf, buflen, 1, HomeDir);
1429 }
1430 }
1431 else if (buf[0] == '@')
1432 {
1433 /* elm compatibility, @ expands alias to user name */
1434 struct AddressList *al = alias_lookup(buf + 1);
1435 if (!al || TAILQ_EMPTY(al))
1436 break;
1437
1438 struct Email *e = email_new();
1439 e->env = mutt_env_new();
1440 mutt_addrlist_copy(&e->env->from, al, false);
1441 mutt_addrlist_copy(&e->env->to, al, false);
1442 mutt_default_save(buf, buflen, e);
1443 email_free(&e);
1444 break;
1445 }
1446 else
1447 {
1448 break;
1449 }
1450 }
1451
1452 // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1453 // return -1;
1454
1455 enum MailboxType type2 = mx_path_probe(buf);
1456 if (type)
1457 *type = type2;
1458 const struct MxOps *ops = mx_get_ops(type2);
1459 if (!ops || !ops->path_canon)
1460 return -1;
1461
1462 if (ops->path_canon(buf, buflen) < 0)
1463 {
1464 mutt_path_canon(buf, buflen, HomeDir, true);
1465 }
1466
1467 return 0;
1468}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:280
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
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
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:949
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
#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:389
+ 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 1477 of file mx.c.

1478{
1479 if (!m)
1480 return -1;
1481
1482 char buf[PATH_MAX] = { 0 };
1483
1484 if (m->realpath)
1485 mutt_str_copy(buf, m->realpath, sizeof(buf));
1486 else
1487 mutt_str_copy(buf, mailbox_path(m), sizeof(buf));
1488
1489 int rc = mx_path_canon(buf, sizeof(buf), folder, &m->type);
1490
1491 mutt_str_replace(&m->realpath, buf);
1492
1493 if (rc >= 0)
1494 {
1495 m->mx_ops = mx_get_ops(m->type);
1497 }
1498
1499 return rc;
1500}
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
#define PATH_MAX
Definition: mutt.h:40
int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition: mx.c:1373
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 1505 of file mx.c.

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

1534{
1535 if (!buf)
1536 return -1;
1537
1538 return 0;
1539}

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

1550{
1551 if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1552 return 0;
1553
1554 return m->mx_ops->msg_padding_size(m);
1555}
int(* msg_padding_size)(struct Mailbox *m)
Definition: mxapi.h:308
+ 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 1563 of file mx.c.

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

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

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

1678{
1679 if (!path)
1680 return NULL;
1681
1682 struct Mailbox *m = mx_mbox_find2(path);
1683 if (m)
1684 return m;
1685
1686 m = mailbox_new();
1687 mutt_buffer_strcpy(&m->pathbuf, path);
1688 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1689 mx_path_canon2(m, c_folder);
1690
1691 return m;
1692}
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:1649
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1477
+ 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 1700 of file mx.c.

1701{
1702 if (!a || !name)
1703 return NULL;
1704
1705 struct MailboxNode *np = NULL;
1706
1707 STAILQ_FOREACH(np, &a->mailboxes, entries)
1708 {
1709 if (mutt_str_equal(np->mailbox->name, name))
1710 return np->mailbox;
1711 }
1712
1713 return NULL;
1714}
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 1721 of file mx.c.

1722{
1723 if (!name)
1724 return NULL;
1725
1726 struct Account *np = NULL;
1727 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1728 {
1729 struct Mailbox *m = mx_mbox_find_by_name_ac(np, name);
1730 if (m)
1731 return m;
1732 }
1733
1734 return NULL;
1735}
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:1700
+ 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 1746 of file mx.c.

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

1765{
1766 if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1767 return false;
1768
1769 return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1770}
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:147
+ 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 1781 of file mx.c.

1782{
1783 if (!m || !m->account)
1784 return -1;
1785
1786 struct Account *a = m->account;
1788 if (!keep_account && STAILQ_EMPTY(&a->mailboxes))
1789 {
1791 }
1792 return 0;
1793}
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 1800 of file mx.c.

1801{
1802 if (!m)
1803 return MX_STATUS_ERROR;
1804
1805 enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1806 if (rc != MX_STATUS_ERROR)
1807 {
1808 struct EventMailbox ev_m = { m };
1810 }
1811
1812 return rc;
1813}
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:172
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:186
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition: mailbox.h:144
enum MxStatus(* mbox_check_stats)(struct Mailbox *m, CheckStatsFlags flags)
Definition: mxapi.h:202
+ 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 1824 of file mx.c.

1825{
1826 if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1827 return 0;
1828
1829 return m->mx_ops->msg_save_hcache(m, e);
1830}
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Definition: mxapi.h:324
+ 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 1837 of file mx.c.

1838{
1839 return m ? m->type : MUTT_MAILBOX_ERROR;
1840}
+ 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 1848 of file mx.c.

1849{
1850 if (!m)
1851 return -1;
1852
1853 if (m->readonly)
1854 {
1855 mutt_error(_("Can't toggle write on a readonly mailbox"));
1856 return -1;
1857 }
1858
1859 if (m->dontwrite)
1860 {
1861 m->dontwrite = false;
1862 mutt_message(_("Changes to folder will be written on folder exit"));
1863 }
1864 else
1865 {
1866 m->dontwrite = true;
1867 mutt_message(_("Changes to folder will not be written"));
1868 }
1869
1870 struct EventMailbox ev_m = { m };
1872 return 0;
1873}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ MboxTypeMap

const struct Mapping MboxTypeMap[]
static
Initial value:
= {
{ "mbox", MUTT_MBOX, },
{ "MMDF", MUTT_MMDF, },
{ "MH", MUTT_MH, },
{ "Maildir", MUTT_MAILDIR, },
{ NULL, 0, },
}

Definition at line 88 of file mx.c.

◆ MboxTypeDef

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

Definition at line 98 of file mx.c.

◆ MxOps

const struct MxOps* MxOps[]
Initial value:
= {
NULL,
}
struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps -.
Definition: maildir.c:1645
struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1254
struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition: compress.c:937
struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition: mbox.c:1874
struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps -.
Definition: nntp.c:2741
struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition: imap.c:2486
struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition: mbox.c:1842
struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition: notmuch.c:2469
struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1197

All the Mailbox backends.

Definition at line 107 of file mx.c.