NeoMutt  2023-03-22-27-g3cb248
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 "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. 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 86 of file imap.c.

87{
89}
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:76
#define mutt_array_size(x)
Definition: memory.h:36
+ 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 479 of file imap.c.

480{
481 if (imap_path_status(path, false) >= 0)
482 return 0;
483 return -1;
484}
int imap_path_status(const char *path, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1249
+ 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 1118 of file imap.c.

1119{
1120 if (!m || !m->account)
1121 return MX_STATUS_ERROR;
1122
1124 struct ImapMboxData *mdata = imap_mdata_get(m);
1125
1126 /* overload keyboard timeout to avoid many mailbox checks in a row.
1127 * Most users don't like having to wait exactly when they press a key. */
1128 int rc = 0;
1129
1130 /* try IDLE first, unless force is set */
1131 const bool c_imap_idle = cs_subset_bool(NeoMutt->sub, "imap_idle");
1132 const short c_imap_keepalive = cs_subset_number(NeoMutt->sub, "imap_keepalive");
1133 if (!force && c_imap_idle && (adata->capabilities & IMAP_CAP_IDLE) &&
1134 ((adata->state != IMAP_IDLE) || (mutt_date_now() >= adata->lastread + c_imap_keepalive)))
1135 {
1136 if (imap_cmd_idle(adata) < 0)
1137 return MX_STATUS_ERROR;
1138 }
1139 if (adata->state == IMAP_IDLE)
1140 {
1141 while ((rc = mutt_socket_poll(adata->conn, 0)) > 0)
1142 {
1143 if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
1144 {
1145 mutt_debug(LL_DEBUG1, "Error reading IDLE response\n");
1146 return MX_STATUS_ERROR;
1147 }
1148 }
1149 if (rc < 0)
1150 {
1151 mutt_debug(LL_DEBUG1, "Poll failed, disabling IDLE\n");
1152 adata->capabilities &= ~IMAP_CAP_IDLE; // Clear the flag
1153 }
1154 }
1155
1156 const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
1157 if ((force || ((adata->state != IMAP_IDLE) && (mutt_date_now() >= adata->lastread + c_timeout))) &&
1158 (imap_exec(adata, "NOOP", IMAP_CMD_POLL) != IMAP_EXEC_SUCCESS))
1159 {
1160 return MX_STATUS_ERROR;
1161 }
1162
1163 /* We call this even when we haven't run NOOP in case we have pending
1164 * changes to process, since we can reopen here. */
1165 imap_cmd_finish(adata);
1166
1167 enum MxStatus check = MX_STATUS_OK;
1168 if (mdata->check_status & IMAP_EXPUNGE_PENDING)
1169 check = MX_STATUS_REOPENED;
1170 else if (mdata->check_status & IMAP_NEWMAIL_PENDING)
1171 check = MX_STATUS_NEW_MAIL;
1172 else if (mdata->check_status & IMAP_FLAGS_PENDING)
1173 check = MX_STATUS_FLAGS;
1174 else if (rc < 0)
1175 check = MX_STATUS_ERROR;
1176
1177 mdata->check_status = IMAP_OPEN_NO_FLAGS;
1178
1179 return check;
1180}
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_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:432
#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:1392
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1085
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:1260
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition: command.c:1325
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:196
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 521 of file imap.c.

522{
523 char buf[PATH_MAX + 7];
524 char mbox[PATH_MAX] = { 0 };
525 struct Url *url = url_parse(path);
526
528 imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), url->path);
529 url_free(&url);
530 snprintf(buf, sizeof(buf), "DELETE %s", mbox);
532 return -1;
533
534 return 0;
535}
#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:907
#define PATH_MAX
Definition: mutt.h:41
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:236
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 1545 of file imap.c.

1546{
1547 if (!m)
1548 return -1;
1549
1550 struct Email **emails = NULL;
1551 int rc;
1552
1554 struct ImapMboxData *mdata = imap_mdata_get(m);
1555
1556 if (adata->state < IMAP_SELECTED)
1557 {
1558 mutt_debug(LL_DEBUG2, "no mailbox selected\n");
1559 return -1;
1560 }
1561
1562 /* This function is only called when the calling code expects the context
1563 * to be changed. */
1565
1566 enum MxStatus check = imap_check_mailbox(m, false);
1567 if (check == MX_STATUS_ERROR)
1568 return check;
1569
1570 /* if we are expunging anyway, we can do deleted messages very quickly... */
1571 if (expunge && (m->rights & MUTT_ACL_DELETE))
1572 {
1573 rc = imap_exec_msgset(m, "UID STORE", "+FLAGS.SILENT (\\Deleted)",
1574 MUTT_DELETED, true, false);
1575 if (rc < 0)
1576 {
1577 mutt_error(_("Expunge failed"));
1578 return rc;
1579 }
1580
1581 if (rc > 0)
1582 {
1583 /* mark these messages as unchanged so second pass ignores them. Done
1584 * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */
1585 for (int i = 0; i < m->msg_count; i++)
1586 {
1587 struct Email *e = m->emails[i];
1588 if (!e)
1589 break;
1590 if (e->deleted && e->changed)
1591 e->active = false;
1592 }
1593 if (m->verbose)
1594 {
1595 mutt_message(ngettext("Marking %d message deleted...",
1596 "Marking %d messages deleted...", rc),
1597 rc);
1598 }
1599 }
1600 }
1601
1602#ifdef USE_HCACHE
1603 imap_hcache_open(adata, mdata);
1604#endif
1605
1606 /* save messages with real (non-flag) changes */
1607 for (int i = 0; i < m->msg_count; i++)
1608 {
1609 struct Email *e = m->emails[i];
1610 if (!e)
1611 break;
1612
1613 if (e->deleted)
1614 {
1615 imap_cache_del(m, e);
1616#ifdef USE_HCACHE
1617 imap_hcache_del(mdata, imap_edata_get(e)->uid);
1618#endif
1619 }
1620
1621 if (e->active && e->changed)
1622 {
1623#ifdef USE_HCACHE
1624 imap_hcache_put(mdata, e);
1625#endif
1626 /* if the message has been rethreaded or attachments have been deleted
1627 * we delete the message and reupload it.
1628 * This works better if we're expunging, of course. */
1629 /* TODO: why the e->env check? */
1630 if ((e->env && e->env->changed) || e->attach_del)
1631 {
1632 /* L10N: The plural is chosen by the last %d, i.e. the total number */
1633 if (m->verbose)
1634 {
1635 mutt_message(ngettext("Saving changed message... [%d/%d]",
1636 "Saving changed messages... [%d/%d]", m->msg_count),
1637 i + 1, m->msg_count);
1638 }
1639 bool save_append = m->append;
1640 m->append = true;
1642 m->append = save_append;
1643 /* TODO: why the check for e->env? Is this possible? */
1644 if (e->env)
1645 e->env->changed = 0;
1646 }
1647 }
1648 }
1649
1650#ifdef USE_HCACHE
1651 imap_hcache_close(mdata);
1652#endif
1653
1654 /* presort here to avoid doing 10 resorts in imap_exec_msgset */
1655 const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
1656 if (c_sort != SORT_ORDER)
1657 {
1658 emails = m->emails;
1659 m->emails = mutt_mem_malloc(m->msg_count * sizeof(struct Email *));
1660 memcpy(m->emails, emails, m->msg_count * sizeof(struct Email *));
1661
1663 qsort(m->emails, m->msg_count, sizeof(struct Email *), compare_uid);
1664 }
1665
1666 rc = sync_helper(m, MUTT_ACL_DELETE, MUTT_DELETED, "\\Deleted");
1667 if (rc >= 0)
1668 rc |= sync_helper(m, MUTT_ACL_WRITE, MUTT_FLAG, "\\Flagged");
1669 if (rc >= 0)
1670 rc |= sync_helper(m, MUTT_ACL_WRITE, MUTT_OLD, "Old");
1671 if (rc >= 0)
1672 rc |= sync_helper(m, MUTT_ACL_SEEN, MUTT_READ, "\\Seen");
1673 if (rc >= 0)
1674 rc |= sync_helper(m, MUTT_ACL_WRITE, MUTT_REPLIED, "\\Answered");
1675
1676 if (c_sort != SORT_ORDER)
1677 {
1678 cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
1679 FREE(&m->emails);
1680 m->emails = emails;
1681 }
1682
1683 /* Flush the queued flags if any were changed in sync_helper. */
1684 if (rc > 0)
1685 if (imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1686 rc = -1;
1687
1688 if (rc < 0)
1689 {
1690 if (close)
1691 {
1692 if (mutt_yesorno(_("Error saving flags. Close anyway?"), MUTT_NO) == MUTT_YES)
1693 {
1694 adata->state = IMAP_AUTHENTICATED;
1695 return 0;
1696 }
1697 }
1698 else
1699 {
1700 mutt_error(_("Error saving flags"));
1701 }
1702 return -1;
1703 }
1704
1705 /* Update local record of server state to reflect the synchronization just
1706 * completed. imap_read_headers always overwrites hcache-origin flags, so
1707 * there is no need to mutate the hcache after flag-only changes. */
1708 for (int i = 0; i < m->msg_count; i++)
1709 {
1710 struct Email *e = m->emails[i];
1711 if (!e)
1712 break;
1713 struct ImapEmailData *edata = imap_edata_get(e);
1714 edata->deleted = e->deleted;
1715 edata->flagged = e->flagged;
1716 edata->old = e->old;
1717 edata->read = e->read;
1718 edata->replied = e->replied;
1719 e->changed = false;
1720 }
1721 m->changed = false;
1722
1723 /* We must send an EXPUNGE command if we're not closing. */
1724 if (expunge && !close && (m->rights & MUTT_ACL_DELETE))
1725 {
1726 if (m->verbose)
1727 mutt_message(_("Expunging messages from server..."));
1728 /* Set expunge bit so we don't get spurious reopened messages */
1729 mdata->reopen |= IMAP_EXPUNGE_EXPECTED;
1730 if (imap_exec(adata, "EXPUNGE", IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1731 {
1732 mdata->reopen &= ~IMAP_EXPUNGE_EXPECTED;
1733 imap_error(_("imap_sync_mailbox: EXPUNGE failed"), adata->buf);
1734 return -1;
1735 }
1736 mdata->reopen &= ~IMAP_EXPUNGE_EXPECTED;
1737 }
1738
1739 if (expunge && close)
1740 {
1741 adata->closing = true;
1742 imap_exec(adata, "CLOSE", IMAP_CMD_NO_FLAGS);
1743 adata->state = IMAP_AUTHENTICATED;
1744 }
1745
1746 const bool c_message_cache_clean = cs_subset_bool(NeoMutt->sub, "message_cache_clean");
1747 if (c_message_cache_clean)
1749
1750 return check;
1751}
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
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: external.c:759
@ TRANSFORM_NONE
No transformation.
Definition: external.h:40
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: external.h:51
#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:914
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:1853
int imap_cache_del(struct Mailbox *m, struct Email *e)
Delete an email from the body cache.
Definition: message.c:1834
void imap_allow_reopen(struct Mailbox *m)
Allow re-opening a folder upon expunge.
Definition: util.c:1012
@ 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:379
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:338
int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
Delete an item from the header cache.
Definition: util.c:397
void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata)
Open a header cache.
Definition: util.c:296
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:940
static int sync_helper(struct Mailbox *m, AclFlags right, enum MessageType flag, const char *name)
Sync flag changes to the server.
Definition: imap.c:325
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition: imap.c:1118
@ 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:81
@ MUTT_OLD
Old messages.
Definition: mutt.h:79
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:87
@ MUTT_DELETED
Deleted messages.
Definition: mutt.h:86
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:80
@ 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:44
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:98
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 1249 of file imap.c.

1250{
1251 struct Mailbox *m = mx_mbox_find2(path);
1252
1253 const bool is_temp = !m;
1254 if (is_temp)
1255 {
1256 m = mx_path_resolve(path);
1257 if (!mx_mbox_ac_link(m))
1258 {
1259 mailbox_free(&m);
1260 return 0;
1261 }
1262 }
1263
1264 int rc = imap_mailbox_status(m, queue);
1265
1266 if (is_temp)
1267 {
1268 mx_ac_remove(m, false);
1269 mailbox_free(&m);
1270 }
1271
1272 return rc;
1273}
int imap_mailbox_status(struct Mailbox *m, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1284
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:1788
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1656
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:268
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1684
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 1284 of file imap.c.

1285{
1287 struct ImapMboxData *mdata = imap_mdata_get(m);
1288 if (!adata || !mdata)
1289 return -1;
1290 return imap_status(adata, mdata, queue);
1291}
static int imap_status(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1189
+ 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 1300 of file imap.c.

1301{
1302 struct ImapAccountData *adata = NULL;
1303 struct ImapMboxData *mdata = NULL;
1304 char buf[2048] = { 0 };
1305 struct Buffer err;
1306
1307 if (imap_adata_find(path, &adata, &mdata) < 0)
1308 return -1;
1309
1310 if (subscribe)
1311 mutt_message(_("Subscribing to %s..."), mdata->name);
1312 else
1313 mutt_message(_("Unsubscribing from %s..."), mdata->name);
1314
1315 snprintf(buf, sizeof(buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mdata->munge_name);
1316
1317 if (imap_exec(adata, buf, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1318 {
1319 imap_mdata_free((void *) &mdata);
1320 return -1;
1321 }
1322
1323 const bool c_imap_check_subscribed = cs_subset_bool(NeoMutt->sub, "imap_check_subscribed");
1324 if (c_imap_check_subscribed)
1325 {
1326 char mbox[1024] = { 0 };
1327 mutt_buffer_init(&err);
1328 err.dsize = 256;
1329 err.data = mutt_mem_malloc(err.dsize);
1330 size_t len = snprintf(mbox, sizeof(mbox), "%smailboxes ", subscribe ? "" : "un");
1331 imap_quote_string(mbox + len, sizeof(mbox) - len, path, true);
1332 if (parse_rc_line(mbox, &err))
1333 mutt_debug(LL_DEBUG1, "Error adding subscribed mailbox: %s\n", err.data);
1334 FREE(&err.data);
1335 }
1336
1337 if (subscribe)
1338 mutt_message(_("Subscribed to %s"), mdata->name);
1339 else
1340 mutt_message(_("Unsubscribed from %s"), mdata->name);
1341 imap_mdata_free((void *) &mdata);
1342 return 0;
1343}
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:833
int imap_adata_find(const char *path, struct ImapAccountData **adata, struct ImapMboxData **mdata)
Find the Account data for this path.
Definition: util.c:71
enum CommandResult parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: rc.c:109
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 1356 of file imap.c.

1357{
1358 struct ImapAccountData *adata = NULL;
1359 struct ImapMboxData *mdata = NULL;
1360 char tmp[2048] = { 0 };
1361 struct ImapList listresp = { 0 };
1362 char completion[1024] = { 0 };
1363 size_t clen;
1364 size_t matchlen = 0;
1365 int completions = 0;
1366 int rc;
1367
1368 if (imap_adata_find(path, &adata, &mdata) < 0)
1369 {
1370 mutt_str_copy(buf, path, buflen);
1371 return complete_hosts(buf, buflen);
1372 }
1373
1374 /* fire off command */
1375 const bool c_imap_list_subscribed = cs_subset_bool(NeoMutt->sub, "imap_list_subscribed");
1376 snprintf(tmp, sizeof(tmp), "%s \"\" \"%s%%\"",
1377 c_imap_list_subscribed ? "LSUB" : "LIST", mdata->real_name);
1378
1379 imap_cmd_start(adata, tmp);
1380
1381 /* and see what the results are */
1382 mutt_str_copy(completion, mdata->name, sizeof(completion));
1383 imap_mdata_free((void *) &mdata);
1384
1385 adata->cmdresult = &listresp;
1386 do
1387 {
1388 listresp.name = NULL;
1389 rc = imap_cmd_step(adata);
1390
1391 if ((rc == IMAP_RES_CONTINUE) && listresp.name)
1392 {
1393 /* if the folder isn't selectable, append delimiter to force browse
1394 * to enter it on second tab. */
1395 if (listresp.noselect)
1396 {
1397 clen = strlen(listresp.name);
1398 listresp.name[clen++] = listresp.delim;
1399 listresp.name[clen] = '\0';
1400 }
1401 /* copy in first word */
1402 if (!completions)
1403 {
1404 mutt_str_copy(completion, listresp.name, sizeof(completion));
1405 matchlen = strlen(completion);
1406 completions++;
1407 continue;
1408 }
1409
1410 matchlen = longest_common_prefix(completion, listresp.name, 0, matchlen);
1411 completions++;
1412 }
1413 } while (rc == IMAP_RES_CONTINUE);
1414 adata->cmdresult = NULL;
1415
1416 if (completions)
1417 {
1418 /* reformat output */
1419 imap_qualify_path(buf, buflen, &adata->conn->account, completion);
1420 mutt_pretty_mailbox(buf, buflen);
1421 return 0;
1422 }
1423
1424 return -1;
1425}
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:469
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1071
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
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:366
static int complete_hosts(char *buf, size_t buflen)
Look for completion matches for mailboxes.
Definition: imap.c:387
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:151
bool noselect
Definition: private.h:154
char * name
Definition: private.h:152
char delim
Definition: private.h:153
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 1435 of file imap.c.

1436{
1437 char prompt[1024] = { 0 };
1438 int rc = -1;
1439 bool triedcreate = false;
1440 enum QuadOption err_continue = MUTT_NO;
1441
1443 struct ImapAccountData *dest_adata = NULL;
1444 struct ImapMboxData *dest_mdata = NULL;
1445
1446 if (imap_adata_find(dest, &dest_adata, &dest_mdata) < 0)
1447 return -1;
1448
1449 struct Buffer sync_cmd = mutt_buffer_make(0);
1450
1451 /* check that the save-to folder is in the same account */
1452 if (!imap_account_match(&(adata->conn->account), &(dest_adata->conn->account)))
1453 {
1454 mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1455 goto out;
1456 }
1457
1458 for (int i = 0; i < m->msg_count; i++)
1459 {
1460 struct Email *e = m->emails[i];
1461 if (!e)
1462 break;
1463 if (e->active && e->changed && e->deleted && !e->purge)
1464 {
1465 rc = imap_sync_message_for_copy(m, e, &sync_cmd, &err_continue);
1466 if (rc < 0)
1467 {
1468 mutt_debug(LL_DEBUG1, "could not sync\n");
1469 goto out;
1470 }
1471 }
1472 }
1473
1474 /* loop in case of TRYCREATE */
1475 do
1476 {
1477 rc = imap_exec_msgset(m, "UID COPY", dest_mdata->munge_name, MUTT_TRASH, false, false);
1478 if (rc == 0)
1479 {
1480 mutt_debug(LL_DEBUG1, "No messages to trash\n");
1481 rc = -1;
1482 goto out;
1483 }
1484 else if (rc < 0)
1485 {
1486 mutt_debug(LL_DEBUG1, "could not queue copy\n");
1487 goto out;
1488 }
1489 else if (m->verbose)
1490 {
1491 mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1492 rc, dest_mdata->name);
1493 }
1494
1495 /* let's get it on */
1496 rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1497 if (rc == IMAP_EXEC_ERROR)
1498 {
1499 if (triedcreate)
1500 {
1501 mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", dest_mdata->name);
1502 break;
1503 }
1504 /* bail out if command failed for reasons other than nonexistent target */
1505 if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1506 break;
1507 mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1508 snprintf(prompt, sizeof(prompt), _("Create %s?"), dest_mdata->name);
1509 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
1510 if (c_confirm_create && (mutt_yesorno(prompt, MUTT_YES) != MUTT_YES))
1511 {
1513 goto out;
1514 }
1515 if (imap_create_mailbox(adata, dest_mdata->name) < 0)
1516 break;
1517 triedcreate = true;
1518 }
1519 } while (rc == IMAP_EXEC_ERROR);
1520
1521 if (rc != IMAP_EXEC_SUCCESS)
1522 {
1523 imap_error("imap_fast_trash", adata->buf);
1524 goto out;
1525 }
1526
1527 rc = IMAP_EXEC_SUCCESS;
1528
1529out:
1530 mutt_buffer_dealloc(&sync_cmd);
1531 imap_mdata_free((void *) &dest_mdata);
1532
1533 return ((rc == IMAP_EXEC_SUCCESS) ? 0 : -1);
1534}
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:347
@ 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:1040
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:453
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:1017
@ 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:209
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:93
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
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 662 of file imap.c.

663{
664 struct ImapMboxData *mdata = imap_mdata_get(m);
666
667 if (!mdata || !edata)
668 return;
669
670 imap_msn_remove(&mdata->msn, edata->msn - 1);
671 edata->msn = 0;
672}
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 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:142
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
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
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: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:155
List of Mailboxes.
Definition: mailbox.h:152
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:153
+ 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:298
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:365
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:78
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:58
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1408
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:494
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 1660 of file message.c.

1662{
1663 if (!m || !el || !dest)
1664 return -1;
1665
1666 struct Buffer cmd, sync_cmd;
1667 char buf[PATH_MAX] = { 0 };
1668 char mbox[PATH_MAX] = { 0 };
1669 char mmbox[PATH_MAX] = { 0 };
1670 char prompt[PATH_MAX + 64];
1671 int rc;
1672 struct ConnAccount cac = { { 0 } };
1673 enum QuadOption err_continue = MUTT_NO;
1674 int triedcreate = 0;
1675 struct EmailNode *en = STAILQ_FIRST(el);
1676 bool single = !STAILQ_NEXT(en, entries);
1678
1679 if (single && en->email->attach_del)
1680 {
1681 mutt_debug(LL_DEBUG3, "#1 Message contains attachments to be deleted\n");
1682 return 1;
1683 }
1684
1685 if (imap_parse_path(dest, &cac, buf, sizeof(buf)))
1686 {
1687 mutt_debug(LL_DEBUG1, "bad destination %s\n", dest);
1688 return -1;
1689 }
1690
1691 /* check that the save-to folder is in the same account */
1692 if (!imap_account_match(&adata->conn->account, &cac))
1693 {
1694 mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1695 return 1;
1696 }
1697
1698 imap_fix_path(adata->delim, buf, mbox, sizeof(mbox));
1699 if (*mbox == '\0')
1700 mutt_str_copy(mbox, "INBOX", sizeof(mbox));
1701 imap_munge_mbox_name(adata->unicode, mmbox, sizeof(mmbox), mbox);
1702
1703 /* loop in case of TRYCREATE */
1704 do
1705 {
1706 mutt_buffer_init(&sync_cmd);
1707 mutt_buffer_init(&cmd);
1708
1709 if (!single) /* copy tagged messages */
1710 {
1711 /* if any messages have attachments to delete, fall through to FETCH
1712 * and APPEND. TODO: Copy what we can with COPY, fall through for the
1713 * remainder. */
1714 STAILQ_FOREACH(en, el, entries)
1715 {
1716 if (en->email->attach_del)
1717 {
1718 mutt_debug(LL_DEBUG3, "#2 Message contains attachments to be deleted\n");
1719 return 1;
1720 }
1721
1722 if (en->email->active && en->email->changed)
1723 {
1724 rc = imap_sync_message_for_copy(m, en->email, &sync_cmd, &err_continue);
1725 if (rc < 0)
1726 {
1727 mutt_debug(LL_DEBUG1, "#1 could not sync\n");
1728 goto out;
1729 }
1730 }
1731 }
1732
1733 rc = imap_exec_msgset(m, "UID COPY", mmbox, MUTT_TAG, false, false);
1734 if (rc == 0)
1735 {
1736 mutt_debug(LL_DEBUG1, "No messages tagged\n");
1737 rc = -1;
1738 goto out;
1739 }
1740 else if (rc < 0)
1741 {
1742 mutt_debug(LL_DEBUG1, "#1 could not queue copy\n");
1743 goto out;
1744 }
1745 else
1746 {
1747 mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1748 rc, mbox);
1749 }
1750 }
1751 else
1752 {
1753 mutt_message(_("Copying message %d to %s..."), en->email->index + 1, mbox);
1754 mutt_buffer_add_printf(&cmd, "UID COPY %u %s", imap_edata_get(en->email)->uid, mmbox);
1755
1756 if (en->email->active && en->email->changed)
1757 {
1758 rc = imap_sync_message_for_copy(m, en->email, &sync_cmd, &err_continue);
1759 if (rc < 0)
1760 {
1761 mutt_debug(LL_DEBUG1, "#2 could not sync\n");
1762 goto out;
1763 }
1764 }
1765 rc = imap_exec(adata, cmd.data, IMAP_CMD_QUEUE);
1766 if (rc != IMAP_EXEC_SUCCESS)
1767 {
1768 mutt_debug(LL_DEBUG1, "#2 could not queue copy\n");
1769 goto out;
1770 }
1771 }
1772
1773 /* let's get it on */
1774 rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1775 if (rc == IMAP_EXEC_ERROR)
1776 {
1777 if (triedcreate)
1778 {
1779 mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", mbox);
1780 break;
1781 }
1782 /* bail out if command failed for reasons other than nonexistent target */
1783 if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1784 break;
1785 mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1786 snprintf(prompt, sizeof(prompt), _("Create %s?"), mbox);
1787 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
1788 if (c_confirm_create && (mutt_yesorno(prompt, MUTT_YES) != MUTT_YES))
1789 {
1791 goto out;
1792 }
1793 if (imap_create_mailbox(adata, mbox) < 0)
1794 break;
1795 triedcreate = 1;
1796 }
1797 } while (rc == IMAP_EXEC_ERROR);
1798
1799 if (rc != 0)
1800 {
1801 imap_error("imap_copy_messages", adata->buf);
1802 goto out;
1803 }
1804
1805 /* cleanup */
1806 if (save_opt == SAVE_MOVE)
1807 {
1808 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
1809 STAILQ_FOREACH(en, el, entries)
1810 {
1811 mutt_set_flag(m, en->email, MUTT_DELETE, true);
1812 mutt_set_flag(m, en->email, MUTT_PURGE, true);
1813 if (c_delete_untag)
1814 mutt_set_flag(m, en->email, MUTT_TAG, false);
1815 }
1816 }
1817
1818 rc = 0;
1819
1820out:
1821 FREE(&cmd.data);
1822 FREE(&sync_cmd.data);
1823
1824 return (rc < 0) ? -1 : rc;
1825}
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:85
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:88
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:83
#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:131
struct Email * email
Email in the list.
Definition: email.h:132
int index
The absolute (unsorted) message number.
Definition: email.h:109
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 568 of file imap.c.

569{
570 struct Account *np = NULL;
571 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
572 {
573 if (np->type != MUTT_IMAP)
574 continue;
575
576 struct ImapAccountData *adata = np->adata;
577 if (!adata)
578 continue;
579
580 struct Connection *conn = adata->conn;
581 if (!conn || (conn->fd < 0))
582 continue;
583
584 mutt_message(_("Closing connection to %s..."), conn->account.host);
585 imap_logout(np->adata);
587 }
588}
static void imap_logout(struct ImapAccountData *adata)
Gracefully log out of server.
Definition: imap.c:541
#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 2465 of file imap.c.

2466{
2468 return imap_path_canon(buf->data, PATH_MAX);
2469}
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:313
int imap_path_canon(char *buf, size_t buflen)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition: imap.c:2439
+ 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
#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:203
+ 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: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:2425
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:420
#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:1040
+ 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: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:679
+ 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 965 of file util.c.

966{
967 struct sigaction oldalrm;
968 struct sigaction act;
969 sigset_t oldmask;
970 int rc;
971
972 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
973 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", true, NULL);
974 OptKeepQuiet = true;
975
976 sigprocmask(SIG_SETMASK, NULL, &oldmask);
977
978 sigemptyset(&act.sa_mask);
979 act.sa_handler = mutt_sig_empty_handler;
980#ifdef SA_INTERRUPT
981 act.sa_flags = SA_INTERRUPT;
982#else
983 act.sa_flags = 0;
984#endif
985
986 sigaction(SIGALRM, &act, &oldalrm);
987
988 const short c_imap_keepalive = cs_subset_number(NeoMutt->sub, "imap_keepalive");
989 alarm(c_imap_keepalive);
990 while ((waitpid(pid, &rc, 0) < 0) && (errno == EINTR))
991 {
992 alarm(0); /* cancel a possibly pending alarm */
994 alarm(c_imap_keepalive);
995 }
996
997 alarm(0); /* cancel a possibly pending alarm */
998
999 sigaction(SIGALRM, &oldalrm, NULL);
1000 sigprocmask(SIG_SETMASK, &oldmask, NULL);
1001
1002 OptKeepQuiet = false;
1003 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1004
1005 return rc;
1006}
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition: globals.c:72
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:941
+ 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 941 of file util.c.

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

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

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