NeoMutt  2021-10-22-8-g9cb437
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 83 of file imap.c.

84 {
86 }
static const struct Command imap_commands[]
Definition: imap.c:73
#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 474 of file imap.c.

475 {
476  if (imap_path_status(path, false) >= 0)
477  return 0;
478  return -1;
479 }
int imap_path_status(const char *path, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1235
+ 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 enum MxStatus

Definition at line 1004 of file imap.c.

1104 {
1105  if (!m || !m->account)
1106  return MX_STATUS_ERROR;
1107 
1108  struct ImapAccountData *adata = imap_adata_get(m);
1109  struct ImapMboxData *mdata = imap_mdata_get(m);
1110 
1111  /* overload keyboard timeout to avoid many mailbox checks in a row.
1112  * Most users don't like having to wait exactly when they press a key. */
1113  int rc = 0;
1114 
1115  /* try IDLE first, unless force is set */
1116  const bool c_imap_idle = cs_subset_bool(NeoMutt->sub, "imap_idle");
1117  const short c_imap_keepalive =
1118  cs_subset_number(NeoMutt->sub, "imap_keepalive");
1119  if (!force && c_imap_idle && (adata->capabilities & IMAP_CAP_IDLE) &&
1120  ((adata->state != IMAP_IDLE) || (mutt_date_epoch() >= adata->lastread + c_imap_keepalive)))
1121  {
1122  if (imap_cmd_idle(adata) < 0)
1123  return MX_STATUS_ERROR;
1124  }
1125  if (adata->state == IMAP_IDLE)
1126  {
1127  while ((rc = mutt_socket_poll(adata->conn, 0)) > 0)
1128  {
1129  if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
1130  {
1131  mutt_debug(LL_DEBUG1, "Error reading IDLE response\n");
1132  return MX_STATUS_ERROR;
1133  }
1134  }
1135  if (rc < 0)
1136  {
1137  mutt_debug(LL_DEBUG1, "Poll failed, disabling IDLE\n");
1138  adata->capabilities &= ~IMAP_CAP_IDLE; // Clear the flag
1139  }
1140  }
1141 
1142  const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
1143  if ((force || ((adata->state != IMAP_IDLE) &&
1144  (mutt_date_epoch() >= adata->lastread + c_timeout))) &&
1145  (imap_exec(adata, "NOOP", IMAP_CMD_POLL) != IMAP_EXEC_SUCCESS))
1146  {
1147  return MX_STATUS_ERROR;
1148  }
1149 
1150  /* We call this even when we haven't run NOOP in case we have pending
1151  * changes to process, since we can reopen here. */
1152  imap_cmd_finish(adata);
1153 
1154  enum MxStatus check = MX_STATUS_OK;
1155  if (mdata->check_status & IMAP_EXPUNGE_PENDING)
1156  check = MX_STATUS_REOPENED;
1157  else if (mdata->check_status & IMAP_NEWMAIL_PENDING)
1158  check = MX_STATUS_NEW_MAIL;
1159  else if (mdata->check_status & IMAP_FLAGS_PENDING)
1160  check = MX_STATUS_FLAGS;
1161  else if (rc < 0)
1162  check = MX_STATUS_ERROR;
1163 
1164  mdata->check_status = IMAP_OPEN_NO_FLAGS;
1165 
1166  return check;
1167 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
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
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: adata.c:90
int imap_cmd_idle(struct ImapAccountData *adata)
Enter the IDLE state.
Definition: command.c:1387
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1083
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:1254
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition: command.c:1320
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: mdata.c:59
#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:76
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:77
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:78
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mxapi.h:82
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:81
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:79
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:192
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:136
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:131
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 516 of file imap.c.

517 {
518  char buf[PATH_MAX + 7];
519  char mbox[PATH_MAX];
520  struct Url *url = url_parse(path);
521 
522  struct ImapAccountData *adata = imap_adata_get(m);
523  imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), url->path);
524  url_free(&url);
525  snprintf(buf, sizeof(buf), "DELETE %s", mbox);
527  return -1;
528 
529  return 0;
530 }
#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:914
#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 1423 of file imap.c.

1535 {
1536  if (!m)
1537  return -1;
1538 
1539  struct Email **emails = NULL;
1540  int rc;
1541 
1542  struct ImapAccountData *adata = imap_adata_get(m);
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. */
1553  imap_allow_reopen(m);
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 =
1734  cs_subset_bool(NeoMutt->sub, "message_cache_clean");
1735  if (c_message_cache_clean)
1736  imap_cache_clean(m);
1737 
1738  return check;
1739 }
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:760
@ TRANSFORM_NONE
No transformation.
Definition: commands.h:40
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: commands.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:904
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:64
int imap_cache_clean(struct Mailbox *m)
Delete all the entries in the message cache.
Definition: message.c:1837
int imap_cache_del(struct Mailbox *m, struct Email *e)
Delete an email from the body cache.
Definition: message.c:1818
void imap_allow_reopen(struct Mailbox *m)
Allow re-opening a folder upon expunge.
Definition: util.c:1021
@ 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:381
void imap_error(const char *where, const char *msg)
Show an error and abort.
Definition: util.c:665
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition: util.c:340
int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
Delete an item from the header cache.
Definition: util.c:399
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:927
static int sync_helper(struct Mailbox *m, AclFlags right, enum MessageType flag, const char *name)
Sync flag changes to the server.
Definition: imap.c:324
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition: imap.c:1103
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:66
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:74
#define MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition: mailbox.h:73
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:40
#define _(a)
Definition: message.h:28
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:92
@ MUTT_OLD
Old messages.
Definition: mutt.h:90
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:98
@ MUTT_DELETED
Deleted messages.
Definition: mutt.h:97
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:91
@ 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:182
@ 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:90
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:114
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:113
int msg_count
Total number of messages.
Definition: mailbox.h:91
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
bool verbose
Display status messages?
Definition: mailbox.h:118
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

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

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

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

1287 {
1288  struct ImapAccountData *adata = NULL;
1289  struct ImapMboxData *mdata = NULL;
1290  char buf[2048];
1291  struct Buffer err;
1292 
1293  if (imap_adata_find(path, &adata, &mdata) < 0)
1294  return -1;
1295 
1296  if (subscribe)
1297  mutt_message(_("Subscribing to %s..."), mdata->name);
1298  else
1299  mutt_message(_("Unsubscribing from %s..."), mdata->name);
1300 
1301  snprintf(buf, sizeof(buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mdata->munge_name);
1302 
1303  if (imap_exec(adata, buf, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1304  {
1305  imap_mdata_free((void *) &mdata);
1306  return -1;
1307  }
1308 
1309  const bool c_imap_check_subscribed =
1310  cs_subset_bool(NeoMutt->sub, "imap_check_subscribed");
1311  if (c_imap_check_subscribed)
1312  {
1313  char mbox[1024];
1314  mutt_buffer_init(&err);
1315  err.dsize = 256;
1316  err.data = mutt_mem_malloc(err.dsize);
1317  size_t len = snprintf(mbox, sizeof(mbox), "%smailboxes ", subscribe ? "" : "un");
1318  imap_quote_string(mbox + len, sizeof(mbox) - len, path, true);
1319  if (mutt_parse_rc_line(mbox, &err))
1320  mutt_debug(LL_DEBUG1, "Error adding subscribed mailbox: %s\n", err.data);
1321  FREE(&err.data);
1322  }
1323 
1324  if (subscribe)
1325  mutt_message(_("Subscribed to %s"), mdata->name);
1326  else
1327  mutt_message(_("Unsubscribed from %s"), mdata->name);
1328  imap_mdata_free((void *) &mdata);
1329  return 0;
1330 }
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
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:840
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:1043
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 1343 of file imap.c.

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

1424 {
1425  char prompt[1024];
1426  int rc = -1;
1427  bool triedcreate = false;
1428  enum QuadOption err_continue = MUTT_NO;
1429 
1430  struct ImapAccountData *adata = imap_adata_get(m);
1431  struct ImapAccountData *dest_adata = NULL;
1432  struct ImapMboxData *dest_mdata = NULL;
1433 
1434  if (imap_adata_find(dest, &dest_adata, &dest_mdata) < 0)
1435  return -1;
1436 
1437  struct Buffer sync_cmd = mutt_buffer_make(0);
1438 
1439  /* check that the save-to folder is in the same account */
1440  if (!imap_account_match(&(adata->conn->account), &(dest_adata->conn->account)))
1441  {
1442  mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1443  goto out;
1444  }
1445 
1446  for (int i = 0; i < m->msg_count; i++)
1447  {
1448  struct Email *e = m->emails[i];
1449  if (!e)
1450  break;
1451  if (e->active && e->changed && e->deleted && !e->purge)
1452  {
1453  rc = imap_sync_message_for_copy(m, e, &sync_cmd, &err_continue);
1454  if (rc < 0)
1455  {
1456  mutt_debug(LL_DEBUG1, "could not sync\n");
1457  goto out;
1458  }
1459  }
1460  }
1461 
1462  /* loop in case of TRYCREATE */
1463  do
1464  {
1465  rc = imap_exec_msgset(m, "UID COPY", dest_mdata->munge_name, MUTT_TRASH, false, false);
1466  if (rc == 0)
1467  {
1468  mutt_debug(LL_DEBUG1, "No messages to trash\n");
1469  rc = -1;
1470  goto out;
1471  }
1472  else if (rc < 0)
1473  {
1474  mutt_debug(LL_DEBUG1, "could not queue copy\n");
1475  goto out;
1476  }
1477  else if (m->verbose)
1478  {
1479  mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1480  rc, dest_mdata->name);
1481  }
1482 
1483  /* let's get it on */
1484  rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1485  if (rc == IMAP_EXEC_ERROR)
1486  {
1487  if (triedcreate)
1488  {
1489  mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", dest_mdata->name);
1490  break;
1491  }
1492  /* bail out if command failed for reasons other than nonexistent target */
1493  if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1494  break;
1495  mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1496  snprintf(prompt, sizeof(prompt), _("Create %s?"), dest_mdata->name);
1497  const bool c_confirm_create =
1498  cs_subset_bool(NeoMutt->sub, "confirm_create");
1499  if (c_confirm_create && (mutt_yesorno(prompt, MUTT_YES) != MUTT_YES))
1500  {
1501  mutt_clear_error();
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 
1518 out:
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:61
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
@ 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:1049
char * imap_get_qualifier(char *buf)
Get the qualifier from a tagged response.
Definition: util.c:775
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:1004
int imap_create_mailbox(struct ImapAccountData *adata, char *mailbox)
Create a new mailbox.
Definition: imap.c:448
@ 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:215
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
@ MUTT_TRASH
Trashed messages.
Definition: mutt.h:104
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
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 656 of file imap.c.

657 {
658  struct ImapMboxData *mdata = imap_mdata_get(m);
659  struct ImapEmailData *edata = imap_edata_get(e);
660 
661  if (!mdata || !edata)
662  return;
663 
664  imap_msn_remove(&mdata->msn, edata->msn - 1);
665  edata->msn = 0;
666 }
void imap_msn_remove(struct MSN *msn, size_t idx)
Remove an entry from the cache.
Definition: msn.c:112
+ 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];
189  char munged_mbox[PATH_MAX];
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 =
203  cs_subset_bool(NeoMutt->sub, "imap_check_subscribed");
204  cs_subset_str_native_set(NeoMutt->sub, "imap_check_subscribed", false, NULL);
205 
206  // Pick first mailbox connected to the same server
207  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
209  struct MailboxNode *np = NULL;
210  STAILQ_FOREACH(np, &ml, entries)
211  {
212  adata = imap_adata_get(np->mailbox);
213  // Pick first mailbox connected on the same server
214  if (imap_account_match(&adata->conn->account, &cac))
215  break;
216  adata = NULL;
217  }
219  if (!adata)
220  goto fail;
221 
222  const bool c_imap_list_subscribed =
223  cs_subset_bool(NeoMutt->sub, "imap_list_subscribed");
224  if (c_imap_list_subscribed)
225  {
226  /* RFC3348 section 3 states LSUB is unreliable for hierarchy information.
227  * The newer LIST extensions are designed for this. */
229  list_cmd = "LIST (SUBSCRIBED RECURSIVEMATCH)";
230  else
231  list_cmd = "LSUB";
232  }
233  else
234  {
235  list_cmd = "LIST";
236  }
237 
238  mutt_message(_("Getting folder list..."));
239 
240  /* skip check for parents when at the root */
241  if (buf[0] == '\0')
242  {
243  mbox[0] = '\0';
244  n = 0;
245  }
246  else
247  {
248  imap_fix_path(adata->delim, buf, mbox, sizeof(mbox));
249  n = mutt_str_len(mbox);
250  }
251 
252  if (n)
253  {
254  int rc;
255  mutt_debug(LL_DEBUG3, "mbox: %s\n", mbox);
256 
257  /* if our target exists and has inferiors, enter it if we
258  * aren't already going to */
259  imap_munge_mbox_name(adata->unicode, munged_mbox, sizeof(munged_mbox), mbox);
260  len = snprintf(buf, sizeof(buf), "%s \"\" %s", list_cmd, munged_mbox);
262  snprintf(buf + len, sizeof(buf) - len, " RETURN (CHILDREN)");
263  imap_cmd_start(adata, buf);
264  adata->cmdresult = &list;
265  do
266  {
267  list.name = 0;
268  rc = imap_cmd_step(adata);
269  if ((rc == IMAP_RES_CONTINUE) && list.name)
270  {
271  if (!list.noinferiors && list.name[0] &&
272  (imap_mxcmp(list.name, mbox) == 0) && (n < sizeof(mbox) - 1))
273  {
274  mbox[n++] = list.delim;
275  mbox[n] = '\0';
276  }
277  }
278  } while (rc == IMAP_RES_CONTINUE);
279  adata->cmdresult = NULL;
280 
281  /* if we're descending a folder, mark it as current in browser_state */
282  if (mbox[n - 1] == list.delim)
283  {
284  showparents = true;
285  imap_qualify_path(buf, sizeof(buf), &cac, mbox);
286  state->folder = mutt_str_dup(buf);
287  n--;
288  }
289 
290  /* Find superiors to list
291  * Note: UW-IMAP servers return folder + delimiter when asked to list
292  * folder + delimiter. Cyrus servers don't. So we ask for folder,
293  * and tack on delimiter ourselves.
294  * Further note: UW-IMAP servers return nothing when asked for
295  * NAMESPACES without delimiters at the end. Argh! */
296  for (n--; n >= 0 && mbox[n] != list.delim; n--)
297  ; // do nothing
298 
299  if (n > 0) /* "aaaa/bbbb/" -> "aaaa" */
300  {
301  /* forget the check, it is too delicate (see above). Have we ever
302  * had the parent not exist? */
303  ctmp = mbox[n];
304  mbox[n] = '\0';
305 
306  if (showparents)
307  {
308  mutt_debug(LL_DEBUG3, "adding parent %s\n", mbox);
309  add_folder(list.delim, mbox, true, false, state, true);
310  }
311 
312  /* if our target isn't a folder, we are in our superior */
313  if (!state->folder)
314  {
315  /* store folder with delimiter */
316  mbox[n++] = ctmp;
317  ctmp = mbox[n];
318  mbox[n] = '\0';
319  imap_qualify_path(buf, sizeof(buf), &cac, mbox);
320  state->folder = mutt_str_dup(buf);
321  }
322  mbox[n] = ctmp;
323  }
324  /* "/bbbb/" -> add "/", "aaaa/" -> add "" */
325  else
326  {
327  char relpath[2];
328  /* folder may be "/" */
329  snprintf(relpath, sizeof(relpath), "%c", (n < 0) ? '\0' : adata->delim);
330  if (showparents)
331  add_folder(adata->delim, relpath, true, false, state, true);
332  if (!state->folder)
333  {
334  imap_qualify_path(buf, sizeof(buf), &cac, relpath);
335  state->folder = mutt_str_dup(buf);
336  }
337  }
338  }
339 
340  /* no namespace, no folder: set folder to host only */
341  if (!state->folder)
342  {
343  imap_qualify_path(buf, sizeof(buf), &cac, NULL);
344  state->folder = mutt_str_dup(buf);
345  }
346 
347  mutt_debug(LL_DEBUG3, "Quoting mailbox scan: %s -> ", mbox);
348  snprintf(buf, sizeof(buf), "%s%%", mbox);
349  imap_munge_mbox_name(adata->unicode, munged_mbox, sizeof(munged_mbox), buf);
350  mutt_debug(LL_DEBUG3, "%s\n", munged_mbox);
351  len = snprintf(buf, sizeof(buf), "%s \"\" %s", list_cmd, munged_mbox);
353  snprintf(buf + len, sizeof(buf) - len, " RETURN (CHILDREN)");
354  if (browse_add_list_result(adata, buf, state, false))
355  goto fail;
356 
357  if (ARRAY_EMPTY(&state->entry))
358  {
359  // L10N: (%s) is the name / path of the folder we were trying to browse
360  mutt_error(_("No such folder: %s"), path);
361  goto fail;
362  }
363 
365 
366  cs_subset_str_native_set(NeoMutt->sub, "imap_check_subscribed",
367  c_imap_check_subscribed, NULL);
368  return 0;
369 
370 fail:
371  cs_subset_str_native_set(NeoMutt->sub, "imap_check_subscribed",
372  c_imap_check_subscribed, NULL);
373  return -1;
374 }
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:70
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:483
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:554
char * imap_fix_path(char delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition: util.c:687
#define IMAP_CAP_LIST_EXTENDED
RFC5258: IMAP4 LIST Command Extensions.
Definition: private.h:140
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:53
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
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: browser.h:96
struct BrowserStateEntry entry
Array of files / dirs / mailboxes.
Definition: browser.h:93
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:157
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:158
+ 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 384 of file browse.c.

385 {
386  struct ImapAccountData *adata = NULL;
387  struct ImapMboxData *mdata = NULL;
388  char name[1024];
389 
390  if (imap_adata_find(path, &adata, &mdata) < 0)
391  {
392  mutt_debug(LL_DEBUG1, "Couldn't find open connection to %s\n", path);
393  goto err;
394  }
395 
396  /* append a delimiter if necessary */
397  const size_t n = mutt_str_copy(name, mdata->real_name, sizeof(name));
398  if (n && (n < sizeof(name) - 1) && (name[n - 1] != adata->delim))
399  {
400  name[n] = adata->delim;
401  name[n + 1] = '\0';
402  }
403 
404  if (mutt_get_field(_("Create mailbox: "), name, sizeof(name), MUTT_FILE,
405  false, NULL, NULL) < 0)
406  {
407  goto err;
408  }
409 
410  if (mutt_str_len(name) == 0)
411  {
412  mutt_error(_("Mailbox must have a name"));
413  goto err;
414  }
415 
416  if (imap_create_mailbox(adata, name) < 0)
417  goto err;
418 
419  imap_mdata_free((void *) &mdata);
420  mutt_message(_("Mailbox created"));
421  mutt_sleep(0);
422  return 0;
423 
424 err:
425  imap_mdata_free((void *) &mdata);
426  return -1;
427 }
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:335
#define MUTT_FILE
Do file completion.
Definition: mutt.h:54
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1461
+ 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 437 of file browse.c.

438 {
439  struct ImapAccountData *adata = NULL;
440  struct ImapMboxData *mdata = NULL;
441  char buf[PATH_MAX];
442  char newname[PATH_MAX];
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  return -1;
448  }
449 
450  if (mdata->real_name[0] == '\0')
451  {
452  mutt_error(_("Can't rename root folder"));
453  goto err;
454  }
455 
456  snprintf(buf, sizeof(buf), _("Rename mailbox %s to: "), mdata->name);
457  mutt_str_copy(newname, mdata->name, sizeof(newname));
458 
459  if (mutt_get_field(buf, newname, sizeof(newname), MUTT_FILE, false, NULL, NULL) < 0)
460  goto err;
461 
462  if (mutt_str_len(newname) == 0)
463  {
464  mutt_error(_("Mailbox must have a name"));
465  goto err;
466  }
467 
468  imap_fix_path(adata->delim, newname, buf, sizeof(buf));
469 
470  if (imap_rename_mailbox(adata, mdata->name, buf) < 0)
471  {
472  mutt_error(_("Rename failed: %s"), imap_get_qualifier(adata->buf));
473  goto err;
474  }
475 
476  mutt_message(_("Mailbox renamed"));
477  mutt_sleep(0);
478  return 0;
479 
480 err:
481  imap_mdata_free((void *) &mdata);
482  return -1;
483 }
int imap_rename_mailbox(struct ImapAccountData *adata, char *oldname, const char *newname)
Rename a mailbox.
Definition: imap.c:489
+ 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 1642 of file message.c.

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

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

2443 {
2445  return imap_path_canon(buf->data, PATH_MAX);
2446 }
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:265
int imap_path_canon(char *buf, size_t buflen)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition: imap.c:2416
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_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 483 of file util.c.

484 {
485  static unsigned short ImapPort = 0;
486  static unsigned short ImapsPort = 0;
487 
488  if (ImapPort == 0)
489  {
490  struct servent *service = getservbyname("imap", "tcp");
491  if (service)
492  ImapPort = ntohs(service->s_port);
493  else
494  ImapPort = IMAP_PORT;
495  mutt_debug(LL_DEBUG3, "Using default IMAP port %d\n", ImapPort);
496  }
497 
498  if (ImapsPort == 0)
499  {
500  struct servent *service = getservbyname("imaps", "tcp");
501  if (service)
502  ImapsPort = ntohs(service->s_port);
503  else
504  ImapsPort = IMAP_SSL_PORT;
505  mutt_debug(LL_DEBUG3, "Using default IMAPS port %d\n", ImapsPort);
506  }
507 
508  /* Defaults */
509  cac->port = ImapPort;
510  cac->type = MUTT_ACCT_TYPE_IMAP;
511  cac->service = "imap";
512  cac->get_field = imap_get_field;
513 
514  struct Url *url = url_parse(path);
515  if (!url)
516  return -1;
517 
518  if ((url->scheme != U_IMAP) && (url->scheme != U_IMAPS))
519  {
520  url_free(&url);
521  return -1;
522  }
523 
524  if ((mutt_account_fromurl(cac, url) < 0) || (cac->host[0] == '\0'))
525  {
526  url_free(&url);
527  return -1;
528  }
529 
530  if (url->scheme == U_IMAPS)
531  cac->flags |= MUTT_ACCT_SSL;
532 
533  mutt_str_copy(mailbox, url->path, mailboxlen);
534 
535  url_free(&url);
536 
537  if ((cac->flags & MUTT_ACCT_SSL) && !(cac->flags & MUTT_ACCT_PORT))
538  cac->port = ImapsPort;
539 
540  return 0;
541 }
#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 590 of file util.c.

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

555 {
556  char *b1 = NULL;
557  char *b2 = NULL;
558  int rc;
559 
560  if (!mx1 || (*mx1 == '\0'))
561  mx1 = "INBOX";
562  if (!mx2 || (*mx2 == '\0'))
563  mx2 = "INBOX";
564  if (mutt_istr_equal(mx1, "INBOX") && mutt_istr_equal(mx2, "INBOX"))
565  {
566  return 0;
567  }
568 
569  b1 = mutt_mem_malloc(strlen(mx1) + 1);
570  b2 = mutt_mem_malloc(strlen(mx2) + 1);
571 
572  imap_fix_path('\0', mx1, b1, strlen(mx1) + 1);
573  imap_fix_path('\0', mx2, b2, strlen(mx2) + 1);
574 
575  rc = mutt_str_cmp(b1, b2);
576  FREE(&b1);
577  FREE(&b2);
578 
579  return rc;
580 }
int mutt_str_cmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:567
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * imap_fix_path(char delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition: util.c:687
+ 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 973 of file util.c.

974 {
975  struct sigaction oldalrm;
976  struct sigaction act;
977  sigset_t oldmask;
978  int rc;
979 
980  const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
981  cs_subset_str_native_set(NeoMutt->sub, "imap_passive", true, NULL);
982  OptKeepQuiet = true;
983 
984  sigprocmask(SIG_SETMASK, NULL, &oldmask);
985 
986  sigemptyset(&act.sa_mask);
987  act.sa_handler = mutt_sig_empty_handler;
988 #ifdef SA_INTERRUPT
989  act.sa_flags = SA_INTERRUPT;
990 #else
991  act.sa_flags = 0;
992 #endif
993 
994  sigaction(SIGALRM, &act, &oldalrm);
995 
996  const short c_imap_keepalive =
997  cs_subset_number(NeoMutt->sub, "imap_keepalive");
998  alarm(c_imap_keepalive);
999  while ((waitpid(pid, &rc, 0) < 0) && (errno == EINTR))
1000  {
1001  alarm(0); /* cancel a possibly pending alarm */
1002  imap_keepalive();
1003  alarm(c_imap_keepalive);
1004  }
1005 
1006  alarm(0); /* cancel a possibly pending alarm */
1007 
1008  sigaction(SIGALRM, &oldalrm, NULL);
1009  sigprocmask(SIG_SETMASK, &oldmask, NULL);
1010 
1011  OptKeepQuiet = false;
1012  cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1013 
1014  return rc;
1015 }
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:948
+ 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 948 of file util.c.

949 {
950  time_t now = mutt_date_epoch();
951  struct Account *np = NULL;
952  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
953  {
954  if (np->type != MUTT_IMAP)
955  continue;
956 
957  struct ImapAccountData *adata = np->adata;
958  if (!adata || !adata->mailbox)
959  continue;
960 
961  const short c_imap_keepalive =
962  cs_subset_number(NeoMutt->sub, "imap_keepalive");
963  if ((adata->state >= IMAP_AUTHENTICATED) && (now >= (adata->lastread + c_imap_keepalive)))
964  imap_check_mailbox(adata->mailbox, true);
965  }
966 }
+ 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];
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:823
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 
246  struct ImapAccountData *adata = imap_adata_get(m);
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:225
#define SLIST_FIRST(head)
Definition: queue.h:229
static bool compile_search(const struct ImapAccountData *adata, const struct Pattern *pat, struct Buffer *buf)
Convert NeoMutt pattern to IMAP search.
Definition: search.c: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: