NeoMutt  2024-02-01-35-geee02f
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 <unistd.h>
#include "mutt/lib.h"
#include "address/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 125 of file mx.c.

126{
127 for (const struct MxOps **ops = MxOps; *ops; ops++)
128 if ((*ops)->type == type)
129 return *ops;
130
131 return NULL;
132}
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 139 of file mx.c.

140{
141 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
142 if (mutt_str_equal(str, c_spool_file))
143 return true;
144
145 struct Url *ua = url_parse(str);
146 struct Url *ub = url_parse(c_spool_file);
147
148 const bool is_spool = ua && ub && (ua->scheme == ub->scheme) &&
149 mutt_istr_equal(ua->host, ub->host) &&
150 mutt_istr_equal(ua->path, ub->path) &&
151 (!ua->user || !ub->user || mutt_str_equal(ua->user, ub->user));
152
153 url_free(&ua);
154 url_free(&ub);
155 return is_spool;
156}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:721
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:709
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
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 168 of file mx.c.

169{
170 if (imap_path_probe(path, NULL) == MUTT_IMAP)
171 return imap_access(path);
172
173 return access(path, flags);
174}
@ 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:2342
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:464
+ 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 183 of file mx.c.

184{
185 if (!m)
186 return false;
187
188 struct stat st = { 0 };
189
190 m->append = true;
191 if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR))
192 {
194
195 if (m->type == MUTT_UNKNOWN)
196 {
197 if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
198 {
200 }
201 else
202 {
203 mutt_error(_("%s is not a mailbox"), mailbox_path(m));
204 return false;
205 }
206 }
207
208 if (m->type == MUTT_MAILBOX_ERROR)
209 {
210 if (stat(mailbox_path(m), &st) == -1)
211 {
212 if (errno == ENOENT)
213 {
216 else
217 m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
218 flags |= MUTT_APPENDNEW;
219 }
220 else
221 {
222 mutt_perror("%s", mailbox_path(m));
223 return false;
224 }
225 }
226 else
227 {
228 return false;
229 }
230 }
231
232 m->mx_ops = mx_get_ops(m->type);
233 }
234
235 if (!m->mx_ops || !m->mx_ops->mbox_open_append)
236 return false;
237
238 const bool rc = m->mx_ops->mbox_open_append(m, flags);
239 m->opened++;
240 return rc;
241}
bool mutt_comp_can_append(struct Mailbox *m)
Can we append to this path?
Definition: compress.c:343
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:72
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:211
@ 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:125
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1319
#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 249 of file mx.c.

250{
251 if (!m)
252 return false;
253
254 if (m->account)
255 return true;
256
257 struct Account *a = mx_ac_find(m);
258 const bool new_account = !a;
259 if (new_account)
260 {
261 a = account_new(NULL, NeoMutt->sub);
262 a->type = m->type;
263 }
264 if (!mx_ac_add(a, m))
265 {
266 if (new_account)
267 {
268 account_free(&a);
269 }
270 return false;
271 }
272 if (new_account)
273 {
275 }
276 return true;
277}
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:1721
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1517
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition: neomutt.c:105
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 286 of file mx.c.

287{
288 if (!m)
289 return false;
290
291 if ((m->type == MUTT_UNKNOWN) && (flags & (MUTT_NEWFOLDER | MUTT_APPEND)))
292 {
293 m->type = cs_subset_enum(NeoMutt->sub, "mbox_type");
294 m->mx_ops = mx_get_ops(m->type);
295 }
296
297 const bool newly_linked_account = !m->account;
298 if (newly_linked_account)
299 {
300 if (!mx_mbox_ac_link(m))
301 {
302 return false;
303 }
304 }
305
306 m->verbose = !(flags & MUTT_QUIET);
307 m->readonly = (flags & MUTT_READONLY);
308 m->peekonly = (flags & MUTT_PEEK);
309
310 if (flags & (MUTT_APPEND | MUTT_NEWFOLDER))
311 {
312 if (!mx_open_mailbox_append(m, flags))
313 {
314 goto error;
315 }
316 return true;
317 }
318
319 if (m->opened > 0)
320 {
321 m->opened++;
322 return true;
323 }
324
325 m->size = 0;
326 m->msg_unread = 0;
327 m->msg_flagged = 0;
328 m->rights = MUTT_ACL_ALL;
329
330 if (m->type == MUTT_UNKNOWN)
331 {
333 m->mx_ops = mx_get_ops(m->type);
334 }
335
336 if ((m->type == MUTT_UNKNOWN) || (m->type == MUTT_MAILBOX_ERROR) || !m->mx_ops)
337 {
338 if (m->type == MUTT_MAILBOX_ERROR)
339 mutt_perror("%s", mailbox_path(m));
340 else if ((m->type == MUTT_UNKNOWN) || !m->mx_ops)
341 mutt_error(_("%s is not a mailbox"), mailbox_path(m));
342 goto error;
343 }
344
346
347 /* if the user has a 'push' command in their .neomuttrc, or in a folder-hook,
348 * it will cause the progress messages not to be displayed because
349 * mutt_refresh() will think we are in the middle of a macro. so set a
350 * flag to indicate that we should really refresh the screen. */
351 OptForceRefresh = true;
352
353 if (m->verbose)
354 mutt_message(_("Reading %s..."), mailbox_path(m));
355
356 // Clear out any existing emails
357 for (int i = 0; i < m->email_max; i++)
358 {
359 email_free(&m->emails[i]);
360 }
361
362 m->msg_count = 0;
363 m->msg_unread = 0;
364 m->msg_flagged = 0;
365 m->msg_new = 0;
366 m->msg_deleted = 0;
367 m->msg_tagged = 0;
368 m->vcount = 0;
369
370 enum MxOpenReturns rc = m->mx_ops->mbox_open(m);
371 m->opened++;
372
373 if ((rc == MX_OPEN_OK) || (rc == MX_OPEN_ABORT))
374 {
375 if ((flags & MUTT_NOSORT) == 0)
376 {
377 /* avoid unnecessary work since the mailbox is completely unthreaded
378 * to begin with */
379 OptSortSubthreads = false;
380 OptNeedRescore = false;
381 }
382 if (m->verbose)
384 if (rc == MX_OPEN_ABORT)
385 {
386 mutt_error(_("Reading from %s interrupted..."), mailbox_path(m));
387 }
388 }
389 else
390 {
391 goto error;
392 }
393
394 if (!m->peekonly)
395 m->has_new = false;
396 OptForceRefresh = false;
397
398 return true;
399
400error:
401 mx_fastclose_mailbox(m, newly_linked_account);
402 if (newly_linked_account)
404 return false;
405}
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:419
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:412
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:249
static bool mx_open_mailbox_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox for appending.
Definition: mx.c:183
#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 412 of file mx.c.

413{
414 if (!m)
415 return;
416
417 m->opened--;
418 if (m->opened != 0)
419 return;
420
421 /* never announce that a mailbox we've just left has new mail.
422 * TODO: really belongs in mx_mbox_close, but this is a nice hook point */
423 if (!m->peekonly)
425
426 if (m->mx_ops)
427 m->mx_ops->mbox_close(m);
428
432
433 if (m->emails)
434 {
435 for (int i = 0; i < m->msg_count; i++)
436 {
437 if (!m->emails[i])
438 break;
439 email_free(&m->emails[i]);
440 }
441 }
442
443 if (!m->visible)
444 {
445 mx_ac_remove(m, keep_account);
446 }
447}
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:302
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1738
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 454 of file mx.c.

455{
456 if (!m || !m->mx_ops || !m->mx_ops->mbox_sync)
457 return MX_STATUS_ERROR;
458
459 if (m->verbose)
460 {
461 /* L10N: Displayed before/as a mailbox is being synced */
462 mutt_message(_("Writing %s..."), mailbox_path(m));
463 }
464
465 enum MxStatus rc = m->mx_ops->mbox_sync(m);
466 if (rc != MX_STATUS_OK)
467 {
468 mutt_debug(LL_DEBUG2, "mbox_sync returned: %d\n", rc);
469 if ((rc == MX_STATUS_ERROR) && m->verbose)
470 {
471 /* L10N: Displayed if a mailbox sync fails */
472 mutt_error(_("Unable to write %s"), mailbox_path(m));
473 }
474 }
475
476 return rc;
477}
#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 485 of file mx.c.

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

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

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

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

1104{
1105 if (!m || !m->mx_ops)
1106 return MX_STATUS_ERROR;
1107
1108 const short c_mail_check = cs_subset_number(NeoMutt->sub, "mail_check");
1109
1110 time_t t = mutt_date_now();
1111 if ((t - m->last_checked) < c_mail_check)
1112 return MX_STATUS_OK;
1113
1114 m->last_checked = t;
1115
1116 enum MxStatus rc = m->mx_ops->mbox_check(m);
1117 if ((rc == MX_STATUS_NEW_MAIL) || (rc == MX_STATUS_REOPENED))
1118 {
1120 }
1121
1122 return rc;
1123}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:144
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:177
@ 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 1132 of file mx.c.

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

1158{
1159 if (!m || !m->mx_ops || !m->mx_ops->msg_commit || !msg)
1160 return -1;
1161
1162 if (!(msg->write && m->append))
1163 {
1164 mutt_debug(LL_DEBUG1, "msg->write = %d, m->append = %d\n", msg->write, m->append);
1165 return -1;
1166 }
1167
1168 return m->mx_ops->msg_commit(m, msg);
1169}
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 1178 of file mx.c.

1179{
1180 if (!m || !ptr || !*ptr)
1181 return 0;
1182
1183 int rc = 0;
1184 struct Message *msg = *ptr;
1185
1186 if (m->mx_ops && m->mx_ops->msg_close)
1187 rc = m->mx_ops->msg_close(m, msg);
1188
1189 if (msg->path)
1190 {
1191 mutt_debug(LL_DEBUG1, "unlinking %s\n", msg->path);
1192 unlink(msg->path);
1193 }
1194
1195 message_free(ptr);
1196 return rc;
1197}
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 1204 of file mx.c.

1205{
1206 if ((req_size + 1) <= m->email_max)
1207 return;
1208
1209 // Step size to increase by
1210 // Larger mailboxes get a larger step (limited to 1000)
1211 const int grow = CLAMP(m->email_max, 25, 1000);
1212
1213 // Sanity checks
1214 req_size = ROUND_UP(req_size + 1, grow);
1215
1216 const size_t s = MAX(sizeof(struct Email *), sizeof(int));
1217 if ((req_size * s) < (m->email_max * s))
1218 {
1219 mutt_error(_("Out of memory"));
1220 mutt_exit(1);
1221 }
1222
1223 if (m->emails)
1224 {
1225 mutt_mem_realloc(&m->emails, req_size * sizeof(struct Email *));
1226 mutt_mem_realloc(&m->v2r, req_size * sizeof(int));
1227 }
1228 else
1229 {
1230 m->emails = mutt_mem_calloc(req_size, sizeof(struct Email *));
1231 m->v2r = mutt_mem_calloc(req_size, sizeof(int));
1232 }
1233
1234 for (int i = m->email_max; i < req_size; i++)
1235 {
1236 m->emails[i] = NULL;
1237 m->v2r[i] = -1;
1238 }
1239
1240 m->email_max = req_size;
1241}
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:231
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#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 1250 of file mx.c.

1251{
1252 if (buf_is_empty(path))
1253 return -1;
1254
1255 enum MailboxType type = mx_path_probe(buf_string(path));
1256 const struct MxOps *ops = mx_get_ops(type);
1257 if (!ops || !ops->path_is_empty)
1258 return -1;
1259
1260 return ops->path_is_empty(path);
1261}
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 1272 of file mx.c.

1273{
1274 if (!m || !buf)
1275 return -1;
1276
1277 if (m->mx_ops->tags_edit)
1278 return m->mx_ops->tags_edit(m, tags, buf);
1279
1280 mutt_message(_("Folder doesn't support tagging, aborting"));
1281 return -1;
1282}
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 1292 of file mx.c.

1293{
1294 if (!m || !e || !tags)
1295 return -1;
1296
1297 if (m->mx_ops->tags_commit)
1298 return m->mx_ops->tags_commit(m, e, tags);
1299
1300 mutt_message(_("Folder doesn't support tagging, aborting"));
1301 return -1;
1302}
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 1309 of file mx.c.

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

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

1366{
1367 if (buf_is_empty(path))
1368 return -1;
1369
1370 for (size_t i = 0; i < 3; i++)
1371 {
1372 /* Look for !! ! - < > or ^ followed by / or NUL */
1373 if ((buf_at(path, 0) == '!') && (buf_at(path, 1) == '!'))
1374 {
1375 if (((buf_at(path, 2) == '/') || (buf_at(path, 2) == '\0')))
1376 {
1377 buf_inline_replace(path, 0, 2, LastFolder);
1378 }
1379 }
1380 else if ((buf_at(path, 0) == '+') || (buf_at(path, 0) == '='))
1381 {
1382 size_t folder_len = mutt_str_len(folder);
1383 if ((folder_len > 0) && (folder[folder_len - 1] != '/'))
1384 {
1385 path->data[0] = '/';
1386 buf_inline_replace(path, 0, 0, folder);
1387 }
1388 else
1389 {
1390 buf_inline_replace(path, 0, 1, folder);
1391 }
1392 }
1393 else if ((buf_at(path, 1) == '/') || (buf_at(path, 1) == '\0'))
1394 {
1395 if (buf_at(path, 0) == '!')
1396 {
1397 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1398 buf_inline_replace(path, 0, 1, c_spool_file);
1399 }
1400 else if (buf_at(path, 0) == '-')
1401 {
1402 buf_inline_replace(path, 0, 1, LastFolder);
1403 }
1404 else if (buf_at(path, 0) == '<')
1405 {
1406 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
1407 buf_inline_replace(path, 0, 1, c_record);
1408 }
1409 else if (buf_at(path, 0) == '>')
1410 {
1411 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
1412 buf_inline_replace(path, 0, 1, c_mbox);
1413 }
1414 else if (buf_at(path, 0) == '^')
1415 {
1416 buf_inline_replace(path, 0, 1, CurrentFolder);
1417 }
1418 else if (buf_at(path, 0) == '~')
1419 {
1420 buf_inline_replace(path, 0, 1, HomeDir);
1421 }
1422 }
1423 else if (buf_at(path, 0) == '@')
1424 {
1425 /* elm compatibility, @ expands alias to user name */
1426 struct AddressList *al = alias_lookup(buf_string(path));
1427 if (!al || TAILQ_EMPTY(al))
1428 break;
1429
1430 struct Email *e = email_new();
1431 e->env = mutt_env_new();
1432 mutt_addrlist_copy(&e->env->from, al, false);
1433 mutt_addrlist_copy(&e->env->to, al, false);
1435 email_free(&e);
1436 break;
1437 }
1438 else
1439 {
1440 break;
1441 }
1442 }
1443
1444 // if (!folder) //XXX - use inherited version, or pass NULL to backend?
1445 // return -1;
1446
1448 if (type)
1449 *type = type2;
1450 const struct MxOps *ops = mx_get_ops(type2);
1451 if (!ops || !ops->path_canon)
1452 return -1;
1453
1454 if (ops->path_canon(path) < 0)
1455 {
1456 mutt_path_canon(path, HomeDir, true);
1457 }
1458
1459 return 0;
1460}
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:282
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:687
void buf_inline_replace(struct Buffer *buf, size_t pos, size_t len, const char *str)
Definition: buffer.c:787
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:748
bool mutt_path_canon(struct Buffer *path, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition: path.c:247
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:545
#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 1469 of file mx.c.

1470{
1471 if (!m)
1472 return -1;
1473
1474 struct Buffer *path = buf_pool_get();
1475
1476 if (m->realpath)
1477 buf_strcpy(path, m->realpath);
1478 else
1479 buf_strcpy(path, mailbox_path(m));
1480
1481 int rc = mx_path_canon(path, folder, &m->type);
1482
1484 buf_pool_release(&path);
1485
1486 if (rc >= 0)
1487 {
1488 m->mx_ops = mx_get_ops(m->type);
1489 buf_strcpy(&m->pathbuf, m->realpath);
1490 }
1491
1492 return rc;
1493}
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:329
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:1365
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 1503 of file mx.c.

1504{
1505 if (!m || !m->mx_ops || !m->mx_ops->msg_padding_size)
1506 return 0;
1507
1508 return m->mx_ops->msg_padding_size(m);
1509}
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 1517 of file mx.c.

1518{
1519 if (!m || !m->mx_ops || !m->realpath)
1520 return NULL;
1521
1522 struct Account *np = NULL;
1523 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1524 {
1525 if (np->type != m->type)
1526 continue;
1527
1528 if (m->mx_ops->ac_owns_path(np, m->realpath))
1529 return np;
1530 }
1531
1532 return NULL;
1533}
#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:46
+ 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 1541 of file mx.c.

1542{
1543 if (!a || !path)
1544 return NULL;
1545
1546 struct MailboxNode *np = NULL;
1547 struct Url *url_p = NULL;
1548 struct Url *url_a = NULL;
1549
1550 const bool use_url = (a->type == MUTT_IMAP);
1551 if (use_url)
1552 {
1553 url_p = url_parse(path);
1554 if (!url_p)
1555 goto done;
1556 }
1557
1558 STAILQ_FOREACH(np, &a->mailboxes, entries)
1559 {
1560 if (!use_url)
1561 {
1563 return np->mailbox;
1564 continue;
1565 }
1566
1567 url_free(&url_a);
1568 url_a = url_parse(np->mailbox->realpath);
1569 if (!url_a)
1570 continue;
1571
1572 if (!mutt_istr_equal(url_a->host, url_p->host))
1573 continue;
1574 if (url_p->user && !mutt_istr_equal(url_a->user, url_p->user))
1575 continue;
1576 if (a->type == MUTT_IMAP)
1577 {
1578 if (imap_mxcmp(url_a->path, url_p->path) == 0)
1579 break;
1580 }
1581 else
1582 {
1583 if (mutt_str_equal(url_a->path, url_p->path))
1584 break;
1585 }
1586 }
1587
1588done:
1589 url_free(&url_p);
1590 url_free(&url_a);
1591
1592 if (!np)
1593 return NULL;
1594 return np->mailbox;
1595}
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:154
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:155
+ 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 1603 of file mx.c.

1604{
1605 if (!path)
1606 return NULL;
1607
1608 struct Buffer *buf = buf_new(path);
1609 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1610 mx_path_canon(buf, c_folder, NULL);
1611
1612 struct Account *np = NULL;
1613 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1614 {
1615 struct Mailbox *m = mx_mbox_find(np, buf_string(buf));
1616 if (m)
1617 {
1618 buf_free(&buf);
1619 return m;
1620 }
1621 }
1622
1623 buf_free(&buf);
1624 return NULL;
1625}
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition: buffer.c:336
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:321
+ 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 1634 of file mx.c.

1635{
1636 if (!path)
1637 return NULL;
1638
1639 struct Mailbox *m = mx_mbox_find2(path);
1640 if (m)
1641 return m;
1642
1643 m = mailbox_new();
1644 buf_strcpy(&m->pathbuf, path);
1645 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1646 mx_path_canon2(m, c_folder);
1647
1648 return m;
1649}
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition: mailbox.c:69
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1603
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1469
+ 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 1657 of file mx.c.

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

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

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

1722{
1723 if (!a || !m || !m->mx_ops || !m->mx_ops->ac_add)
1724 return false;
1725
1726 return m->mx_ops->ac_add(a, m) && account_mailbox_add(a, m);
1727}
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 1738 of file mx.c.

1739{
1740 if (!m || !m->account)
1741 return -1;
1742
1743 struct Account *a = m->account;
1745 if (!keep_account && STAILQ_EMPTY(&a->mailboxes))
1746 {
1748 }
1749 return 0;
1750}
bool neomutt_account_remove(struct NeoMutt *n, const struct Account *a)
Remove an Account from the global list.
Definition: neomutt.c:128
#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 1757 of file mx.c.

1758{
1759 if (!m)
1760 return MX_STATUS_ERROR;
1761
1762 enum MxStatus rc = m->mx_ops->mbox_check_stats(m, flags);
1763 if (rc != MX_STATUS_ERROR)
1764 {
1765 struct EventMailbox ev_m = { m };
1767 }
1768
1769 return rc;
1770}
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:173
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:187
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 1781 of file mx.c.

1782{
1783 if (!m || !m->mx_ops || !m->mx_ops->msg_save_hcache || !e)
1784 return 0;
1785
1786 return m->mx_ops->msg_save_hcache(m, e);
1787}
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 1794 of file mx.c.

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

1806{
1807 if (!m)
1808 return -1;
1809
1810 if (m->readonly)
1811 {
1812 mutt_error(_("Can't toggle write on a readonly mailbox"));
1813 return -1;
1814 }
1815
1816 if (m->dontwrite)
1817 {
1818 m->dontwrite = false;
1819 mutt_message(_("Changes to folder will be written on folder exit"));
1820 }
1821 else
1822 {
1823 m->dontwrite = true;
1824 mutt_message(_("Changes to folder will not be written"));
1825 }
1826
1827 struct EventMailbox ev_m = { m };
1829 return 0;
1830}
+ 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 79 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:79
Mapping between user-readable string and a constant.
Definition: mapping.h:33

Data for the $mbox_type enumeration.

Definition at line 90 of file mx.c.

◆ MxOps

const struct MxOps* MxOps[]
static
Initial value:
= {
NULL,
}
const struct MxOps MxNntpOps
NNTP Mailbox - Implements MxOps -.
Definition: nntp.c:2760
const struct MxOps MxMboxOps
Mbox Mailbox - Implements MxOps -.
Definition: mbox.c:1717
const struct MxOps MxNotmuchOps
Notmuch Mailbox - Implements MxOps -.
Definition: notmuch.c:2470
const struct MxOps MxMhOps
MH Mailbox - Implements MxOps -.
Definition: mh.c:1237
const struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1179
const struct MxOps MxImapOps
IMAP Mailbox - Implements MxOps -.
Definition: imap.c:2404
const struct MxOps MxCompOps
Compressed Mailbox - Implements MxOps -.
Definition: compress.c:897
const struct MxOps MxMmdfOps
MMDF Mailbox - Implements MxOps -.
Definition: mbox.c:1747
const struct MxOps MxMaildirOps
Maildir Mailbox - Implements MxOps -.
Definition: maildir.c:44

All the Mailbox backends.

Definition at line 99 of file mx.c.