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

Variables

struct MxOps MxImapOps
 IMAP Mailbox - Implements MxOps -. More...
 

Detailed Description

IMAP network mailbox.

Authors
  • Michael R. Elkins
  • Brendan Cully
  • Richard Russon

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 84 of file imap.c.

85{
87}
static const struct Command imap_commands[]
Definition: imap.c:74
#define COMMANDS_REGISTER(cmds)
Definition: mutt_commands.h:47
+ 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 473 of file imap.c.

474{
475 if (imap_path_status(path, false) >= 0)
476 return 0;
477 return -1;
478}
int imap_path_status(const char *path, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1238
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_check_mailbox()

int 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 1106 of file imap.c.

1107{
1108 if (!m || !m->account)
1109 return MX_STATUS_ERROR;
1110
1112 struct ImapMboxData *mdata = imap_mdata_get(m);
1113
1114 /* overload keyboard timeout to avoid many mailbox checks in a row.
1115 * Most users don't like having to wait exactly when they press a key. */
1116 int rc = 0;
1117
1118 /* try IDLE first, unless force is set */
1119 const bool c_imap_idle = cs_subset_bool(NeoMutt->sub, "imap_idle");
1120 const short c_imap_keepalive = cs_subset_number(NeoMutt->sub, "imap_keepalive");
1121 if (!force && c_imap_idle && (adata->capabilities & IMAP_CAP_IDLE) &&
1122 ((adata->state != IMAP_IDLE) || (mutt_date_epoch() >= adata->lastread + c_imap_keepalive)))
1123 {
1124 if (imap_cmd_idle(adata) < 0)
1125 return MX_STATUS_ERROR;
1126 }
1127 if (adata->state == IMAP_IDLE)
1128 {
1129 while ((rc = mutt_socket_poll(adata->conn, 0)) > 0)
1130 {
1131 if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
1132 {
1133 mutt_debug(LL_DEBUG1, "Error reading IDLE response\n");
1134 return MX_STATUS_ERROR;
1135 }
1136 }
1137 if (rc < 0)
1138 {
1139 mutt_debug(LL_DEBUG1, "Poll failed, disabling IDLE\n");
1140 adata->capabilities &= ~IMAP_CAP_IDLE; // Clear the flag
1141 }
1142 }
1143
1144 const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
1145 if ((force || ((adata->state != IMAP_IDLE) &&
1146 (mutt_date_epoch() >= adata->lastread + c_timeout))) &&
1147 (imap_exec(adata, "NOOP", IMAP_CMD_POLL) != IMAP_EXEC_SUCCESS))
1148 {
1149 return MX_STATUS_ERROR;
1150 }
1151
1152 /* We call this even when we haven't run NOOP in case we have pending
1153 * changes to process, since we can reopen here. */
1154 imap_cmd_finish(adata);
1155
1156 enum MxStatus check = MX_STATUS_OK;
1157 if (mdata->check_status & IMAP_EXPUNGE_PENDING)
1158 check = MX_STATUS_REOPENED;
1159 else if (mdata->check_status & IMAP_NEWMAIL_PENDING)
1160 check = MX_STATUS_NEW_MAIL;
1161 else if (mdata->check_status & IMAP_FLAGS_PENDING)
1162 check = MX_STATUS_FLAGS;
1163 else if (rc < 0)
1164 check = MX_STATUS_ERROR;
1165
1166 mdata->check_status = IMAP_OPEN_NO_FLAGS;
1167
1168 return check;
1169}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: adata.c:89
int imap_cmd_idle(struct ImapAccountData *adata)
Enter the IDLE state.
Definition: command.c:1379
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
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:1247
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition: command.c:1312
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:135
@ IMAP_IDLE
Connection is idle.
Definition: private.h:113
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:68
#define IMAP_OPEN_NO_FLAGS
No flags are set.
Definition: private.h:65
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: private.h:76
@ IMAP_EXEC_SUCCESS
Imap command executed or queued successfully.
Definition: private.h:84
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: private.h:69
#define IMAP_FLAGS_PENDING
Flags have changed on the server.
Definition: private.h:70
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:57
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:84
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:85
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:86
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mxapi.h:90
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:89
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:87
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:193
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
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:39
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:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ 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 515 of file imap.c.

516{
517 char buf[PATH_MAX + 7];
518 char mbox[PATH_MAX] = { 0 };
519 struct Url *url = url_parse(path);
520
522 imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), url->path);
523 url_free(&url);
524 snprintf(buf, sizeof(buf), "DELETE %s", mbox);
526 return -1;
527
528 return 0;
529}
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: private.h:73
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:911
#define PATH_MAX
Definition: mutt.h:40
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:234
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_sync_mailbox()

int 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 1534 of file imap.c.

1535{
1536 if (!m)
1537 return -1;
1538
1539 struct Email **emails = NULL;
1540 int rc;
1541
1543 struct ImapMboxData *mdata = imap_mdata_get(m);
1544
1545 if (adata->state < IMAP_SELECTED)
1546 {
1547 mutt_debug(LL_DEBUG2, "no mailbox selected\n");
1548 return -1;
1549 }
1550
1551 /* This function is only called when the calling code expects the context
1552 * to be changed. */
1554
1555 enum MxStatus check = imap_check_mailbox(m, false);
1556 if (check == MX_STATUS_ERROR)
1557 return check;
1558
1559 /* if we are expunging anyway, we can do deleted messages very quickly... */
1560 if (expunge && (m->rights & MUTT_ACL_DELETE))
1561 {
1562 rc = imap_exec_msgset(m, "UID STORE", "+FLAGS.SILENT (\\Deleted)",
1563 MUTT_DELETED, true, false);
1564 if (rc < 0)
1565 {
1566 mutt_error(_("Expunge failed"));
1567 return rc;
1568 }
1569
1570 if (rc > 0)
1571 {
1572 /* mark these messages as unchanged so second pass ignores them. Done
1573 * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */
1574 for (int i = 0; i < m->msg_count; i++)
1575 {
1576 struct Email *e = m->emails[i];
1577 if (!e)
1578 break;
1579 if (e->deleted && e->changed)
1580 e->active = false;
1581 }
1582 if (m->verbose)
1583 {
1584 mutt_message(ngettext("Marking %d message deleted...",
1585 "Marking %d messages deleted...", rc),
1586 rc);
1587 }
1588 }
1589 }
1590
1591#ifdef USE_HCACHE
1592 imap_hcache_open(adata, mdata);
1593#endif
1594
1595 /* save messages with real (non-flag) changes */
1596 for (int i = 0; i < m->msg_count; i++)
1597 {
1598 struct Email *e = m->emails[i];
1599 if (!e)
1600 break;
1601
1602 if (e->deleted)
1603 {
1604 imap_cache_del(m, e);
1605#ifdef USE_HCACHE
1606 imap_hcache_del(mdata, imap_edata_get(e)->uid);
1607#endif
1608 }
1609
1610 if (e->active && e->changed)
1611 {
1612#ifdef USE_HCACHE
1613 imap_hcache_put(mdata, e);
1614#endif
1615 /* if the message has been rethreaded or attachments have been deleted
1616 * we delete the message and reupload it.
1617 * This works better if we're expunging, of course. */
1618 /* TODO: why the e->env check? */
1619 if ((e->env && e->env->changed) || e->attach_del)
1620 {
1621 /* L10N: The plural is chosen by the last %d, i.e. the total number */
1622 if (m->verbose)
1623 {
1624 mutt_message(ngettext("Saving changed message... [%d/%d]",
1625 "Saving changed messages... [%d/%d]", m->msg_count),
1626 i + 1, m->msg_count);
1627 }
1628 bool save_append = m->append;
1629 m->append = true;
1631 m->append = save_append;
1632 /* TODO: why the check for e->env? Is this possible? */
1633 if (e->env)
1634 e->env->changed = 0;
1635 }
1636 }
1637 }
1638
1639#ifdef USE_HCACHE
1640 imap_hcache_close(mdata);
1641#endif
1642
1643 /* presort here to avoid doing 10 resorts in imap_exec_msgset */
1644 const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
1645 if (c_sort != SORT_ORDER)
1646 {
1647 emails = m->emails;
1648 m->emails = mutt_mem_malloc(m->msg_count * sizeof(struct Email *));
1649 memcpy(m->emails, emails, m->msg_count * sizeof(struct Email *));
1650
1652 qsort(m->emails, m->msg_count, sizeof(struct Email *), compare_uid);
1653 }
1654
1655 rc = sync_helper(m, MUTT_ACL_DELETE, MUTT_DELETED, "\\Deleted");
1656 if (rc >= 0)
1657 rc |= sync_helper(m, MUTT_ACL_WRITE, MUTT_FLAG, "\\Flagged");
1658 if (rc >= 0)
1659 rc |= sync_helper(m, MUTT_ACL_WRITE, MUTT_OLD, "Old");
1660 if (rc >= 0)
1661 rc |= sync_helper(m, MUTT_ACL_SEEN, MUTT_READ, "\\Seen");
1662 if (rc >= 0)
1663 rc |= sync_helper(m, MUTT_ACL_WRITE, MUTT_REPLIED, "\\Answered");
1664
1665 if (c_sort != SORT_ORDER)
1666 {
1667 cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
1668 FREE(&m->emails);
1669 m->emails = emails;
1670 }
1671
1672 /* Flush the queued flags if any were changed in sync_helper. */
1673 if (rc > 0)
1674 if (imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1675 rc = -1;
1676
1677 if (rc < 0)
1678 {
1679 if (close)
1680 {
1681 if (mutt_yesorno(_("Error saving flags. Close anyway?"), MUTT_NO) == MUTT_YES)
1682 {
1683 adata->state = IMAP_AUTHENTICATED;
1684 return 0;
1685 }
1686 }
1687 else
1688 mutt_error(_("Error saving flags"));
1689 return -1;
1690 }
1691
1692 /* Update local record of server state to reflect the synchronization just
1693 * completed. imap_read_headers always overwrites hcache-origin flags, so
1694 * there is no need to mutate the hcache after flag-only changes. */
1695 for (int i = 0; i < m->msg_count; i++)
1696 {
1697 struct Email *e = m->emails[i];
1698 if (!e)
1699 break;
1700 struct ImapEmailData *edata = imap_edata_get(e);
1701 edata->deleted = e->deleted;
1702 edata->flagged = e->flagged;
1703 edata->old = e->old;
1704 edata->read = e->read;
1705 edata->replied = e->replied;
1706 e->changed = false;
1707 }
1708 m->changed = false;
1709
1710 /* We must send an EXPUNGE command if we're not closing. */
1711 if (expunge && !close && (m->rights & MUTT_ACL_DELETE))
1712 {
1713 if (m->verbose)
1714 mutt_message(_("Expunging messages from server..."));
1715 /* Set expunge bit so we don't get spurious reopened messages */
1716 mdata->reopen |= IMAP_EXPUNGE_EXPECTED;
1717 if (imap_exec(adata, "EXPUNGE", IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1718 {
1719 mdata->reopen &= ~IMAP_EXPUNGE_EXPECTED;
1720 imap_error(_("imap_sync_mailbox: EXPUNGE failed"), adata->buf);
1721 return -1;
1722 }
1723 mdata->reopen &= ~IMAP_EXPUNGE_EXPECTED;
1724 }
1725
1726 if (expunge && close)
1727 {
1728 adata->closing = true;
1729 imap_exec(adata, "CLOSE", IMAP_CMD_NO_FLAGS);
1730 adata->state = IMAP_AUTHENTICATED;
1731 }
1732
1733 const bool c_message_cache_clean = cs_subset_bool(NeoMutt->sub, "message_cache_clean");
1734 if (c_message_cache_clean)
1736
1737 return check;
1738}
int mutt_save_message_ctx(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: commands.c:772
@ TRANSFORM_NONE
No transformation.
Definition: commands.h:40
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: commands.h:51
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
static int compare_uid(const void *a, const void *b)
Compare two Emails by UID - Implements sort_t -.
Definition: imap.c:904
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:65
int imap_cache_clean(struct Mailbox *m)
Delete all the entries in the message cache.
Definition: message.c:1876
int imap_cache_del(struct Mailbox *m, struct Email *e)
Delete an email from the body cache.
Definition: message.c:1857
void imap_allow_reopen(struct Mailbox *m)
Allow re-opening a folder upon expunge.
Definition: util.c:1016
@ IMAP_AUTHENTICATED
Connection is authenticated.
Definition: private.h:109
@ IMAP_SELECTED
Mailbox is selected.
Definition: private.h:110
#define IMAP_EXPUNGE_EXPECTED
Messages will be expunged from the server.
Definition: private.h:67
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:663
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition: util.c:339
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:297
int imap_exec_msgset(struct Mailbox *m, const char *pre, const char *post, enum MessageType flag, bool changed, bool invert)
Prepare commands for all messages matching conditions.
Definition: imap.c:930
static int sync_helper(struct Mailbox *m, AclFlags right, enum MessageType flag, const char *name)
Sync flag changes to the server.
Definition: imap.c:323
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition: imap.c:1106
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
#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
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:43
#define _(a)
Definition: message.h:28
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:93
@ MUTT_OLD
Old messages.
Definition: mutt.h:91
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:99
@ MUTT_DELETED
Deleted messages.
Definition: mutt.h:98
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:92
@ 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 mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:48
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
struct Envelope * env
Envelope information.
Definition: email.h:66
void * edata
Driver-specific data.
Definition: email.h:72
bool active
Message is not to be removed.
Definition: email.h:74
bool old
Email is seen, but unread.
Definition: email.h:47
bool changed
Email has been edited.
Definition: email.h:75
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:99
bool flagged
Marked important?
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:49
bool deleted
Email is deleted.
Definition: email.h:76
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:92
bool closing
If true, we are waiting for CLOSE completion.
Definition: adata.h:43
IMAP-specific Email data -.
Definition: edata.h:34
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: mdata.h:44
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:117
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
bool verbose
Display status messages?
Definition: mailbox.h:114
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ 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 1238 of file imap.c.

1239{
1240 struct Mailbox *m = mx_mbox_find2(path);
1241
1242 const bool is_temp = !m;
1243 if (is_temp)
1244 {
1245 m = mx_path_resolve(path);
1246 if (!mx_mbox_ac_link(m))
1247 {
1248 mailbox_free(&m);
1249 return 0;
1250 }
1251 }
1252
1253 int rc = imap_mailbox_status(m, queue);
1254
1255 if (is_temp)
1256 {
1257 mx_ac_remove(m, false);
1258 mailbox_free(&m);
1259 }
1260
1261 return rc;
1262}
int imap_mailbox_status(struct Mailbox *m, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1273
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1781
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1649
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:267
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
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 1273 of file imap.c.

1274{
1276 struct ImapMboxData *mdata = imap_mdata_get(m);
1277 if (!adata || !mdata)
1278 return -1;
1279 return imap_status(adata, mdata, queue);
1280}
static int imap_status(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1178
+ 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 1289 of file imap.c.

1290{
1291 struct ImapAccountData *adata = NULL;
1292 struct ImapMboxData *mdata = NULL;
1293 char buf[2048] = { 0 };
1294 struct Buffer err;
1295
1296 if (imap_adata_find(path, &adata, &mdata) < 0)
1297 return -1;
1298
1299 if (subscribe)
1300 mutt_message(_("Subscribing to %s..."), mdata->name);
1301 else
1302 mutt_message(_("Unsubscribing from %s..."), mdata->name);
1303
1304 snprintf(buf, sizeof(buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mdata->munge_name);
1305
1306 if (imap_exec(adata, buf, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1307 {
1308 imap_mdata_free((void *) &mdata);
1309 return -1;
1310 }
1311
1312 const bool c_imap_check_subscribed = cs_subset_bool(NeoMutt->sub, "imap_check_subscribed");
1313 if (c_imap_check_subscribed)
1314 {
1315 char mbox[1024] = { 0 };
1316 mutt_buffer_init(&err);
1317 err.dsize = 256;
1318 err.data = mutt_mem_malloc(err.dsize);
1319 size_t len = snprintf(mbox, sizeof(mbox), "%smailboxes ", subscribe ? "" : "un");
1320 imap_quote_string(mbox + len, sizeof(mbox) - len, path, true);
1321 if (mutt_parse_rc_line(mbox, &err))
1322 mutt_debug(LL_DEBUG1, "Error adding subscribed mailbox: %s\n", err.data);
1323 FREE(&err.data);
1324 }
1325
1326 if (subscribe)
1327 mutt_message(_("Subscribed to %s"), mdata->name);
1328 else
1329 mutt_message(_("Unsubscribed from %s"), mdata->name);
1330 imap_mdata_free((void *) &mdata);
1331 return 0;
1332}
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:52
void imap_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:40
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
Quote string according to IMAP rules.
Definition: util.c:837
int imap_adata_find(const char *path, struct ImapAccountData **adata, struct ImapMboxData **mdata)
Find the Account data for this path.
Definition: util.c:72
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:894
String manipulation buffer.
Definition: buffer.h:34
char * munge_name
Munged version of the mailbox name.
Definition: mdata.h:41
char * name
Mailbox name.
Definition: mdata.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_complete()

int imap_complete ( char *  buf,
size_t  buflen,
const char *  path 
)

Try to complete an IMAP folder path.

Parameters
bufBuffer for result
buflenLength of buffer
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 1345 of file imap.c.

1346{
1347 struct ImapAccountData *adata = NULL;
1348 struct ImapMboxData *mdata = NULL;
1349 char tmp[2048] = { 0 };
1350 struct ImapList listresp = { 0 };
1351 char completion[1024] = { 0 };
1352 size_t clen;
1353 size_t matchlen = 0;
1354 int completions = 0;
1355 int rc;
1356
1357 if (imap_adata_find(path, &adata, &mdata) < 0)
1358 {
1359 mutt_str_copy(buf, path, buflen);
1360 return complete_hosts(buf, buflen);
1361 }
1362
1363 /* fire off command */
1364 const bool c_imap_list_subscribed = cs_subset_bool(NeoMutt->sub, "imap_list_subscribed");
1365 snprintf(tmp, sizeof(tmp), "%s \"\" \"%s%%\"",
1366 c_imap_list_subscribed ? "LSUB" : "LIST", mdata->real_name);
1367
1368 imap_cmd_start(adata, tmp);
1369
1370 /* and see what the results are */
1371 mutt_str_copy(completion, mdata->name, sizeof(completion));
1372 imap_mdata_free((void *) &mdata);
1373
1374 adata->cmdresult = &listresp;
1375 do
1376 {
1377 listresp.name = NULL;
1378 rc = imap_cmd_step(adata);
1379
1380 if ((rc == IMAP_RES_CONTINUE) && listresp.name)
1381 {
1382 /* if the folder isn't selectable, append delimiter to force browse
1383 * to enter it on second tab. */
1384 if (listresp.noselect)
1385 {
1386 clen = strlen(listresp.name);
1387 listresp.name[clen++] = listresp.delim;
1388 listresp.name[clen] = '\0';
1389 }
1390 /* copy in first word */
1391 if (!completions)
1392 {
1393 mutt_str_copy(completion, listresp.name, sizeof(completion));
1394 matchlen = strlen(completion);
1395 completions++;
1396 continue;
1397 }
1398
1399 matchlen = longest_common_prefix(completion, listresp.name, 0, matchlen);
1400 completions++;
1401 }
1402 } while (rc == IMAP_RES_CONTINUE);
1403 adata->cmdresult = NULL;
1404
1405 if (completions)
1406 {
1407 /* reformat output */
1408 imap_qualify_path(buf, buflen, &adata->conn->account, completion);
1409 mutt_pretty_mailbox(buf, buflen);
1410 return 0;
1411 }
1412
1413 return -1;
1414}
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:522
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1062
void imap_qualify_path(char *buf, size_t buflen, struct ConnAccount *conn_account, char *path)
Make an absolute IMAP folder target.
Definition: util.c:820
static size_t longest_common_prefix(char *dest, const char *src, size_t start, size_t dlen)
Find longest prefix common to two strings.
Definition: imap.c:364
static int complete_hosts(char *buf, size_t buflen)
Look for completion matches for mailboxes.
Definition: imap.c:385
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:652
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
struct ImapList * cmdresult
Definition: adata.h:66
Items in an IMAP browser.
Definition: private.h:150
bool noselect
Definition: private.h:153
char * name
Definition: private.h:151
char delim
Definition: private.h:152
char * real_name
Original Mailbox name, e.g.: INBOX can be just \0.
Definition: mdata.h:42
+ 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 1424 of file imap.c.

1425{
1426 char prompt[1024] = { 0 };
1427 int rc = -1;
1428 bool triedcreate = false;
1429 enum QuadOption err_continue = MUTT_NO;
1430
1432 struct ImapAccountData *dest_adata = NULL;
1433 struct ImapMboxData *dest_mdata = NULL;
1434
1435 if (imap_adata_find(dest, &dest_adata, &dest_mdata) < 0)
1436 return -1;
1437
1438 struct Buffer sync_cmd = mutt_buffer_make(0);
1439
1440 /* check that the save-to folder is in the same account */
1441 if (!imap_account_match(&(adata->conn->account), &(dest_adata->conn->account)))
1442 {
1443 mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1444 goto out;
1445 }
1446
1447 for (int i = 0; i < m->msg_count; i++)
1448 {
1449 struct Email *e = m->emails[i];
1450 if (!e)
1451 break;
1452 if (e->active && e->changed && e->deleted && !e->purge)
1453 {
1454 rc = imap_sync_message_for_copy(m, e, &sync_cmd, &err_continue);
1455 if (rc < 0)
1456 {
1457 mutt_debug(LL_DEBUG1, "could not sync\n");
1458 goto out;
1459 }
1460 }
1461 }
1462
1463 /* loop in case of TRYCREATE */
1464 do
1465 {
1466 rc = imap_exec_msgset(m, "UID COPY", dest_mdata->munge_name, MUTT_TRASH, false, false);
1467 if (rc == 0)
1468 {
1469 mutt_debug(LL_DEBUG1, "No messages to trash\n");
1470 rc = -1;
1471 goto out;
1472 }
1473 else if (rc < 0)
1474 {
1475 mutt_debug(LL_DEBUG1, "could not queue copy\n");
1476 goto out;
1477 }
1478 else if (m->verbose)
1479 {
1480 mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1481 rc, dest_mdata->name);
1482 }
1483
1484 /* let's get it on */
1485 rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1486 if (rc == IMAP_EXEC_ERROR)
1487 {
1488 if (triedcreate)
1489 {
1490 mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", dest_mdata->name);
1491 break;
1492 }
1493 /* bail out if command failed for reasons other than nonexistent target */
1494 if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1495 break;
1496 mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1497 snprintf(prompt, sizeof(prompt), _("Create %s?"), dest_mdata->name);
1498 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
1499 if (c_confirm_create && (mutt_yesorno(prompt, MUTT_YES) != MUTT_YES))
1500 {
1502 goto out;
1503 }
1504 if (imap_create_mailbox(adata, dest_mdata->name) < 0)
1505 break;
1506 triedcreate = true;
1507 }
1508 } while (rc == IMAP_EXEC_ERROR);
1509
1510 if (rc != IMAP_EXEC_SUCCESS)
1511 {
1512 imap_error("imap_fast_trash", adata->buf);
1513 goto out;
1514 }
1515
1516 rc = IMAP_EXEC_SUCCESS;
1517
1518out:
1519 mutt_buffer_dealloc(&sync_cmd);
1520 imap_mdata_free((void *) &dest_mdata);
1521
1522 return ((rc == IMAP_EXEC_SUCCESS) ? 0 : -1);
1523}
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
@ IMAP_EXEC_ERROR
Imap command failure.
Definition: private.h:85
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition: util.c:1044
char * imap_get_qualifier(char *buf)
Get the qualifier from a tagged response.
Definition: util.c:772
int imap_create_mailbox(struct ImapAccountData *adata, const char *mailbox)
Create a new mailbox.
Definition: imap.c:447
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:1007
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
@ MUTT_TRASH
Trashed messages.
Definition: mutt.h:105
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
bool purge
Skip trash folder when deleting.
Definition: email.h:77
+ 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 654 of file imap.c.

655{
656 struct ImapMboxData *mdata = imap_mdata_get(m);
658
659 if (!mdata || !edata)
660 return;
661
662 imap_msn_remove(&mdata->msn, edata->msn - 1);
663 edata->msn = 0;
664}
void imap_msn_remove(struct MSN *msn, size_t idx)
Remove an entry from the cache.
Definition: msn.c:113
+ 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 182 of file browse.c.

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

◆ 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 382 of file browse.c.

383{
384 struct ImapAccountData *adata = NULL;
385 struct ImapMboxData *mdata = NULL;
386 struct Buffer *name = mutt_buffer_pool_get();
387 int rc = -1;
388
389 if (imap_adata_find(path, &adata, &mdata) < 0)
390 {
391 mutt_debug(LL_DEBUG1, "Couldn't find open connection to %s\n", path);
392 goto done;
393 }
394
395 /* append a delimiter if necessary */
396 const size_t n = mutt_buffer_strcpy(name, mdata->real_name);
397 if ((n != 0) && (name->data[n - 1] != adata->delim))
398 {
399 mutt_buffer_addch(name, adata->delim);
400 }
401
402 if (mutt_buffer_get_field(_("Create mailbox: "), name, MUTT_COMP_FILE, false,
403 NULL, NULL, NULL) != 0)
404 {
405 goto done;
406 }
407
408 if (mutt_buffer_is_empty(name))
409 {
410 mutt_error(_("Mailbox must have a name"));
411 goto done;
412 }
413
414 if (imap_create_mailbox(adata, mutt_buffer_string(name)) < 0)
415 goto done;
416
417 imap_mdata_free((void *) &mdata);
418 mutt_message(_("Mailbox created"));
419 mutt_sleep(0);
420 rc = 0;
421
422done:
423 imap_mdata_free((void *) &mdata);
425 return rc;
426}
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
#define MUTT_COMP_FILE
File completion (in browser)
Definition: mutt.h:55
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1455
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
char * data
Pointer to data.
Definition: buffer.h:35
+ 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 436 of file browse.c.

437{
438 struct ImapAccountData *adata = NULL;
439 struct ImapMboxData *mdata = NULL;
440 struct Buffer *buf = NULL;
441 struct Buffer *newname = NULL;
442 int rc = -1;
443
444 if (imap_adata_find(path, &adata, &mdata) < 0)
445 {
446 mutt_debug(LL_DEBUG1, "Couldn't find open connection to %s\n", path);
447 goto done;
448 }
449
450 if (mdata->real_name[0] == '\0')
451 {
452 mutt_error(_("Can't rename root folder"));
453 goto done;
454 }
455
456 buf = mutt_buffer_pool_get();
457 newname = mutt_buffer_pool_get();
458
459 mutt_buffer_printf(buf, _("Rename mailbox %s to: "), mdata->name);
460 mutt_buffer_strcpy(newname, mdata->name);
461
463 false, NULL, NULL, NULL) != 0)
464 {
465 goto done;
466 }
467
468 if (mutt_buffer_is_empty(newname))
469 {
470 mutt_error(_("Mailbox must have a name"));
471 goto done;
472 }
473
474 imap_fix_path(adata->delim, mutt_buffer_string(newname), buf->data, buf->dsize);
475
476 if (imap_rename_mailbox(adata, mdata->name, mutt_buffer_string(buf)) < 0)
477 {
478 mutt_error(_("Rename failed: %s"), imap_get_qualifier(adata->buf));
479 goto done;
480 }
481
482 mutt_message(_("Mailbox renamed"));
483 mutt_sleep(0);
484 rc = 0;
485
486done:
487 imap_mdata_free((void *) &mdata);
489 mutt_buffer_pool_release(&newname);
490
491 return rc;
492}
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
int imap_rename_mailbox(struct ImapAccountData *adata, char *oldname, const char *newname)
Rename a mailbox.
Definition: imap.c:488
size_t dsize
Length of data.
Definition: buffer.h:37
+ 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 EmailList *  el,
const char *  dest,
enum MessageSaveOpt  save_opt 
)

Server COPY messages to another folder.

Parameters
mMailbox
elList 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 1683 of file message.c.

1685{
1686 if (!m || !el || !dest)
1687 return -1;
1688
1689 struct Buffer cmd, sync_cmd;
1690 char buf[PATH_MAX] = { 0 };
1691 char mbox[PATH_MAX] = { 0 };
1692 char mmbox[PATH_MAX] = { 0 };
1693 char prompt[PATH_MAX + 64];
1694 int rc;
1695 struct ConnAccount cac = { { 0 } };
1696 enum QuadOption err_continue = MUTT_NO;
1697 int triedcreate = 0;
1698 struct EmailNode *en = STAILQ_FIRST(el);
1699 bool single = !STAILQ_NEXT(en, entries);
1701
1702 if (single && en->email->attach_del)
1703 {
1704 mutt_debug(LL_DEBUG3, "#1 Message contains attachments to be deleted\n");
1705 return 1;
1706 }
1707
1708 if (imap_parse_path(dest, &cac, buf, sizeof(buf)))
1709 {
1710 mutt_debug(LL_DEBUG1, "bad destination %s\n", dest);
1711 return -1;
1712 }
1713
1714 /* check that the save-to folder is in the same account */
1715 if (!imap_account_match(&adata->conn->account, &cac))
1716 {
1717 mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1718 return 1;
1719 }
1720
1721 imap_fix_path(adata->delim, buf, mbox, sizeof(mbox));
1722 if (*mbox == '\0')
1723 mutt_str_copy(mbox, "INBOX", sizeof(mbox));
1724 imap_munge_mbox_name(adata->unicode, mmbox, sizeof(mmbox), mbox);
1725
1726 /* loop in case of TRYCREATE */
1727 do
1728 {
1729 mutt_buffer_init(&sync_cmd);
1730 mutt_buffer_init(&cmd);
1731
1732 if (!single) /* copy tagged messages */
1733 {
1734 /* if any messages have attachments to delete, fall through to FETCH
1735 * and APPEND. TODO: Copy what we can with COPY, fall through for the
1736 * remainder. */
1737 STAILQ_FOREACH(en, el, entries)
1738 {
1739 if (en->email->attach_del)
1740 {
1741 mutt_debug(LL_DEBUG3, "#2 Message contains attachments to be deleted\n");
1742 return 1;
1743 }
1744
1745 if (en->email->active && en->email->changed)
1746 {
1747 rc = imap_sync_message_for_copy(m, en->email, &sync_cmd, &err_continue);
1748 if (rc < 0)
1749 {
1750 mutt_debug(LL_DEBUG1, "#1 could not sync\n");
1751 goto out;
1752 }
1753 }
1754 }
1755
1756 rc = imap_exec_msgset(m, "UID COPY", mmbox, MUTT_TAG, false, false);
1757 if (rc == 0)
1758 {
1759 mutt_debug(LL_DEBUG1, "No messages tagged\n");
1760 rc = -1;
1761 goto out;
1762 }
1763 else if (rc < 0)
1764 {
1765 mutt_debug(LL_DEBUG1, "#1 could not queue copy\n");
1766 goto out;
1767 }
1768 else
1769 {
1770 mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1771 rc, mbox);
1772 }
1773 }
1774 else
1775 {
1776 mutt_message(_("Copying message %d to %s..."), en->email->index + 1, mbox);
1777 mutt_buffer_add_printf(&cmd, "UID COPY %u %s", imap_edata_get(en->email)->uid, mmbox);
1778
1779 if (en->email->active && en->email->changed)
1780 {
1781 rc = imap_sync_message_for_copy(m, en->email, &sync_cmd, &err_continue);
1782 if (rc < 0)
1783 {
1784 mutt_debug(LL_DEBUG1, "#2 could not sync\n");
1785 goto out;
1786 }
1787 }
1788 rc = imap_exec(adata, cmd.data, IMAP_CMD_QUEUE);
1789 if (rc != IMAP_EXEC_SUCCESS)
1790 {
1791 mutt_debug(LL_DEBUG1, "#2 could not queue copy\n");
1792 goto out;
1793 }
1794 }
1795
1796 /* let's get it on */
1797 rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1798 if (rc == IMAP_EXEC_ERROR)
1799 {
1800 if (triedcreate)
1801 {
1802 mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", mbox);
1803 break;
1804 }
1805 /* bail out if command failed for reasons other than nonexistent target */
1806 if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1807 break;
1808 mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1809 snprintf(prompt, sizeof(prompt), _("Create %s?"), mbox);
1810 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
1811 if (c_confirm_create && (mutt_yesorno(prompt, MUTT_YES) != MUTT_YES))
1812 {
1814 goto out;
1815 }
1816 if (imap_create_mailbox(adata, mbox) < 0)
1817 break;
1818 triedcreate = 1;
1819 }
1820 } while (rc == IMAP_EXEC_ERROR);
1821
1822 if (rc != 0)
1823 {
1824 imap_error("imap_copy_messages", adata->buf);
1825 goto out;
1826 }
1827
1828 /* cleanup */
1829 if (save_opt == SAVE_MOVE)
1830 {
1831 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
1832 STAILQ_FOREACH(en, el, entries)
1833 {
1834 mutt_set_flag(m, en->email, MUTT_DELETE, true);
1835 mutt_set_flag(m, en->email, MUTT_PURGE, true);
1836 if (c_delete_untag)
1837 mutt_set_flag(m, en->email, MUTT_TAG, false);
1838 }
1839 }
1840
1841 rc = 0;
1842
1843out:
1844 FREE(&cmd.data);
1845 FREE(&sync_cmd.data);
1846
1847 return (rc < 0) ? -1 : rc;
1848}
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:211
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: private.h:75
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:97
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:100
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:95
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:63
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
List of Emails.
Definition: email.h:132
struct Email * email
Email in the list.
Definition: email.h:133
int index
The absolute (unsorted) message number.
Definition: email.h:110
unsigned int uid
32-bit Message UID
Definition: edata.h:44
+ 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 562 of file imap.c.

563{
564 struct Account *np = NULL;
565 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
566 {
567 if (np->type != MUTT_IMAP)
568 continue;
569
570 struct ImapAccountData *adata = np->adata;
571 if (!adata)
572 continue;
573
574 struct Connection *conn = adata->conn;
575 if (!conn || (conn->fd < 0))
576 continue;
577
578 mutt_message(_("Closing connection to %s..."), conn->account.host);
579 imap_logout(np->adata);
581 }
582}
static void imap_logout(struct ImapAccountData *adata)
Gracefully log out of server.
Definition: imap.c:535
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
A group of associated Mailboxes.
Definition: account.h:37
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:38
char host[128]
Server to login to.
Definition: connaccount.h:54
int fd
Socket file descriptor.
Definition: connection.h:54
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
+ 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 buf)

Buffer wrapper around imap_path_canon()

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

Definition at line 2440 of file imap.c.

2441{
2443 return imap_path_canon(buf->data, PATH_MAX);
2444}
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:275
int imap_path_canon(char *buf, size_t buflen)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition: imap.c:2414
+ 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 482 of file util.c.

483{
484 static unsigned short ImapPort = 0;
485 static unsigned short ImapsPort = 0;
486
487 if (ImapPort == 0)
488 {
489 struct servent *service = getservbyname("imap", "tcp");
490 if (service)
491 ImapPort = ntohs(service->s_port);
492 else
493 ImapPort = IMAP_PORT;
494 mutt_debug(LL_DEBUG3, "Using default IMAP port %d\n", ImapPort);
495 }
496
497 if (ImapsPort == 0)
498 {
499 struct servent *service = getservbyname("imaps", "tcp");
500 if (service)
501 ImapsPort = ntohs(service->s_port);
502 else
503 ImapsPort = IMAP_SSL_PORT;
504 mutt_debug(LL_DEBUG3, "Using default IMAPS port %d\n", ImapsPort);
505 }
506
507 /* Defaults */
508 cac->port = ImapPort;
510 cac->service = "imap";
512
513 struct Url *url = url_parse(path);
514 if (!url)
515 return -1;
516
517 if ((url->scheme != U_IMAP) && (url->scheme != U_IMAPS))
518 {
519 url_free(&url);
520 return -1;
521 }
522
523 if ((mutt_account_fromurl(cac, url) < 0) || (cac->host[0] == '\0'))
524 {
525 url_free(&url);
526 return -1;
527 }
528
529 if (url->scheme == U_IMAPS)
530 cac->flags |= MUTT_ACCT_SSL;
531
532 mutt_str_copy(mailbox, url->path, mailboxlen);
533
534 url_free(&url);
535
536 if ((cac->flags & MUTT_ACCT_SSL) && !(cac->flags & MUTT_ACCT_PORT))
537 cac->port = ImapsPort;
538
539 return 0;
540}
#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
#define IMAP_PORT
Default port for IMAP.
Definition: private.h:45
#define IMAP_SSL_PORT
Port for IMAP over SSL/TLS.
Definition: private.h:46
int mutt_account_fromurl(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
Definition: mutt_account.c:43
@ MUTT_ACCT_TYPE_IMAP
Imap Account.
Definition: mutt_account.h:37
const char * service
Name of the service, e.g. "imap".
Definition: connaccount.h:61
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Function to get some login credentials.
Definition: connaccount.h:68
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
static const char * imap_get_field(enum ConnAccountField field, void *gf_data)
Get connection login credentials - Implements ConnAccount::get_field()
Definition: util.c:204
+ 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 589 of file util.c.

590{
591 struct ConnAccount cac_target = { { 0 } };
592 struct ConnAccount cac_home = { { 0 } };
593 struct Url url = { 0 };
594 const char *delim = NULL;
595 int tlen;
596 int hlen = 0;
597 bool home_match = false;
598 char target_mailbox[1024] = { 0 };
599 char home_mailbox[1024] = { 0 };
600
601 if (imap_parse_path(path, &cac_target, target_mailbox, sizeof(target_mailbox)) < 0)
602 return;
603
604 if (imap_path_probe(folder, NULL) != MUTT_IMAP)
605 goto fallback;
606
607 if (imap_parse_path(folder, &cac_home, home_mailbox, sizeof(home_mailbox)) < 0)
608 goto fallback;
609
610 tlen = mutt_str_len(target_mailbox);
611 hlen = mutt_str_len(home_mailbox);
612
613 /* check whether we can do '+' substitution */
614 if (tlen && imap_account_match(&cac_home, &cac_target) &&
615 mutt_strn_equal(home_mailbox, target_mailbox, hlen))
616 {
617 const char *const c_imap_delim_chars = cs_subset_string(NeoMutt->sub, "imap_delim_chars");
618 if (hlen == 0)
619 home_match = true;
620 else if (c_imap_delim_chars)
621 {
622 for (delim = c_imap_delim_chars; *delim != '\0'; delim++)
623 if (target_mailbox[hlen] == *delim)
624 home_match = true;
625 }
626 }
627
628 /* do the '+' substitution */
629 if (home_match)
630 {
631 *path++ = '+';
632 /* copy remaining path, skipping delimiter */
633 if (hlen != 0)
634 ++hlen;
635 memcpy(path, target_mailbox + hlen, tlen - hlen);
636 path[tlen - hlen] = '\0';
637 return;
638 }
639
640fallback:
641 mutt_account_tourl(&cac_target, &url);
642 url.path = target_mailbox;
643 url_tostring(&url, path, pathlen, U_NO_FLAGS);
644}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2400
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:496
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:79
int url_tostring(struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition: url.c:418
#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:482
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition: util.c:1044
+ 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 553 of file util.c.

554{
555 char *b1 = NULL;
556 char *b2 = NULL;
557 int rc;
558
559 if (!mx1 || (*mx1 == '\0'))
560 mx1 = "INBOX";
561 if (!mx2 || (*mx2 == '\0'))
562 mx2 = "INBOX";
563 if (mutt_istr_equal(mx1, "INBOX") && mutt_istr_equal(mx2, "INBOX"))
564 {
565 return 0;
566 }
567
568 b1 = mutt_mem_malloc(strlen(mx1) + 1);
569 b2 = mutt_mem_malloc(strlen(mx2) + 1);
570
571 imap_fix_path('\0', mx1, b1, strlen(mx1) + 1);
572 imap_fix_path('\0', mx2, b2, strlen(mx2) + 1);
573
574 rc = mutt_str_cmp(b1, b2);
575 FREE(&b1);
576 FREE(&b2);
577
578 return rc;
579}
int mutt_str_cmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:470
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
char * imap_fix_path(char delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition: util.c:685
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_wait_keepalive()

int imap_wait_keepalive ( 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 969 of file util.c.

970{
971 struct sigaction oldalrm;
972 struct sigaction act;
973 sigset_t oldmask;
974 int rc;
975
976 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
977 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", true, NULL);
978 OptKeepQuiet = true;
979
980 sigprocmask(SIG_SETMASK, NULL, &oldmask);
981
982 sigemptyset(&act.sa_mask);
983 act.sa_handler = mutt_sig_empty_handler;
984#ifdef SA_INTERRUPT
985 act.sa_flags = SA_INTERRUPT;
986#else
987 act.sa_flags = 0;
988#endif
989
990 sigaction(SIGALRM, &act, &oldalrm);
991
992 const short c_imap_keepalive = cs_subset_number(NeoMutt->sub, "imap_keepalive");
993 alarm(c_imap_keepalive);
994 while ((waitpid(pid, &rc, 0) < 0) && (errno == EINTR))
995 {
996 alarm(0); /* cancel a possibly pending alarm */
998 alarm(c_imap_keepalive);
999 }
1000
1001 alarm(0); /* cancel a possibly pending alarm */
1002
1003 sigaction(SIGALRM, &oldalrm, NULL);
1004 sigprocmask(SIG_SETMASK, &oldmask, NULL);
1005
1006 OptKeepQuiet = false;
1007 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1008
1009 return rc;
1010}
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition: options.h:44
void mutt_sig_empty_handler(int sig)
Dummy signal handler.
Definition: signal.c:57
void imap_keepalive(void)
Poll the current folder to keep the connection alive.
Definition: util.c:945
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_keepalive()

void imap_keepalive ( void  )

Poll the current folder to keep the connection alive.

Definition at line 945 of file util.c.

946{
947 time_t now = mutt_date_epoch();
948 struct Account *np = NULL;
949 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
950 {
951 if (np->type != MUTT_IMAP)
952 continue;
953
954 struct ImapAccountData *adata = np->adata;
955 if (!adata || !adata->mailbox)
956 continue;
957
958 const short c_imap_keepalive = cs_subset_number(NeoMutt->sub, "imap_keepalive");
959 if ((adata->state >= IMAP_AUTHENTICATED) && (now >= (adata->lastread + c_imap_keepalive)))
960 imap_check_mailbox(adata->mailbox, true);
961 }
962}
+ 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 161 of file util.c.

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

189{
190 struct ImapAccountData *adata = NULL;
191 struct ImapMboxData *mdata = NULL;
192
193 if (imap_adata_find(path, &adata, &mdata) < 0)
194 return;
195
196 /* Returns a fully qualified IMAP url */
197 imap_qualify_path(path, plen, &adata->conn->account, mdata->name);
198 imap_mdata_free((void *) &mdata);
199}
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
+ 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 229 of file search.c.

230{
231 for (int i = 0; i < m->msg_count; i++)
232 {
233 struct Email *e = m->emails[i];
234 if (!e)
235 break;
236 e->matched = false;
237 }
238
239 if (check_pattern_list(pat) == 0)
240 return true;
241
242 struct Buffer buf;
243 mutt_buffer_init(&buf);
244 mutt_buffer_addstr(&buf, "UID SEARCH ");
245
247 const bool ok = compile_search(adata, SLIST_FIRST(pat), &buf) &&
249
250 FREE(&buf.data);
251 return ok;
252}
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
#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:209
static int check_pattern_list(const struct PatternList *patterns)
Check how many patterns in a list can be searched server-side.
Definition: search.c:83
bool matched
Search matches this Email.
Definition: email.h:102
+ Here is the call graph for this function:
+ Here is the caller graph for this function: