NeoMutt  2024-04-25-76-g20fe7b
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mx.c File Reference

Mailbox multiplexor. More...

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

Go to the source code of this file.

Functions

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

Variables

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

Detailed Description

Mailbox multiplexor.

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

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

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

Definition in file mx.c.

Function Documentation

◆ mx_get_ops()

const struct MxOps * mx_get_ops ( enum MailboxType  type)

Get mailbox operations.

Parameters
typeMailbox type
Return values
ptrMailbox function
NULLError

Definition at line 127 of file mx.c.

128{
129 for (const struct MxOps **ops = MxOps; *ops; ops++)
130 if ((*ops)->type == type)
131 return *ops;
132
133 return NULL;
134}
Definition: mxapi.h:91
+ Here is the caller graph for this function:

◆ mutt_is_spool()

static bool mutt_is_spool ( const char *  str)
static

Is this the spool_file?

Parameters
strName to check
Return values
trueIt is the spool_file

Definition at line 141 of file mx.c.

142{
143 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
144 if (mutt_str_equal(str, c_spool_file))
145 return true;
146
147 struct Url *ua = url_parse(str);
148 struct Url *ub = url_parse(c_spool_file);
149
150 const bool is_spool = ua && ub && (ua->scheme == ub->scheme) &&
151 mutt_istr_equal(ua->host, ub->host) &&
152 mutt_istr_equal(ua->path, ub->path) &&
153 (!ua->user || !ub->user || mutt_str_equal(ua->user, ub->user));
154
155 url_free(&ua);
156 url_free(&ub);
157 return is_spool;
158}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:672
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * user
Username.
Definition: url.h:71
char * host
Host.
Definition: url.h:73
char * path
Path.
Definition: url.h:75
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:70
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:239
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:124
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_access()

int mx_access ( const char *  path,
int  flags 
)

Wrapper for access, checks permissions on a given mailbox.

Parameters
pathPath of mailbox
flagsFlags, e.g. W_OK
Return values
0Success, allowed
<0Failure, not allowed

We may be interested in using ACL-style flags at some point, currently we use the normal access() flags.

Definition at line 170 of file mx.c.

171{
172 if (imap_path_probe(path, NULL) == MUTT_IMAP)
173 return imap_access(path);
174
175 return access(path, flags);
176}
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2345
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:463
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_open_mailbox_append()

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

Open a mailbox for appending.

Parameters
mMailbox
flagsFlags, see OpenMailboxFlags
Return values
trueSuccess
falseFailure

Definition at line 185 of file mx.c.

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

◆ mx_mbox_ac_link()

bool mx_mbox_ac_link ( struct Mailbox m)

Link a Mailbox to an existing or new Account.

Parameters
mMailbox to link
Return values
trueSuccess
falseFailure

Definition at line 251 of file mx.c.

252{
253 if (!m)
254 return false;
255
256 if (m->account)
257 return true;
258
259 struct Account *a = mx_ac_find(m);
260 const bool new_account = !a;
261 if (new_account)
262 {
263 a = account_new(NULL, NeoMutt->sub);
264 a->type = m->type;
265 }
266 if (!mx_ac_add(a, m))
267 {
268 if (new_account)
269 {
270 account_free(&a);
271 }
272 return false;
273 }
274 if (new_account)
275 {
277 }
278 return true;
279}
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:44
void account_free(struct Account **ptr)
Free an Account.
Definition: account.c:143
bool mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1723
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1519
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition: neomutt.c:110
A group of associated Mailboxes.
Definition: account.h:36
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:37
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:127
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_open()

bool mx_mbox_open ( struct Mailbox m,
OpenMailboxFlags  flags 
)

Open a mailbox and parse it.

Parameters
mMailbox to open
flagsFlags, see OpenMailboxFlags
Return values
trueSuccess
falseError

Definition at line 288 of file mx.c.

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

◆ mx_fastclose_mailbox()

void mx_fastclose_mailbox ( struct Mailbox m,
bool  keep_account 
)

Free up memory associated with the Mailbox.

Parameters
mMailbox
keep_accountMake sure not to remove the mailbox's account

Definition at line 414 of file mx.c.

415{
416 if (!m)
417 return;
418
419 m->opened--;
420 if (m->opened != 0)
421 return;
422
423 /* never announce that a mailbox we've just left has new mail.
424 * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
425 if (!m->peekonly)
427
428 if (m->mx_ops)
429 m->mx_ops->mbox_close(m);
430
434
435 if (m->emails)
436 {
437 for (int i = 0; i < m->msg_count; i++)
438 {
439 if (!m->emails[i])
440 break;
441 email_free(&m->emails[i]);
442 }
443 }
444
445 if (!m->visible)
446 {
447 mx_ac_remove(m, keep_account);
448 }
449}
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
void mutt_mailbox_set_notified(struct Mailbox *m)
Note when the user was last notified of new mail.
Definition: mutt_mailbox.c:304
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1740
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:199
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sync_mailbox()

static enum MxStatus sync_mailbox ( struct Mailbox m)
static

Save changes to disk.

Parameters
mMailbox
Return values
enumMxStatus

Definition at line 456 of file mx.c.

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

◆ trash_append()

static int trash_append ( struct Mailbox m)
static

Move deleted mails to the trash folder.

Parameters
mMailbox
Return values
0Success
-1Failure

Definition at line 487 of file mx.c.

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

◆ mx_mbox_close()

enum MxStatus mx_mbox_close ( struct Mailbox m)

Save changes and close mailbox.

Parameters
mMailbox
Return values
enumMxStatus
Note
The flag retvals come from a call to a backend sync function
It's very important to ensure the mailbox is properly closed before free'ing the context. For selected mailboxes, IMAP will cache the context inside connection->adata until imap_close_mailbox() removes it. Readonly, dontwrite, and append mailboxes are guaranteed to call mx_fastclose_mailbox(), so for most of NeoMutt's code you won't see return value checks for temporary contexts.

Definition at line 598 of file mx.c.

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

◆ mx_mbox_sync()

enum MxStatus mx_mbox_sync ( struct Mailbox m)

Save changes to mailbox.

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

Definition at line 906 of file mx.c.

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

◆ mx_msg_open_new()

struct Message * mx_msg_open_new ( struct Mailbox m,
const struct Email e,
MsgOpenFlags  flags 
)

Open a new message.

Parameters
mDestination mailbox
eMessage being copied (required for maildir support, because the filename depends on the message flags)
flagsFlags, see MsgOpenFlags
Return values
ptrNew Message

Definition at line 1040 of file mx.c.

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

◆ mx_mbox_check()

enum MxStatus mx_mbox_check ( struct Mailbox m)

Check for new mail - Wrapper for MxOps::mbox_check()

Parameters
mMailbox
Return values
enumMxStatus

Definition at line 1105 of file mx.c.

1106{
1107 if (!m || !m->mx_ops)
1108 return MX_STATUS_ERROR;
1109
1110 const short c_mail_check = cs_subset_number(NeoMutt->sub, "mail_check");
1111
1112 time_t t = mutt_date_now();
1113 if ((t - m->last_checked) < c_mail_check)
1114 return MX_STATUS_OK;
1115
1116 m->last_checked = t;
1117
1118 enum MxStatus rc = m->mx_ops->mbox_check(m);
1119 if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1120 {
1122 }
1123
1124 return rc;
1125}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:143
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:189
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:68
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:66
time_t last_checked
Last time we checked this mailbox for new mail.
Definition: mailbox.h:105
enum MxStatus(* mbox_check)(struct Mailbox *m)
Definition: mxapi.h:162
+ 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 1134 of file mx.c.

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

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

◆ mx_msg_close()

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

Close a message.

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

Definition at line 1180 of file mx.c.

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

◆ mx_alloc_memory()

void mx_alloc_memory ( struct Mailbox m,
int  req_size 
)

Create storage for the emails.

Parameters
mMailbox
req_sizeSpace required

Definition at line 1206 of file mx.c.

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

◆ mx_path_is_empty()

int mx_path_is_empty ( struct Buffer path)

Is the mailbox empty.

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

Definition at line 1252 of file mx.c.

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

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

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

1312{
1313 return m && m->mx_ops->tags_commit && m->mx_ops->tags_edit;
1314}
+ Here is the caller graph for this function:

◆ mx_path_probe()

enum MailboxType mx_path_probe ( const char *  path)

Find a mailbox that understands a path.

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

Definition at line 1321 of file mx.c.

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

◆ mx_path_canon()

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

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

Definition at line 1367 of file mx.c.

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

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

◆ mx_msg_padding_size()

int mx_msg_padding_size ( struct Mailbox m)

Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()

Parameters
mMailbox
Return values
numNumber of bytes of padding

mmdf and mbox add separators, which leads a small discrepancy when computing vsize for a limited view.

Definition at line 1505 of file mx.c.

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

1520{
1521 if (!m || !m->mx_ops || !m->realpath)
1522 return NULL;
1523
1524 struct Account *np = NULL;
1525 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1526 {
1527 if (np->type != m->type)
1528 continue;
1529
1530 if (m->mx_ops->ac_owns_path(np, m->realpath))
1531 return np;
1532 }
1533
1534 return NULL;
1535}
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
bool(* ac_owns_path)(struct Account *a, const char *path)
Definition: mxapi.h:109
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:47
+ Here is the caller graph for this function:

◆ mx_mbox_find()

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

Find a Mailbox on an Account.

Parameters
aAccount to search
pathPath to find
Return values
ptrMailbox

Definition at line 1543 of file mx.c.

1544{
1545 if (!a || !path)
1546 return NULL;
1547
1548 struct MailboxNode *np = NULL;
1549 struct Url *url_p = NULL;
1550 struct Url *url_a = NULL;
1551
1552 const bool use_url = (a->type == MUTT_IMAP);
1553 if (use_url)
1554 {
1555 url_p = url_parse(path);
1556 if (!url_p)
1557 goto done;
1558 }
1559
1560 STAILQ_FOREACH(np, &a->mailboxes, entries)
1561 {
1562 if (!use_url)
1563 {
1565 return np->mailbox;
1566 continue;
1567 }
1568
1569 url_free(&url_a);
1570 url_a = url_parse(np->mailbox->realpath);
1571 if (!url_a)
1572 continue;
1573
1574 if (!mutt_istr_equal(url_a->host, url_p->host))
1575 continue;
1576 if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1577 continue;
1578 if (a->type == MUTT_IMAP)
1579 {
1580 if (imap_mxcmp(url_a->path, url_p->path) == 0)
1581 break;
1582 }
1583 else
1584 {
1585 if (mutt_str_equal(url_a->path, url_p->path))
1586 break;
1587 }
1588 }
1589
1590done:
1591 url_free(&url_p);
1592 url_free(&url_a);
1593
1594 if (!np)
1595 return NULL;
1596 return np->mailbox;
1597}
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:545
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
struct MailboxList mailboxes
List of Mailboxes.
Definition: account.h:40
List of Mailboxes.
Definition: mailbox.h:166
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:167
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_mbox_find2()

struct Mailbox * mx_mbox_find2 ( const char *  path)

Find a Mailbox on an Account.

Parameters
pathPath to find
Return values
ptrMailbox
NULLNo match

Definition at line 1605 of file mx.c.

1606{
1607 if (!path)
1608 return NULL;
1609
1610 struct Buffer *buf = buf_new(path);
1611 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1612 mx_path_canon(buf, c_folder, NULL);
1613
1614 struct Account *np = NULL;
1615 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1616 {
1617 struct Mailbox *m = mx_mbox_find(np, buf_string(buf));
1618 if (m)
1619 {
1620 buf_free(&buf);
1621 return m;
1622 }
1623 }
1624
1625 buf_free(&buf);
1626 return NULL;
1627}
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition: buffer.c:319
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:304
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_path_resolve()

struct Mailbox * mx_path_resolve ( const char *  path)

Get a Mailbox for a path.

Parameters
pathMailbox path
Return values
ptrMailbox

If there isn't a Mailbox for the path, one will be created.

Definition at line 1636 of file mx.c.

1637{
1638 if (!path)
1639 return NULL;
1640
1641 struct Mailbox *m = mx_mbox_find2(path);
1642 if (m)
1643 return m;
1644
1645 m = mailbox_new();
1646 buf_strcpy(&m->pathbuf, path);
1647 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1648 mx_path_canon2(m, c_folder);
1649
1650 return m;
1651}
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:1605
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1471
+ 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 1659 of file mx.c.

1660{
1661 if (!a || !name)
1662 return NULL;
1663
1664 struct MailboxNode *np = NULL;
1665
1666 STAILQ_FOREACH(np, &a->mailboxes, entries)
1667 {
1668 if (mutt_str_equal(np->mailbox->name, name))
1669 return np->mailbox;
1670 }
1671
1672 return NULL;
1673}
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 1680 of file mx.c.

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

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

1724{
1725 if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1726 return false;
1727
1728 return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1729}
bool account_mailbox_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account.
Definition: account.c:67
bool(* ac_add)(struct Account *a, struct Mailbox *m)
Definition: mxapi.h:124
+ 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 1740 of file mx.c.

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

1760{
1761 if (!m)
1762 return MX_STATUS_ERROR;
1763
1764 enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1765 if (rc != MX_STATUS_ERROR)
1766 {
1767 struct EventMailbox ev_m = { m };
1769 }
1770
1771 return rc;
1772}
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:185
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:173
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:49
An Event that happened to a Mailbox.
Definition: mailbox.h:199
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition: mailbox.h:145
enum MxStatus(* mbox_check_stats)(struct Mailbox *m, CheckStatsFlags flags)
Definition: mxapi.h:175
+ 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 1783 of file mx.c.

1784{
1785 if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1786 return 0;
1787
1788 return m->mx_ops->msg_save_hcache(m, e);
1789}
int(* msg_save_hcache)(struct Mailbox *m, struct Email *e)
Definition: mxapi.h:289
+ 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 1796 of file mx.c.

1797{
1798 return m ? m->type : MUTT_MAILBOX_ERROR;
1799}
+ 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 1807 of file mx.c.

1808{
1809 if (!m)
1810 return -1;
1811
1812 if (m->readonly)
1813 {
1814 mutt_error(_("Can't toggle write on a readonly mailbox"));
1815 return -1;
1816 }
1817
1818 if (m->dontwrite)
1819 {
1820 m->dontwrite = false;
1821 mutt_message(_("Changes to folder will be written on folder exit"));
1822 }
1823 else
1824 {
1825 m->dontwrite = true;
1826 mutt_message(_("Changes to folder will not be written"));
1827 }
1828
1829 struct EventMailbox ev_m = { m };
1831 return 0;
1832}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ MboxTypeMap

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

Lookup table of mailbox types.

Definition at line 81 of file mx.c.

◆ MboxTypeDef

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

Data for the $mbox_type enumeration.

Definition at line 92 of file mx.c.

◆ MxOps

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

All the Mailbox backends.

Definition at line 101 of file mx.c.