NeoMutt  2024-04-16-36-g75b6fb
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
lib.h File Reference

IMAP network mailbox. More...

#include "config.h"
#include <stddef.h>
#include <stdbool.h>
#include <sys/types.h>
#include "core/lib.h"
#include "external.h"
+ Include dependency graph for lib.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void imap_init (void)
 Setup feature commands.
 
int imap_access (const char *path)
 Check permissions on an IMAP mailbox with a new connection.
 
enum MxStatus imap_check_mailbox (struct Mailbox *m, bool force)
 Use the NOOP or IDLE command to poll for new mail.
 
int imap_delete_mailbox (struct Mailbox *m, char *path)
 Delete a mailbox.
 
enum MxStatus imap_sync_mailbox (struct Mailbox *m, bool expunge, bool close)
 Sync all the changes to the server.
 
int imap_path_status (const char *path, bool queue)
 Refresh the number of total and new messages.
 
int imap_mailbox_status (struct Mailbox *m, bool queue)
 Refresh the number of total and new messages.
 
int imap_subscribe (char *path, bool subscribe)
 Subscribe to a mailbox.
 
int imap_complete (struct Buffer *buf, const char *path)
 Try to complete an IMAP folder path.
 
int imap_fast_trash (struct Mailbox *m, const char *dest)
 Use server COPY command to copy deleted messages to trash.
 
enum MailboxType imap_path_probe (const char *path, const struct stat *st)
 Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
 
int imap_path_canon (struct Buffer *buf)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
 
void imap_notify_delete_email (struct Mailbox *m, struct Email *e)
 Inform IMAP that an Email has been deleted.
 
int imap_browse (const char *path, struct BrowserState *state)
 IMAP hook into the folder browser.
 
int imap_mailbox_create (const char *folder)
 Create a new IMAP mailbox.
 
int imap_mailbox_rename (const char *path)
 Rename a mailbox.
 
int imap_copy_messages (struct Mailbox *m, struct EmailArray *ea, const char *dest, enum MessageSaveOpt save_opt)
 Server COPY messages to another folder.
 
void imap_logout_all (void)
 Close all open connections.
 
int imap_expand_path (struct Buffer *buf)
 Buffer wrapper around imap_path_canon()
 
int imap_parse_path (const char *path, struct ConnAccount *cac, char *mailbox, size_t mailboxlen)
 Parse an IMAP mailbox name into ConnAccount, name.
 
void imap_pretty_mailbox (char *path, size_t pathlen, const char *folder)
 Prettify an IMAP mailbox name.
 
int imap_mxcmp (const char *mx1, const char *mx2)
 Compare mailbox names, giving priority to INBOX.
 
int imap_wait_keep_alive (pid_t pid)
 Wait for a process to change state.
 
void imap_keep_alive (void)
 Poll the current folder to keep the connection alive.
 
void imap_get_parent_path (const char *path, char *buf, size_t buflen)
 Get the path of the parent folder.
 
void imap_clean_path (char *path, size_t plen)
 Cleans an IMAP path using imap_fix_path.
 
bool imap_search (struct Mailbox *m, const struct PatternList *pat)
 Find messages in mailbox matching a pattern.
 

Variables

const struct MxOps MxImapOps
 IMAP Mailbox - Implements MxOps -.
 

Detailed Description

IMAP network mailbox.

Authors
  • Richard Russon
  • Pietro Cerutti

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

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

Definition in file lib.h.

Function Documentation

◆ imap_init()

void imap_init ( void  )

Setup feature commands.

Definition at line 96 of file imap.c.

97{
99}
void commands_register(const struct Command *cmds, const size_t num_cmds)
Add commands to Commands array.
Definition: command.c:53
static const struct Command ImapCommands[]
Imap Commands.
Definition: imap.c:86
#define mutt_array_size(x)
Definition: memory.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_access()

int imap_access ( const char *  path)

Check permissions on an IMAP mailbox with a new connection.

Parameters
pathMailbox path
Return values
0Success
<0Failure

TODO: ACL checks. Right now we assume if it exists we can mess with it. TODO: This method should take a Mailbox as parameter to be able to reuse the existing connection.

Definition at line 463 of file imap.c.

464{
465 if (imap_path_status(path, false) >= 0)
466 return 0;
467 return -1;
468}
int imap_path_status(const char *path, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1172
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_check_mailbox()

enum MxStatus imap_check_mailbox ( struct Mailbox m,
bool  force 
)

Use the NOOP or IDLE command to poll for new mail.

Parameters
mMailbox
forceDon't wait
Return values
numMxStatus

Definition at line 1032 of file imap.c.

1033{
1034 if (!m || !m->account)
1035 return MX_STATUS_ERROR;
1036
1038 struct ImapMboxData *mdata = imap_mdata_get(m);
1039
1040 /* overload keyboard timeout to avoid many mailbox checks in a row.
1041 * Most users don't like having to wait exactly when they press a key. */
1042 int rc = 0;
1043
1044 /* try IDLE first, unless force is set */
1045 const bool c_imap_idle = cs_subset_bool(NeoMutt->sub, "imap_idle");
1046 const short c_imap_keep_alive = cs_subset_number(NeoMutt->sub, "imap_keep_alive");
1047 if (!force && c_imap_idle && (adata->capabilities & IMAP_CAP_IDLE) &&
1048 ((adata->state != IMAP_IDLE) || (mutt_date_now() >= adata->lastread + c_imap_keep_alive)))
1049 {
1050 if (imap_cmd_idle(adata) < 0)
1051 return MX_STATUS_ERROR;
1052 }
1053 if (adata->state == IMAP_IDLE)
1054 {
1055 while ((rc = mutt_socket_poll(adata->conn, 0)) > 0)
1056 {
1057 if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
1058 {
1059 mutt_debug(LL_DEBUG1, "Error reading IDLE response\n");
1060 return MX_STATUS_ERROR;
1061 }
1062 }
1063 if (rc < 0)
1064 {
1065 mutt_debug(LL_DEBUG1, "Poll failed, disabling IDLE\n");
1066 adata->capabilities &= ~IMAP_CAP_IDLE; // Clear the flag
1067 }
1068 }
1069
1070 const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
1071 if ((force || ((adata->state != IMAP_IDLE) && (mutt_date_now() >= adata->lastread + c_timeout))) &&
1072 (imap_exec(adata, "NOOP", IMAP_CMD_POLL) != IMAP_EXEC_SUCCESS))
1073 {
1074 return MX_STATUS_ERROR;
1075 }
1076
1077 /* We call this even when we haven't run NOOP in case we have pending
1078 * changes to process, since we can reopen here. */
1079 imap_cmd_finish(adata);
1080
1081 enum MxStatus check = MX_STATUS_OK;
1082 if (mdata->check_status & IMAP_EXPUNGE_PENDING)
1083 check = MX_STATUS_REOPENED;
1084 else if (mdata->check_status & IMAP_NEWMAIL_PENDING)
1085 check = MX_STATUS_NEW_MAIL;
1086 else if (mdata->check_status & IMAP_FLAGS_PENDING)
1087 check = MX_STATUS_FLAGS;
1088 else if (rc < 0)
1089 check = MX_STATUS_ERROR;
1090
1091 mdata->check_status = IMAP_OPEN_NO_FLAGS;
1092
1093 if (force)
1094 m->last_checked = 0; // force a check on the next mx_mbox_check() call
1095 return check;
1096}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:144
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: adata.c:123
int imap_cmd_idle(struct ImapAccountData *adata)
Enter the IDLE state.
Definition: command.c:1436
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1129
int imap_exec(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Execute a command and wait for the response from the server.
Definition: command.c:1304
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition: command.c:1369
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: mdata.c:60
#define IMAP_CAP_IDLE
RFC2177: IDLE.
Definition: private.h:133
@ IMAP_IDLE
Connection is idle.
Definition: private.h:111
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:66
#define IMAP_OPEN_NO_FLAGS
No flags are set.
Definition: private.h:63
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: private.h:74
@ IMAP_EXEC_SUCCESS
Imap command executed or queued successfully.
Definition: private.h:82
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: private.h:67
#define IMAP_FLAGS_PENDING
Flags have changed on the server.
Definition: private.h:68
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:455
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
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mxapi.h:69
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:68
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:66
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:182
void * adata
Private data (for Mailbox backends)
Definition: account.h:42
IMAP-specific Account data -.
Definition: adata.h:40
time_t lastread
last time we read a command for the server
Definition: adata.h:58
ImapCapFlags capabilities
Capability flags.
Definition: adata.h:55
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: adata.h:44
struct Connection * conn
Connection to IMAP server.
Definition: adata.h:41
IMAP-specific Mailbox data -.
Definition: mdata.h:40
time_t last_checked
Last time we checked this mailbox for new mail.
Definition: mailbox.h:105
void * mdata
Driver specific data.
Definition: mailbox.h:132
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:127
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_delete_mailbox()

int imap_delete_mailbox ( struct Mailbox m,
char *  path 
)

Delete a mailbox.

Parameters
mMailbox
pathname of the mailbox to delete
Return values
0Success
-1Failure

Definition at line 505 of file imap.c.

506{
507 char buf[PATH_MAX + 7];
508 char mbox[PATH_MAX] = { 0 };
509 struct Url *url = url_parse(path);
510 if (!url)
511 return -1;
512
514 imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), url->path);
515 url_free(&url);
516 snprintf(buf, sizeof(buf), "DELETE %s", mbox);
518 return -1;
519
520 return 0;
521}
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: private.h:71
void imap_munge_mbox_name(bool unicode, char *dest, size_t dlen, const char *src)
Quote awkward characters in a mailbox name.
Definition: util.c:921
#define PATH_MAX
Definition: mutt.h:42
char * buf
Definition: adata.h:59
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * path
Path.
Definition: url.h:75
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:

◆ imap_sync_mailbox()

enum MxStatus imap_sync_mailbox ( struct Mailbox m,
bool  expunge,
bool  close 
)

Sync all the changes to the server.

Parameters
mMailbox
expungeif true do expunge
closeif true we move imap state to CLOSE
Return values
enumMxStatus
Note
The flag retvals come from a call to imap_check_mailbox()

Definition at line 1471 of file imap.c.

1472{
1473 if (!m)
1474 return -1;
1475
1476 struct Email **emails = NULL;
1477 int rc;
1478
1480 struct ImapMboxData *mdata = imap_mdata_get(m);
1481
1482 if (adata->state < IMAP_SELECTED)
1483 {
1484 mutt_debug(LL_DEBUG2, "no mailbox selected\n");
1485 return -1;
1486 }
1487
1488 /* This function is only called when the calling code expects the context
1489 * to be changed. */
1491
1492 enum MxStatus check = imap_check_mailbox(m, false);
1493 if (check == MX_STATUS_ERROR)
1494 return check;
1495
1496 /* if we are expunging anyway, we can do deleted messages very quickly... */
1497 if (expunge && (m->rights & MUTT_ACL_DELETE))
1498 {
1499 struct UidArray uida = ARRAY_HEAD_INITIALIZER;
1500 select_email_uids(m->emails, m->msg_count, MUTT_DELETED, true, false, &uida);
1501 ARRAY_SORT(&uida, imap_sort_uid, NULL);
1502 rc = imap_exec_msg_set(adata, "UID STORE", "+FLAGS.SILENT (\\Deleted)", &uida);
1503 ARRAY_FREE(&uida);
1504 if (rc < 0)
1505 {
1506 mutt_error(_("Expunge failed"));
1507 return rc;
1508 }
1509
1510 if (rc > 0)
1511 {
1512 /* mark these messages as unchanged so second pass ignores them. Done
1513 * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */
1514 for (int i = 0; i < m->msg_count; i++)
1515 {
1516 struct Email *e = m->emails[i];
1517 if (!e)
1518 break;
1519 if (e->deleted && e->changed)
1520 e->active = false;
1521 }
1522 if (m->verbose)
1523 {
1524 mutt_message(ngettext("Marking %d message deleted...",
1525 "Marking %d messages deleted...", rc),
1526 rc);
1527 }
1528 }
1529 }
1530
1531#ifdef USE_HCACHE
1532 imap_hcache_open(adata, mdata);
1533#endif
1534
1535 /* save messages with real (non-flag) changes */
1536 for (int i = 0; i < m->msg_count; i++)
1537 {
1538 struct Email *e = m->emails[i];
1539 if (!e)
1540 break;
1541
1542 if (e->deleted)
1543 {
1544 imap_cache_del(m, e);
1545#ifdef USE_HCACHE
1546 imap_hcache_del(mdata, imap_edata_get(e)->uid);
1547#endif
1548 }
1549
1550 if (e->active && e->changed)
1551 {
1552#ifdef USE_HCACHE
1553 imap_hcache_put(mdata, e);
1554#endif
1555 /* if the message has been rethreaded or attachments have been deleted
1556 * we delete the message and reupload it.
1557 * This works better if we're expunging, of course. */
1558 if (e->env->changed || e->attach_del)
1559 {
1560 /* L10N: The plural is chosen by the last %d, i.e. the total number */
1561 if (m->verbose)
1562 {
1563 mutt_message(ngettext("Saving changed message... [%d/%d]",
1564 "Saving changed messages... [%d/%d]", m->msg_count),
1565 i + 1, m->msg_count);
1566 }
1567 bool save_append = m->append;
1568 m->append = true;
1570 m->append = save_append;
1571 e->env->changed = false;
1572 }
1573 }
1574 }
1575
1576#ifdef USE_HCACHE
1577 imap_hcache_close(mdata);
1578#endif
1579
1580 /* presort here to avoid doing 10 resorts in imap_exec_msg_set */
1581 emails = mutt_mem_malloc(m->msg_count * sizeof(struct Email *));
1582 memcpy(emails, m->emails, m->msg_count * sizeof(struct Email *));
1583 mutt_qsort_r(emails, m->msg_count, sizeof(struct Email *), imap_sort_email_uid, NULL);
1584
1585 rc = sync_helper(m, emails, m->msg_count, MUTT_ACL_DELETE, MUTT_DELETED, "\\Deleted");
1586 if (rc >= 0)
1587 rc |= sync_helper(m, emails, m->msg_count, MUTT_ACL_WRITE, MUTT_FLAG, "\\Flagged");
1588 if (rc >= 0)
1589 rc |= sync_helper(m, emails, m->msg_count, MUTT_ACL_WRITE, MUTT_OLD, "Old");
1590 if (rc >= 0)
1591 rc |= sync_helper(m, emails, m->msg_count, MUTT_ACL_SEEN, MUTT_READ, "\\Seen");
1592 if (rc >= 0)
1593 rc |= sync_helper(m, emails, m->msg_count, MUTT_ACL_WRITE, MUTT_REPLIED, "\\Answered");
1594
1595 FREE(&emails);
1596
1597 /* Flush the queued flags if any were changed in sync_helper. */
1598 if (rc > 0)
1599 if (imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1600 rc = -1;
1601
1602 if (rc < 0)
1603 {
1604 if (close)
1605 {
1606 if (query_yesorno(_("Error saving flags. Close anyway?"), MUTT_NO) == MUTT_YES)
1607 {
1608 adata->state = IMAP_AUTHENTICATED;
1609 return 0;
1610 }
1611 }
1612 else
1613 {
1614 mutt_error(_("Error saving flags"));
1615 }
1616 return -1;
1617 }
1618
1619 /* Update local record of server state to reflect the synchronization just
1620 * completed. imap_read_headers always overwrites hcache-origin flags, so
1621 * there is no need to mutate the hcache after flag-only changes. */
1622 for (int i = 0; i < m->msg_count; i++)
1623 {
1624 struct Email *e = m->emails[i];
1625 if (!e)
1626 break;
1627 struct ImapEmailData *edata = imap_edata_get(e);
1628 edata->deleted = e->deleted;
1629 edata->flagged = e->flagged;
1630 edata->old = e->old;
1631 edata->read = e->read;
1632 edata->replied = e->replied;
1633 e->changed = false;
1634 }
1635 m->changed = false;
1636
1637 /* We must send an EXPUNGE command if we're not closing. */
1638 if (expunge && !close && (m->rights & MUTT_ACL_DELETE))
1639 {
1640 if (m->verbose)
1641 mutt_message(_("Expunging messages from server..."));
1642 /* Set expunge bit so we don't get spurious reopened messages */
1643 mdata->reopen |= IMAP_EXPUNGE_EXPECTED;
1644 if (imap_exec(adata, "EXPUNGE", IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1645 {
1646 mdata->reopen &= ~IMAP_EXPUNGE_EXPECTED;
1647 imap_error(_("imap_sync_mailbox: EXPUNGE failed"), adata->buf);
1648 return -1;
1649 }
1650 mdata->reopen &= ~IMAP_EXPUNGE_EXPECTED;
1651 }
1652
1653 if (expunge && close)
1654 {
1655 adata->closing = true;
1656 imap_exec(adata, "CLOSE", IMAP_CMD_NO_FLAGS);
1657 adata->state = IMAP_AUTHENTICATED;
1658 }
1659
1660 const bool c_message_cache_clean = cs_subset_bool(NeoMutt->sub, "message_cache_clean");
1661 if (c_message_cache_clean)
1663
1664 return check;
1665}
#define ARRAY_SORT(head, fn, sdata)
Sort an array.
Definition: array.h:279
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:58
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:63
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:71
#define MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition: mailbox.h:70
int mutt_save_message_mbox(struct Mailbox *m_src, struct Email *e, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt, struct Mailbox *m_dst)
Save a message to a given mailbox.
Definition: external.c:738
@ TRANSFORM_NONE
No transformation.
Definition: external.h:42
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: external.h:53
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
int imap_sort_uid(const void *a, const void *b, void *sdata)
Compare two UIDs - Implements sort_t -.
Definition: msg_set.c:55
static int imap_sort_email_uid(const void *a, const void *b, void *sdata)
Compare two Emails by UID - Implements sort_t -.
Definition: imap.c:900
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:67
int imap_cache_clean(struct Mailbox *m)
Delete all the entries in the message cache.
Definition: message.c:1889
int imap_cache_del(struct Mailbox *m, struct Email *e)
Delete an email from the body cache.
Definition: message.c:1870
void imap_allow_reopen(struct Mailbox *m)
Allow re-opening a folder upon expunge.
Definition: util.c:1026
@ IMAP_AUTHENTICATED
Connection is authenticated.
Definition: private.h:107
@ IMAP_SELECTED
Mailbox is selected.
Definition: private.h:108
#define IMAP_EXPUNGE_EXPECTED
Messages will be expunged from the server.
Definition: private.h:65
int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
Add an entry to the header cache.
Definition: util.c:380
void imap_error(const char *where, const char *msg)
Show an error and abort.
Definition: util.c:657
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition: util.c:340
int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
Delete an item from the header cache.
Definition: util.c:398
void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata)
Open a header cache.
Definition: util.c:299
static int sync_helper(struct Mailbox *m, struct Email **emails, int num_emails, AclFlags right, enum MessageType flag, const char *name)
Sync flag changes to the server.
Definition: imap.c:300
static int select_email_uids(struct Email **emails, int num_emails, enum MessageType flag, bool changed, bool invert, struct UidArray *uida)
Create a list of Email UIDs by type.
Definition: imap.c:230
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition: imap.c:1032
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:45
int imap_exec_msg_set(struct ImapAccountData *adata, const char *pre, const char *post, struct UidArray *uida)
Execute a command using a set of UIDs.
Definition: msg_set.c:133
#define _(a)
Definition: message.h:28
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:73
@ MUTT_OLD
Old messages.
Definition: mutt.h:71
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:79
@ MUTT_DELETED
Deleted messages.
Definition: mutt.h:78
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:72
void mutt_qsort_r(void *base, size_t nmemb, size_t size, sort_t compar, void *sdata)
Sort an array, where the comparator has access to opaque data rather than requiring global variables.
Definition: qsort_r.c:67
@ 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_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:327
The envelope/body of an email.
Definition: email.h:39
bool read
Email is read.
Definition: email.h:50
struct Envelope * env
Envelope information.
Definition: email.h:68
void * edata
Driver-specific data.
Definition: email.h:74
bool active
Message is not to be removed.
Definition: email.h:76
bool old
Email is seen, but unread.
Definition: email.h:49
bool changed
Email has been edited.
Definition: email.h:77
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:102
bool flagged
Marked important?
Definition: email.h:47
bool replied
Email has been replied to.
Definition: email.h:51
bool deleted
Email is deleted.
Definition: email.h:78
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:90
bool closing
If true, we are waiting for CLOSE completion.
Definition: adata.h:43
IMAP-specific Email data -.
Definition: edata.h:35
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: mdata.h:45
bool changed
Mailbox has been modified.
Definition: mailbox.h:110
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:109
int msg_count
Total number of messages.
Definition: mailbox.h:88
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:119
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
bool verbose
Display status messages?
Definition: mailbox.h:117
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_path_status()

int imap_path_status ( const char *  path,
bool  queue 
)

Refresh the number of total and new messages.

Parameters
pathMailbox path
queueQueue the STATUS command
Return values
numTotal number of messages

Definition at line 1172 of file imap.c.

1173{
1174 struct Mailbox *m = mx_mbox_find2(path);
1175
1176 const bool is_temp = !m;
1177 if (is_temp)
1178 {
1179 m = mx_path_resolve(path);
1180 if (!mx_mbox_ac_link(m))
1181 {
1182 mailbox_free(&m);
1183 return 0;
1184 }
1185 }
1186
1187 int rc = imap_mailbox_status(m, queue);
1188
1189 if (is_temp)
1190 {
1191 mx_ac_remove(m, false);
1192 mailbox_free(&m);
1193 }
1194
1195 return rc;
1196}
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:90
int imap_mailbox_status(struct Mailbox *m, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1207
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 Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1603
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:249
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1634
A mailbox.
Definition: mailbox.h:79
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_mailbox_status()

int imap_mailbox_status ( struct Mailbox m,
bool  queue 
)

Refresh the number of total and new messages.

Parameters
mMailbox
queueQueue the STATUS command
Return values
numTotal number of messages
-1Error
Note
Prepare the mailbox if we are not connected

Definition at line 1207 of file imap.c.

1208{
1210 struct ImapMboxData *mdata = imap_mdata_get(m);
1211 if (!adata || !mdata)
1212 return -1;
1213 return imap_status(adata, mdata, queue);
1214}
static int imap_status(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1105
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_subscribe()

int imap_subscribe ( char *  path,
bool  subscribe 
)

Subscribe to a mailbox.

Parameters
pathMailbox path
subscribeTrue: subscribe, false: unsubscribe
Return values
0Success
-1Failure

Definition at line 1223 of file imap.c.

1224{
1225 struct ImapAccountData *adata = NULL;
1226 struct ImapMboxData *mdata = NULL;
1227
1228 if (imap_adata_find(path, &adata, &mdata) < 0)
1229 return -1;
1230
1231 if (subscribe)
1232 mutt_message(_("Subscribing to %s..."), mdata->name);
1233 else
1234 mutt_message(_("Unsubscribing from %s..."), mdata->name);
1235
1236 char buf[2048] = { 0 };
1237 snprintf(buf, sizeof(buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mdata->munge_name);
1238
1239 if (imap_exec(adata, buf, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1240 {
1241 imap_mdata_free((void *) &mdata);
1242 return -1;
1243 }
1244
1245 const bool c_imap_check_subscribed = cs_subset_bool(NeoMutt->sub, "imap_check_subscribed");
1246 if (c_imap_check_subscribed)
1247 {
1248 char mbox[1024] = { 0 };
1249 size_t len = snprintf(mbox, sizeof(mbox), "%smailboxes ", subscribe ? "" : "un");
1250 imap_quote_string(mbox + len, sizeof(mbox) - len, path, true);
1251 struct Buffer *err = buf_pool_get();
1252 if (parse_rc_line(mbox, err))
1253 mutt_debug(LL_DEBUG1, "Error adding subscribed mailbox: %s\n", buf_string(err));
1254 buf_pool_release(&err);
1255 }
1256
1257 if (subscribe)
1258 mutt_message(_("Subscribed to %s"), mdata->name);
1259 else
1260 mutt_message(_("Unsubscribed from %s"), mdata->name);
1261 imap_mdata_free((void *) &mdata);
1262 return 0;
1263}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
void imap_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free() -.
Definition: mdata.c:39
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
Quote string according to IMAP rules.
Definition: util.c:847
int imap_adata_find(const char *path, struct ImapAccountData **adata, struct ImapMboxData **mdata)
Find the Account data for this path.
Definition: util.c:73
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
enum CommandResult parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: rc.c:104
String manipulation buffer.
Definition: buffer.h:36
char * name
Mailbox name.
Definition: mdata.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_complete()

int imap_complete ( struct Buffer buf,
const char *  path 
)

Try to complete an IMAP folder path.

Parameters
bufBuffer for result
pathPartial mailbox name to complete
Return values
0Success
-1Failure

Given a partial IMAP folder path, return a string which adds as much to the path as is unique

Definition at line 1275 of file imap.c.

1276{
1277 struct ImapAccountData *adata = NULL;
1278 struct ImapMboxData *mdata = NULL;
1279 char tmp[2048] = { 0 };
1280 struct ImapList listresp = { 0 };
1281 struct Buffer *completion_buf = NULL;
1282 size_t clen;
1283 int completions = 0;
1284 int rc;
1285
1286 if (imap_adata_find(path, &adata, &mdata) < 0)
1287 {
1288 buf_strcpy(buf, path);
1289 return complete_hosts(buf);
1290 }
1291
1292 /* fire off command */
1293 const bool c_imap_list_subscribed = cs_subset_bool(NeoMutt->sub, "imap_list_subscribed");
1294 snprintf(tmp, sizeof(tmp), "%s \"\" \"%s%%\"",
1295 c_imap_list_subscribed ? "LSUB" : "LIST", mdata->real_name);
1296
1297 imap_cmd_start(adata, tmp);
1298
1299 /* and see what the results are */
1300 completion_buf = buf_pool_get();
1301 buf_strcpy(completion_buf, mdata->name);
1302 imap_mdata_free((void *) &mdata);
1303
1304 adata->cmdresult = &listresp;
1305 do
1306 {
1307 listresp.name = NULL;
1308 rc = imap_cmd_step(adata);
1309
1310 if ((rc == IMAP_RES_CONTINUE) && listresp.name)
1311 {
1312 /* if the folder isn't selectable, append delimiter to force browse
1313 * to enter it on second tab. */
1314 if (listresp.noselect)
1315 {
1316 clen = strlen(listresp.name);
1317 listresp.name[clen++] = listresp.delim;
1318 listresp.name[clen] = '\0';
1319 }
1320 /* copy in first word */
1321 if (!completions)
1322 {
1323 buf_strcpy(completion_buf, listresp.name);
1324 completions++;
1325 continue;
1326 }
1327
1328 longest_common_prefix(completion_buf, listresp.name, 0);
1329 completions++;
1330 }
1331 } while (rc == IMAP_RES_CONTINUE);
1332 adata->cmdresult = NULL;
1333
1334 if (completions)
1335 {
1336 /* reformat output */
1337 imap_buf_qualify_path(buf, &adata->conn->account, completion_buf->data);
1338 buf_pretty_mailbox(buf);
1339 buf_fix_dptr(buf);
1340 buf_pool_release(&completion_buf);
1341 return 0;
1342 }
1343
1344 buf_pool_release(&completion_buf);
1345 return -1;
1346}
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1115
void imap_buf_qualify_path(struct Buffer *buf, struct ConnAccount *conn_account, char *path)
Make an absolute IMAP folder target to a buffer.
Definition: util.c:830
static size_t longest_common_prefix(struct Buffer *buf, const char *src, size_t start)
Find longest prefix common to two strings.
Definition: imap.c:348
static int complete_hosts(struct Buffer *buf)
Look for completion matches for mailboxes.
Definition: imap.c:371
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:554
char * data
Pointer to data.
Definition: buffer.h:37
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:49
struct ImapList * cmdresult
Definition: adata.h:66
Items in an IMAP browser.
Definition: private.h:149
bool noselect
Definition: private.h:152
char * name
Definition: private.h:150
char delim
Definition: private.h:151
char * real_name
Original Mailbox name, e.g.: INBOX can be just \0.
Definition: mdata.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_fast_trash()

int imap_fast_trash ( struct Mailbox m,
const char *  dest 
)

Use server COPY command to copy deleted messages to trash.

Parameters
mMailbox
destMailbox to move to
Return values
-1Error
0Success
1Non-fatal error - try fetch/append

Definition at line 1356 of file imap.c.

1357{
1358 char prompt[1024] = { 0 };
1359 int rc = -1;
1360 bool triedcreate = false;
1361 enum QuadOption err_continue = MUTT_NO;
1362
1364 struct ImapAccountData *dest_adata = NULL;
1365 struct ImapMboxData *dest_mdata = NULL;
1366
1367 if (imap_adata_find(dest, &dest_adata, &dest_mdata) < 0)
1368 return -1;
1369
1370 struct Buffer *sync_cmd = buf_pool_get();
1371
1372 /* check that the save-to folder is in the same account */
1373 if (!imap_account_match(&(adata->conn->account), &(dest_adata->conn->account)))
1374 {
1375 mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1376 goto out;
1377 }
1378
1379 for (int i = 0; i < m->msg_count; i++)
1380 {
1381 struct Email *e = m->emails[i];
1382 if (!e)
1383 break;
1384 if (e->active && e->changed && e->deleted && !e->purge)
1385 {
1386 rc = imap_sync_message_for_copy(m, e, sync_cmd, &err_continue);
1387 if (rc < 0)
1388 {
1389 mutt_debug(LL_DEBUG1, "could not sync\n");
1390 goto out;
1391 }
1392 }
1393 }
1394
1395 /* loop in case of TRYCREATE */
1396 do
1397 {
1398 struct UidArray uida = ARRAY_HEAD_INITIALIZER;
1399 select_email_uids(m->emails, m->msg_count, MUTT_TRASH, false, false, &uida);
1400 ARRAY_SORT(&uida, imap_sort_uid, NULL);
1401 rc = imap_exec_msg_set(adata, "UID COPY", dest_mdata->munge_name, &uida);
1402 if (rc == 0)
1403 {
1404 mutt_debug(LL_DEBUG1, "No messages to trash\n");
1405 rc = -1;
1406 goto out;
1407 }
1408 else if (rc < 0)
1409 {
1410 mutt_debug(LL_DEBUG1, "could not queue copy\n");
1411 goto out;
1412 }
1413 else if (m->verbose)
1414 {
1415 mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1416 rc, dest_mdata->name);
1417 }
1418 ARRAY_FREE(&uida);
1419
1420 /* let's get it on */
1421 rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1422 if (rc == IMAP_EXEC_ERROR)
1423 {
1424 if (triedcreate)
1425 {
1426 mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", dest_mdata->name);
1427 break;
1428 }
1429 /* bail out if command failed for reasons other than nonexistent target */
1430 if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1431 break;
1432 mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1433 snprintf(prompt, sizeof(prompt), _("Create %s?"), dest_mdata->name);
1434 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
1435 if (c_confirm_create &&
1436 (query_yesorno_help(prompt, MUTT_YES, NeoMutt->sub, "confirm_create") != MUTT_YES))
1437 {
1439 goto out;
1440 }
1441 if (imap_create_mailbox(adata, dest_mdata->name) < 0)
1442 break;
1443 triedcreate = true;
1444 }
1445 } while (rc == IMAP_EXEC_ERROR);
1446
1447 if (rc != IMAP_EXEC_SUCCESS)
1448 {
1449 imap_error("imap_fast_trash", adata->buf);
1450 goto out;
1451 }
1452
1453 rc = IMAP_EXEC_SUCCESS;
1454
1455out:
1456 buf_pool_release(&sync_cmd);
1457 imap_mdata_free((void *) &dest_mdata);
1458
1459 return ((rc == IMAP_EXEC_SUCCESS) ? 0 : -1);
1460}
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
@ IMAP_EXEC_ERROR
Imap command failure.
Definition: private.h:83
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition: util.c:1054
char * imap_get_qualifier(char *buf)
Get the qualifier from a tagged response.
Definition: util.c:768
int imap_create_mailbox(struct ImapAccountData *adata, const char *mailbox)
Create a new mailbox.
Definition: imap.c:436
int imap_sync_message_for_copy(struct Mailbox *m, struct Email *e, struct Buffer *cmd, enum QuadOption *err_continue)
Update server to reflect the flags of a single message.
Definition: imap.c:926
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:242
@ MUTT_TRASH
Trashed messages.
Definition: mutt.h:85
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition: question.c:342
bool purge
Skip trash folder when deleting.
Definition: email.h:79
char * munge_name
Munged version of the mailbox name.
Definition: mdata.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_notify_delete_email()

void imap_notify_delete_email ( struct Mailbox m,
struct Email e 
)

Inform IMAP that an Email has been deleted.

Parameters
mMailbox
eEmail

Definition at line 648 of file imap.c.

649{
650 struct ImapMboxData *mdata = imap_mdata_get(m);
652
653 if (!mdata || !edata)
654 return;
655
656 imap_msn_remove(&mdata->msn, edata->msn - 1);
657 edata->msn = 0;
658}
void imap_msn_remove(struct MSNArray *msn, size_t idx)
Remove an entry from the cache.
Definition: msn.c:114
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_browse()

int imap_browse ( const char *  path,
struct BrowserState state 
)

IMAP hook into the folder browser.

Parameters
pathCurrent folder
stateBrowserState to populate
Return values
0Success
-1Failure

Fill out browser_state, given a current folder to browse

Definition at line 197 of file browse.c.

198{
199 struct ImapAccountData *adata = NULL;
200 struct ImapList list = { 0 };
201 struct ConnAccount cac = { { 0 } };
202 char buf[PATH_MAX + 16];
203 char mbox[PATH_MAX] = { 0 };
204 char munged_mbox[PATH_MAX] = { 0 };
205 const char *list_cmd = NULL;
206 int len;
207 int n;
208 char ctmp;
209 bool showparents = false;
210
211 if (imap_parse_path(path, &cac, buf, sizeof(buf)))
212 {
213 mutt_error(_("%s is an invalid IMAP path"), path);
214 return -1;
215 }
216
217 const bool c_imap_check_subscribed = cs_subset_bool(NeoMutt->sub, "imap_check_subscribed");
218 cs_subset_str_native_set(NeoMutt->sub, "imap_check_subscribed", false, NULL);
219
220 // Pick first mailbox connected to the same server
221 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
223 struct MailboxNode *np = NULL;
224 STAILQ_FOREACH(np, &ml, entries)
225 {
226 adata = imap_adata_get(np->mailbox);
227 // Pick first mailbox connected on the same server
228 if (imap_account_match(&adata->conn->account, &cac))
229 break;
230 adata = NULL;
231 }
233 if (!adata)
234 goto fail;
235
236 const bool c_imap_list_subscribed = cs_subset_bool(NeoMutt->sub, "imap_list_subscribed");
237 if (c_imap_list_subscribed)
238 {
239 /* RFC3348 section 3 states LSUB is unreliable for hierarchy information.
240 * The newer LIST extensions are designed for this. */
242 list_cmd = "LIST (SUBSCRIBED RECURSIVEMATCH)";
243 else
244 list_cmd = "LSUB";
245 }
246 else
247 {
248 list_cmd = "LIST";
249 }
250
251 mutt_message(_("Getting folder list..."));
252
253 /* skip check for parents when at the root */
254 if (buf[0] == '\0')
255 {
256 mbox[0] = '\0';
257 n = 0;
258 }
259 else
260 {
261 imap_fix_path(adata->delim, buf, mbox, sizeof(mbox));
262 n = mutt_str_len(mbox);
263 }
264
265 if (n)
266 {
267 int rc;
268 mutt_debug(LL_DEBUG3, "mbox: %s\n", mbox);
269
270 /* if our target exists and has inferiors, enter it if we
271 * aren't already going to */
272 imap_munge_mbox_name(adata->unicode, munged_mbox, sizeof(munged_mbox), mbox);
273 len = snprintf(buf, sizeof(buf), "%s \"\" %s", list_cmd, munged_mbox);
275 snprintf(buf + len, sizeof(buf) - len, " RETURN (CHILDREN)");
276 imap_cmd_start(adata, buf);
277 adata->cmdresult = &list;
278 do
279 {
280 list.name = 0;
281 rc = imap_cmd_step(adata);
282 if ((rc == IMAP_RES_CONTINUE) && list.name)
283 {
284 if (!list.noinferiors && list.name[0] &&
285 (imap_mxcmp(list.name, mbox) == 0) && (n < sizeof(mbox) - 1))
286 {
287 mbox[n++] = list.delim;
288 mbox[n] = '\0';
289 }
290 }
291 } while (rc == IMAP_RES_CONTINUE);
292 adata->cmdresult = NULL;
293
294 /* if we're descending a folder, mark it as current in browser_state */
295 if (mbox[n - 1] == list.delim)
296 {
297 showparents = true;
298 imap_qualify_path(buf, sizeof(buf), &cac, mbox);
299 state->folder = mutt_str_dup(buf);
300 n--;
301 }
302
303 /* Find superiors to list
304 * Note: UW-IMAP servers return folder + delimiter when asked to list
305 * folder + delimiter. Cyrus servers don't. So we ask for folder,
306 * and tack on delimiter ourselves.
307 * Further note: UW-IMAP servers return nothing when asked for
308 * NAMESPACES without delimiters at the end. Argh! */
309 for (n--; n >= 0 && mbox[n] != list.delim; n--)
310 ; // do nothing
311
312 if (n > 0) /* "aaaa/bbbb/" -> "aaaa" */
313 {
314 /* forget the check, it is too delicate (see above). Have we ever
315 * had the parent not exist? */
316 ctmp = mbox[n];
317 mbox[n] = '\0';
318
319 if (showparents)
320 {
321 mutt_debug(LL_DEBUG3, "adding parent %s\n", mbox);
322 add_folder(list.delim, mbox, true, false, state, true);
323 }
324
325 /* if our target isn't a folder, we are in our superior */
326 if (!state->folder)
327 {
328 /* store folder with delimiter */
329 mbox[n++] = ctmp;
330 ctmp = mbox[n];
331 mbox[n] = '\0';
332 imap_qualify_path(buf, sizeof(buf), &cac, mbox);
333 state->folder = mutt_str_dup(buf);
334 }
335 mbox[n] = ctmp;
336 }
337 else
338 {
339 /* "/bbbb/" -> add "/", "aaaa/" -> add "" */
340 char relpath[2] = { 0 };
341 /* folder may be "/" */
342 snprintf(relpath, sizeof(relpath), "%c", (n < 0) ? '\0' : adata->delim);
343 if (showparents)
344 add_folder(adata->delim, relpath, true, false, state, true);
345 if (!state->folder)
346 {
347 imap_qualify_path(buf, sizeof(buf), &cac, relpath);
348 state->folder = mutt_str_dup(buf);
349 }
350 }
351 }
352
353 /* no namespace, no folder: set folder to host only */
354 if (!state->folder)
355 {
356 imap_qualify_path(buf, sizeof(buf), &cac, NULL);
357 state->folder = mutt_str_dup(buf);
358 }
359
360 mutt_debug(LL_DEBUG3, "Quoting mailbox scan: %s -> ", mbox);
361 snprintf(buf, sizeof(buf), "%s%%", mbox);
362 imap_munge_mbox_name(adata->unicode, munged_mbox, sizeof(munged_mbox), buf);
363 mutt_debug(LL_DEBUG3, "%s\n", munged_mbox);
364 len = snprintf(buf, sizeof(buf), "%s \"\" %s", list_cmd, munged_mbox);
366 snprintf(buf + len, sizeof(buf) - len, " RETURN (CHILDREN)");
367 if (browse_add_list_result(adata, buf, state, false))
368 goto fail;
369
370 if (ARRAY_EMPTY(&state->entry))
371 {
372 // L10N: (%s) is the name / path of the folder we were trying to browse
373 mutt_error(_("No such folder: %s"), path);
374 goto fail;
375 }
376
378
379 cs_subset_str_native_set(NeoMutt->sub, "imap_check_subscribed",
380 c_imap_check_subscribed, NULL);
381 return 0;
382
383fail:
384 cs_subset_str_native_set(NeoMutt->sub, "imap_check_subscribed",
385 c_imap_check_subscribed, NULL);
386 return -1;
387}
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:74
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
static int browse_add_list_result(struct ImapAccountData *adata, const char *cmd, struct BrowserState *bstate, bool isparent)
Add entries to the folder browser.
Definition: browse.c:155
static void add_folder(char delim, char *folder, bool noselect, bool noinferiors, struct BrowserState *state, bool isparent)
Format and add an IMAP folder to the browser.
Definition: browse.c:69
int imap_parse_path(const char *path, struct ConnAccount *cac, char *mailbox, size_t mailboxlen)
Parse an IMAP mailbox name into ConnAccount, name.
Definition: util.c:474
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:545
void imap_qualify_path(char *buf, size_t buflen, struct ConnAccount *conn_account, char *path)
Make an absolute IMAP folder target.
Definition: util.c:816
char * imap_fix_path(char delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition: util.c:679
#define IMAP_CAP_LIST_EXTENDED
RFC5258: IMAP4 LIST Command Extensions.
Definition: private.h:138
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:490
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:163
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:186
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
char * folder
Folder name.
Definition: lib.h:147
struct BrowserEntryArray entry
Array of files / dirs / mailboxes.
Definition: lib.h:145
Login details for a remote server.
Definition: connaccount.h:53
char delim
Path delimiter.
Definition: adata.h:75
bool unicode
If true, we can send UTF-8, and the server will use UTF8 rather than mUTF7.
Definition: adata.h:62
bool noinferiors
Definition: private.h:153
List of Mailboxes.
Definition: mailbox.h:166
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:167
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:

◆ imap_mailbox_create()

int imap_mailbox_create ( const char *  path)

Create a new IMAP mailbox.

Parameters
pathMailbox to create
Return values
0Success
-1Failure

Prompt for a new mailbox name, and try to create it

Definition at line 397 of file browse.c.

398{
399 struct ImapAccountData *adata = NULL;
400 struct ImapMboxData *mdata = NULL;
401 struct Buffer *name = buf_pool_get();
402 int rc = -1;
403
404 if (imap_adata_find(path, &adata, &mdata) < 0)
405 {
406 mutt_debug(LL_DEBUG1, "Couldn't find open connection to %s\n", path);
407 goto done;
408 }
409
410 /* append a delimiter if necessary */
411 const size_t n = buf_strcpy(name, mdata->real_name);
412 if ((n != 0) && (name->data[n - 1] != adata->delim))
413 {
414 buf_addch(name, adata->delim);
415 }
416
417 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
418 if (mw_get_field(_("Create mailbox: "), name, MUTT_COMP_NO_FLAGS, HC_MAILBOX,
419 &CompleteMailboxOps, &cdata) != 0)
420 {
421 goto done;
422 }
423
424 if (buf_is_empty(name))
425 {
426 mutt_error(_("Mailbox must have a name"));
427 goto done;
428 }
429
430 if (imap_create_mailbox(adata, buf_string(name)) < 0)
431 goto done;
432
433 imap_mdata_free((void *) &mdata);
434 mutt_message(_("Mailbox created"));
435 mutt_sleep(0);
436 rc = 0;
437
438done:
439 imap_mdata_free((void *) &mdata);
440 buf_pool_release(&name);
441 return rc;
442}
const struct CompleteOps CompleteMailboxOps
Auto-Completion of Files / Mailboxes.
Definition: complete.c:162
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:290
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:274
@ HC_MAILBOX
Mailboxes.
Definition: lib.h:57
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:878
Input for the file completion function.
Definition: curs_lib.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_mailbox_rename()

int imap_mailbox_rename ( const char *  path)

Rename a mailbox.

Parameters
pathMailbox to rename
Return values
0Success
-1Failure

The user will be prompted for a new name.

Definition at line 452 of file browse.c.

453{
454 struct ImapAccountData *adata = NULL;
455 struct ImapMboxData *mdata = NULL;
456 struct Buffer *buf = NULL;
457 struct Buffer *newname = NULL;
458 int rc = -1;
459
460 if (imap_adata_find(path, &adata, &mdata) < 0)
461 {
462 mutt_debug(LL_DEBUG1, "Couldn't find open connection to %s\n", path);
463 goto done;
464 }
465
466 if (mdata->real_name[0] == '\0')
467 {
468 mutt_error(_("Can't rename root folder"));
469 goto done;
470 }
471
472 buf = buf_pool_get();
473 newname = buf_pool_get();
474
475 buf_printf(buf, _("Rename mailbox %s to: "), mdata->name);
476 buf_strcpy(newname, mdata->name);
477
478 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
480 &CompleteMailboxOps, &cdata) != 0)
481 {
482 goto done;
483 }
484
485 if (buf_is_empty(newname))
486 {
487 mutt_error(_("Mailbox must have a name"));
488 goto done;
489 }
490
491 imap_fix_path(adata->delim, buf_string(newname), buf->data, buf->dsize);
492
493 if (imap_rename_mailbox(adata, mdata->name, buf_string(buf)) < 0)
494 {
495 mutt_error(_("Rename failed: %s"), imap_get_qualifier(adata->buf));
496 goto done;
497 }
498
499 mutt_message(_("Mailbox renamed"));
500 mutt_sleep(0);
501 rc = 0;
502
503done:
504 imap_mdata_free((void *) &mdata);
505 buf_pool_release(&buf);
506 buf_pool_release(&newname);
507
508 return rc;
509}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
int imap_rename_mailbox(struct ImapAccountData *adata, char *oldname, const char *newname)
Rename a mailbox.
Definition: imap.c:478
size_t dsize
Length of data.
Definition: buffer.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_copy_messages()

int imap_copy_messages ( struct Mailbox m,
struct EmailArray *  ea,
const char *  dest,
enum MessageSaveOpt  save_opt 
)

Server COPY messages to another folder.

Parameters
mMailbox
eaArray of Emails to copy
destDestination folder
save_optCopy or move, e.g. SAVE_MOVE
Return values
-1Error
0Success
1Non-fatal error - try fetch/append

Definition at line 1688 of file message.c.

1690{
1691 if (!m || !ea || ARRAY_EMPTY(ea) || !dest)
1692 return -1;
1693
1694 char buf[PATH_MAX] = { 0 };
1695 char mbox[PATH_MAX] = { 0 };
1696 char mmbox[PATH_MAX] = { 0 };
1697 char prompt[PATH_MAX + 64];
1698 int rc;
1699 struct ConnAccount cac = { { 0 } };
1700 enum QuadOption err_continue = MUTT_NO;
1701 int triedcreate = 0;
1702 struct Email *e_cur = *ARRAY_GET(ea, 0);
1703 bool single = (ARRAY_SIZE(ea) == 1);
1705
1706 if (single && e_cur->attach_del)
1707 {
1708 mutt_debug(LL_DEBUG3, "#1 Message contains attachments to be deleted\n");
1709 return 1;
1710 }
1711
1712 if (imap_parse_path(dest, &cac, buf, sizeof(buf)))
1713 {
1714 mutt_debug(LL_DEBUG1, "bad destination %s\n", dest);
1715 return -1;
1716 }
1717
1718 /* check that the save-to folder is in the same account */
1719 if (!imap_account_match(&adata->conn->account, &cac))
1720 {
1721 mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1722 return 1;
1723 }
1724
1725 imap_fix_path(adata->delim, buf, mbox, sizeof(mbox));
1726 if (*mbox == '\0')
1727 mutt_str_copy(mbox, "INBOX", sizeof(mbox));
1728 imap_munge_mbox_name(adata->unicode, mmbox, sizeof(mmbox), mbox);
1729
1730 /* loop in case of TRYCREATE */
1731 struct Buffer *cmd = buf_pool_get();
1732 struct Buffer *sync_cmd = buf_pool_get();
1733 do
1734 {
1735 buf_reset(sync_cmd);
1736 buf_reset(cmd);
1737
1738 if (single)
1739 {
1740 mutt_message(_("Copying message %d to %s..."), e_cur->index + 1, mbox);
1741 buf_add_printf(cmd, "UID COPY %u %s", imap_edata_get(e_cur)->uid, mmbox);
1742
1743 if (e_cur->active && e_cur->changed)
1744 {
1745 rc = imap_sync_message_for_copy(m, e_cur, sync_cmd, &err_continue);
1746 if (rc < 0)
1747 {
1748 mutt_debug(LL_DEBUG1, "#2 could not sync\n");
1749 goto out;
1750 }
1751 }
1752 rc = imap_exec(adata, buf_string(cmd), IMAP_CMD_QUEUE);
1753 if (rc != IMAP_EXEC_SUCCESS)
1754 {
1755 mutt_debug(LL_DEBUG1, "#2 could not queue copy\n");
1756 goto out;
1757 }
1758 }
1759 else /* copy tagged messages */
1760 {
1761 /* if any messages have attachments to delete, fall through to FETCH
1762 * and APPEND. TODO: Copy what we can with COPY, fall through for the
1763 * remainder. */
1764 struct Email **ep = NULL;
1765 ARRAY_FOREACH(ep, ea)
1766 {
1767 struct Email *e = *ep;
1768 if (e->attach_del)
1769 {
1770 mutt_debug(LL_DEBUG3, "#2 Message contains attachments to be deleted\n");
1771 rc = 1;
1772 goto out;
1773 }
1774
1775 if (e->active && e->changed)
1776 {
1777 rc = imap_sync_message_for_copy(m, e, sync_cmd, &err_continue);
1778 if (rc < 0)
1779 {
1780 mutt_debug(LL_DEBUG1, "#1 could not sync\n");
1781 goto out;
1782 }
1783 }
1784 }
1785
1786 struct UidArray uida = ARRAY_HEAD_INITIALIZER;
1787 emails_to_uid_array(ea, &uida);
1788 rc = imap_exec_msg_set(adata, "UID COPY", mmbox, &uida);
1789 ARRAY_FREE(&uida);
1790
1791 if (rc == 0)
1792 {
1793 mutt_debug(LL_DEBUG1, "No messages tagged\n");
1794 rc = -1;
1795 goto out;
1796 }
1797 else if (rc < 0)
1798 {
1799 mutt_debug(LL_DEBUG1, "#1 could not queue copy\n");
1800 goto out;
1801 }
1802 else
1803 {
1804 mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1805 rc, mbox);
1806 }
1807 }
1808
1809 /* let's get it on */
1810 rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1811 if (rc == IMAP_EXEC_ERROR)
1812 {
1813 if (triedcreate)
1814 {
1815 mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", mbox);
1816 break;
1817 }
1818 /* bail out if command failed for reasons other than nonexistent target */
1819 if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1820 break;
1821 mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1822 snprintf(prompt, sizeof(prompt), _("Create %s?"), mbox);
1823 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
1824 if (c_confirm_create &&
1825 (query_yesorno_help(prompt, MUTT_YES, NeoMutt->sub, "confirm_create") != MUTT_YES))
1826 {
1828 goto out;
1829 }
1830 if (imap_create_mailbox(adata, mbox) < 0)
1831 break;
1832 triedcreate = 1;
1833 }
1834 } while (rc == IMAP_EXEC_ERROR);
1835
1836 if (rc != 0)
1837 {
1838 imap_error("imap_copy_messages", adata->buf);
1839 goto out;
1840 }
1841
1842 /* cleanup */
1843 if (save_opt == SAVE_MOVE)
1844 {
1845 struct Email **ep = NULL;
1846 ARRAY_FOREACH(ep, ea)
1847 {
1848 struct Email *e = *ep;
1849 mutt_set_flag(m, e, MUTT_DELETE, true, true);
1850 mutt_set_flag(m, e, MUTT_PURGE, true, true);
1851 }
1852 }
1853
1854 rc = 0;
1855
1856out:
1857 buf_pool_release(&cmd);
1858 buf_pool_release(&sync_cmd);
1859
1860 return (rc < 0) ? -1 : rc;
1861}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:87
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:109
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:75
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
static int emails_to_uid_array(struct EmailArray *ea, struct UidArray *uida)
Extract IMAP UIDs from Emails.
Definition: message.c:1663
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: private.h:73
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:575
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:77
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:75
int index
The absolute (unsorted) message number.
Definition: email.h:113
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_logout_all()

void imap_logout_all ( void  )

Close all open connections.

Quick and dirty until we can make sure we've got all the context we need.

Definition at line 554 of file imap.c.

555{
556 struct Account *np = NULL;
557 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
558 {
559 if (np->type != MUTT_IMAP)
560 continue;
561
562 struct ImapAccountData *adata = np->adata;
563 if (!adata)
564 continue;
565
566 struct Connection *conn = adata->conn;
567 if (!conn || (conn->fd < 0))
568 continue;
569
570 mutt_message(_("Closing connection to %s..."), conn->account.host);
571 imap_logout(np->adata);
573 }
574}
static void imap_logout(struct ImapAccountData *adata)
Gracefully log out of server.
Definition: imap.c:527
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
A group of associated Mailboxes.
Definition: account.h:36
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:37
char host[128]
Server to login to.
Definition: connaccount.h:54
int fd
Socket file descriptor.
Definition: connection.h:53
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_expand_path()

int imap_expand_path ( struct Buffer path)

Buffer wrapper around imap_path_canon()

Parameters
pathPath to expand
Return values
0Success
-1Failure
Note
The path is expanded in place

Definition at line 2385 of file imap.c.

2386{
2387 buf_alloc(path, PATH_MAX);
2388 return imap_path_canon(path);
2389}
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:336
int imap_path_canon(struct Buffer *path)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition: imap.c:2359
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_parse_path()

int imap_parse_path ( const char *  path,
struct ConnAccount cac,
char *  mailbox,
size_t  mailboxlen 
)

Parse an IMAP mailbox name into ConnAccount, name.

Parameters
pathMailbox path to parse
cacAccount credentials
mailboxBuffer for mailbox name
mailboxlenLength of buffer
Return values
0Success
-1Failure

Given an IMAP mailbox name, return host, port and a path IMAP servers will recognize.

Definition at line 474 of file util.c.

475{
476 static unsigned short ImapPort = 0;
477 static unsigned short ImapsPort = 0;
478
479 if (ImapPort == 0)
480 {
481 struct servent *service = getservbyname("imap", "tcp");
482 if (service)
483 ImapPort = ntohs(service->s_port);
484 else
485 ImapPort = IMAP_PORT;
486 mutt_debug(LL_DEBUG3, "Using default IMAP port %d\n", ImapPort);
487 }
488
489 if (ImapsPort == 0)
490 {
491 struct servent *service = getservbyname("imaps", "tcp");
492 if (service)
493 ImapsPort = ntohs(service->s_port);
494 else
495 ImapsPort = IMAP_SSL_PORT;
496 mutt_debug(LL_DEBUG3, "Using default IMAPS port %d\n", ImapsPort);
497 }
498
499 /* Defaults */
500 cac->port = ImapPort;
502 cac->service = "imap";
504
505 struct Url *url = url_parse(path);
506 if (!url)
507 return -1;
508
509 if ((url->scheme != U_IMAP) && (url->scheme != U_IMAPS))
510 {
511 url_free(&url);
512 return -1;
513 }
514
515 if ((mutt_account_fromurl(cac, url) < 0) || (cac->host[0] == '\0'))
516 {
517 url_free(&url);
518 return -1;
519 }
520
521 if (url->scheme == U_IMAPS)
522 cac->flags |= MUTT_ACCT_SSL;
523
524 mutt_str_copy(mailbox, url->path, mailboxlen);
525
526 url_free(&url);
527
528 if ((cac->flags & MUTT_ACCT_SSL) && !(cac->flags & MUTT_ACCT_PORT))
529 cac->port = ImapsPort;
530
531 return 0;
532}
#define MUTT_ACCT_SSL
Account uses SSL/TLS.
Definition: connaccount.h:47
#define MUTT_ACCT_PORT
Port field has been set.
Definition: connaccount.h:43
static const char * imap_get_field(enum ConnAccountField field, void *gf_data)
Get connection login credentials - Implements ConnAccount::get_field() -.
Definition: util.c:205
#define IMAP_PORT
Default port for IMAP.
Definition: private.h:44
#define IMAP_SSL_PORT
Port for IMAP over SSL/TLS.
Definition: private.h:45
int mutt_account_fromurl(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
Definition: mutt_account.c:44
@ MUTT_ACCT_TYPE_IMAP
Imap Account.
Definition: mutt_account.h:38
const char * service
Name of the service, e.g. "imap".
Definition: connaccount.h:61
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Definition: connaccount.h:70
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition: connaccount.h:59
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:60
unsigned short port
Port to connect to.
Definition: connaccount.h:58
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:70
@ U_IMAP
Url is imap://.
Definition: url.h:39
@ U_IMAPS
Url is imaps://.
Definition: url.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_pretty_mailbox()

void imap_pretty_mailbox ( char *  path,
size_t  pathlen,
const char *  folder 
)

Prettify an IMAP mailbox name.

Parameters
pathMailbox name to be tidied
pathlenLength of path
folderPath to use for '+' abbreviations

Called by mutt_pretty_mailbox() to make IMAP paths look nice.

Definition at line 581 of file util.c.

582{
583 struct ConnAccount cac_target = { { 0 } };
584 struct ConnAccount cac_home = { { 0 } };
585 struct Url url = { 0 };
586 const char *delim = NULL;
587 int tlen;
588 int hlen = 0;
589 bool home_match = false;
590 char target_mailbox[1024] = { 0 };
591 char home_mailbox[1024] = { 0 };
592
593 if (imap_parse_path(path, &cac_target, target_mailbox, sizeof(target_mailbox)) < 0)
594 return;
595
596 if (imap_path_probe(folder, NULL) != MUTT_IMAP)
597 goto fallback;
598
599 if (imap_parse_path(folder, &cac_home, home_mailbox, sizeof(home_mailbox)) < 0)
600 goto fallback;
601
602 tlen = mutt_str_len(target_mailbox);
603 hlen = mutt_str_len(home_mailbox);
604
605 /* check whether we can do '+' substitution */
606 if (tlen && imap_account_match(&cac_home, &cac_target) &&
607 mutt_strn_equal(home_mailbox, target_mailbox, hlen))
608 {
609 const char *const c_imap_delim_chars = cs_subset_string(NeoMutt->sub, "imap_delim_chars");
610 if (hlen == 0)
611 {
612 home_match = true;
613 }
614 else if (c_imap_delim_chars)
615 {
616 for (delim = c_imap_delim_chars; *delim != '\0'; delim++)
617 if (target_mailbox[hlen] == *delim)
618 home_match = true;
619 }
620 }
621
622 /* do the '+' substitution */
623 if (home_match)
624 {
625 *path++ = '+';
626 /* copy remaining path, skipping delimiter */
627 if (hlen != 0)
628 hlen++;
629 memcpy(path, target_mailbox + hlen, tlen - hlen);
630 path[tlen - hlen] = '\0';
631 return;
632 }
633
634fallback:
635 mutt_account_tourl(&cac_target, &url);
636 url.path = target_mailbox;
637 url_tostring(&url, path, pathlen, U_NO_FLAGS);
638}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
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
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:419
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:80
int url_tostring(const struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition: url.c:423
#define U_NO_FLAGS
Definition: url.h:49
int imap_parse_path(const char *path, struct ConnAccount *cac, char *mailbox, size_t mailboxlen)
Parse an IMAP mailbox name into ConnAccount, name.
Definition: util.c:474
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition: util.c:1054
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_mxcmp()

int imap_mxcmp ( const char *  mx1,
const char *  mx2 
)

Compare mailbox names, giving priority to INBOX.

Parameters
mx1First mailbox name
mx2Second mailbox name
Return values
<0First mailbox precedes Second mailbox
0Mailboxes are the same
>0Second mailbox precedes First mailbox

Like a normal sort function except that "INBOX" will be sorted to the beginning of the list.

Definition at line 545 of file util.c.

546{
547 char *b1 = NULL;
548 char *b2 = NULL;
549 int rc;
550
551 if (!mx1 || (*mx1 == '\0'))
552 mx1 = "INBOX";
553 if (!mx2 || (*mx2 == '\0'))
554 mx2 = "INBOX";
555 if (mutt_istr_equal(mx1, "INBOX") && mutt_istr_equal(mx2, "INBOX"))
556 {
557 return 0;
558 }
559
560 b1 = mutt_mem_malloc(strlen(mx1) + 1);
561 b2 = mutt_mem_malloc(strlen(mx2) + 1);
562
563 imap_fix_path('\0', mx1, b1, strlen(mx1) + 1);
564 imap_fix_path('\0', mx2, b2, strlen(mx2) + 1);
565
566 rc = mutt_str_cmp(b1, b2);
567 FREE(&b1);
568 FREE(&b2);
569
570 return rc;
571}
int mutt_str_cmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:393
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:666
char * imap_fix_path(char delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition: util.c:679
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_wait_keep_alive()

int imap_wait_keep_alive ( pid_t  pid)

Wait for a process to change state.

Parameters
pidProcess ID to listen to
Return values
num'wstatus' from waitpid()

Definition at line 979 of file util.c.

980{
981 struct sigaction oldalrm = { 0 };
982 struct sigaction act = { 0 };
983 sigset_t oldmask = { 0 };
984 int rc;
985
986 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
987 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", true, NULL);
988 OptKeepQuiet = true;
989
990 sigprocmask(SIG_SETMASK, NULL, &oldmask);
991
992 sigemptyset(&act.sa_mask);
993 act.sa_handler = mutt_sig_empty_handler;
994#ifdef SA_INTERRUPT
995 act.sa_flags = SA_INTERRUPT;
996#else
997 act.sa_flags = 0;
998#endif
999
1000 sigaction(SIGALRM, &act, &oldalrm);
1001
1002 const short c_imap_keep_alive = cs_subset_number(NeoMutt->sub, "imap_keep_alive");
1003 alarm(c_imap_keep_alive);
1004 while ((waitpid(pid, &rc, 0) < 0) && (errno == EINTR))
1005 {
1006 alarm(0); /* cancel a possibly pending alarm */
1008 alarm(c_imap_keep_alive);
1009 }
1010
1011 alarm(0); /* cancel a possibly pending alarm */
1012
1013 sigaction(SIGALRM, &oldalrm, NULL);
1014 sigprocmask(SIG_SETMASK, &oldmask, NULL);
1015
1016 OptKeepQuiet = false;
1017 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1018
1019 return rc;
1020}
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition: globals.c:66
void mutt_sig_empty_handler(int sig)
Dummy signal handler.
Definition: signal.c:73
void imap_keep_alive(void)
Poll the current folder to keep the connection alive.
Definition: util.c:955
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_keep_alive()

void imap_keep_alive ( void  )

Poll the current folder to keep the connection alive.

Definition at line 955 of file util.c.

956{
957 time_t now = mutt_date_now();
958 struct Account *np = NULL;
959 const short c_imap_keep_alive = cs_subset_number(NeoMutt->sub, "imap_keep_alive");
960 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
961 {
962 if (np->type != MUTT_IMAP)
963 continue;
964
965 struct ImapAccountData *adata = np->adata;
966 if (!adata || !adata->mailbox)
967 continue;
968
969 if ((adata->state >= IMAP_AUTHENTICATED) && (now >= (adata->lastread + c_imap_keep_alive)))
970 imap_check_mailbox(adata->mailbox, true);
971 }
972}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_get_parent_path()

void imap_get_parent_path ( const char *  path,
char *  buf,
size_t  buflen 
)

Get the path of the parent folder.

Parameters
pathMailbox whose parent is to be determined
bufBuffer for the result
buflenLength of the buffer

Provided an imap path, returns in buf the parent directory if existent. Else returns the same path.

Definition at line 162 of file util.c.

163{
164 struct ImapAccountData *adata = NULL;
165 struct ImapMboxData *mdata = NULL;
166 char mbox[1024] = { 0 };
167
168 if (imap_adata_find(path, &adata, &mdata) < 0)
169 {
170 mutt_str_copy(buf, path, buflen);
171 return;
172 }
173
174 /* Gets the parent mbox in mbox */
175 imap_get_parent(mdata->name, adata->delim, mbox, sizeof(mbox));
176
177 /* Returns a fully qualified IMAP url */
178 imap_qualify_path(buf, buflen, &adata->conn->account, mbox);
179 imap_mdata_free((void *) &mdata);
180}
void imap_qualify_path(char *buf, size_t buflen, struct ConnAccount *cac, char *path)
Make an absolute IMAP folder target.
Definition: util.c:816
void imap_get_parent(const char *mbox, char delim, char *buf, size_t buflen)
Get an IMAP folder's parent.
Definition: util.c:121
int imap_adata_find(const char *path, struct ImapAccountData **adata, struct ImapMboxData **mdata)
Find the Account data for this path.
Definition: util.c:73
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_clean_path()

void imap_clean_path ( char *  path,
size_t  plen 
)

Cleans an IMAP path using imap_fix_path.

Parameters
pathPath to be cleaned
plenLength of the buffer

Does it in place.

Definition at line 189 of file util.c.

190{
191 struct ImapAccountData *adata = NULL;
192 struct ImapMboxData *mdata = NULL;
193
194 if (imap_adata_find(path, &adata, &mdata) < 0)
195 return;
196
197 /* Returns a fully qualified IMAP url */
198 imap_qualify_path(path, plen, &adata->conn->account, mdata->name);
199 imap_mdata_free((void *) &mdata);
200}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_search()

bool imap_search ( struct Mailbox m,
const struct PatternList *  pat 
)

Find messages in mailbox matching a pattern.

Parameters
mMailbox
patPattern to match
Return values
trueSuccess
falseFailure

Definition at line 227 of file search.c.

228{
229 for (int i = 0; i < m->msg_count; i++)
230 {
231 struct Email *e = m->emails[i];
232 if (!e)
233 break;
234 e->matched = false;
235 }
236
237 if (check_pattern_list(pat) == 0)
238 return true;
239
240 struct Buffer *buf = buf_pool_get();
241 buf_addstr(buf, "UID SEARCH ");
242
244 const bool ok = compile_search(adata, SLIST_FIRST(pat), buf) &&
246
248 return ok;
249}
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define SLIST_FIRST(head)
Definition: queue.h:229
static bool compile_search(const struct ImapAccountData *adata, const struct Pattern *pat, struct Buffer *buf)
Convert NeoMutt pattern to IMAP search.
Definition: search.c:207
static int check_pattern_list(const struct PatternList *patterns)
Check how many patterns in a list can be searched server-side.
Definition: search.c:81
bool matched
Search matches this Email.
Definition: email.h:105
+ Here is the call graph for this function:
+ Here is the caller graph for this function: