NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
lib.h File Reference

IMAP network mailbox. More...

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

Go to the source code of this file.

Functions

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

Variables

const struct MxOps MxImapOps
 IMAP Mailbox - Implements MxOps -.
 

Detailed Description

IMAP network mailbox.

Authors
  • 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 88 of file imap.c.

89{
91}
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:78
#define mutt_array_size(x)
Definition: memory.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_access()

int imap_access ( const char *  path)

Check permissions on an IMAP mailbox with a new connection.

Parameters
pathMailbox path
Return values
0Success
<0Failure

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

Definition at line 455 of file imap.c.

456{
457 if (imap_path_status(path, false) >= 0)
458 return 0;
459 return -1;
460}
int imap_path_status(const char *path, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1157
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_check_mailbox()

enum MxStatus imap_check_mailbox ( struct Mailbox m,
bool  force 
)

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

Parameters
mMailbox
forceDon't wait
Return values
numMxStatus

Definition at line 1019 of file imap.c.

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

◆ imap_delete_mailbox()

int imap_delete_mailbox ( struct Mailbox m,
char *  path 
)

Delete a mailbox.

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

Definition at line 497 of file imap.c.

498{
499 char buf[PATH_MAX + 7];
500 char mbox[PATH_MAX] = { 0 };
501 struct Url *url = url_parse(path);
502 if (!url)
503 return -1;
504
506 imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), url->path);
507 url_free(&url);
508 snprintf(buf, sizeof(buf), "DELETE %s", mbox);
510 return -1;
511
512 return 0;
513}
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: private.h:71
void imap_munge_mbox_name(bool unicode, char *dest, size_t dlen, const char *src)
Quote awkward characters in a mailbox name.
Definition: util.c:918
#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:238
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()

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

Sync all the changes to the server.

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

Definition at line 1459 of file imap.c.

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

1158{
1159 struct Mailbox *m = mx_mbox_find2(path);
1160
1161 const bool is_temp = !m;
1162 if (is_temp)
1163 {
1164 m = mx_path_resolve(path);
1165 if (!mx_mbox_ac_link(m))
1166 {
1167 mailbox_free(&m);
1168 return 0;
1169 }
1170 }
1171
1172 int rc = imap_mailbox_status(m, queue);
1173
1174 if (is_temp)
1175 {
1176 mx_ac_remove(m, false);
1177 mailbox_free(&m);
1178 }
1179
1180 return rc;
1181}
int imap_mailbox_status(struct Mailbox *m, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1192
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:90
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1801
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1666
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:267
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1697
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 1192 of file imap.c.

1193{
1195 struct ImapMboxData *mdata = imap_mdata_get(m);
1196 if (!adata || !mdata)
1197 return -1;
1198 return imap_status(adata, mdata, queue);
1199}
static int imap_status(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1090
+ 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 1208 of file imap.c.

1209{
1210 struct ImapAccountData *adata = NULL;
1211 struct ImapMboxData *mdata = NULL;
1212 struct Buffer err;
1213
1214 if (imap_adata_find(path, &adata, &mdata) < 0)
1215 return -1;
1216
1217 if (subscribe)
1218 mutt_message(_("Subscribing to %s..."), mdata->name);
1219 else
1220 mutt_message(_("Unsubscribing from %s..."), mdata->name);
1221
1222 char buf[2048] = { 0 };
1223 snprintf(buf, sizeof(buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mdata->munge_name);
1224
1225 if (imap_exec(adata, buf, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1226 {
1227 imap_mdata_free((void *) &mdata);
1228 return -1;
1229 }
1230
1231 const bool c_imap_check_subscribed = cs_subset_bool(NeoMutt->sub, "imap_check_subscribed");
1232 if (c_imap_check_subscribed)
1233 {
1234 char mbox[1024] = { 0 };
1235 buf_init(&err);
1236 err.dsize = 256;
1237 err.data = mutt_mem_malloc(err.dsize);
1238 size_t len = snprintf(mbox, sizeof(mbox), "%smailboxes ", subscribe ? "" : "un");
1239 imap_quote_string(mbox + len, sizeof(mbox) - len, path, true);
1240 if (parse_rc_line(mbox, &err))
1241 mutt_debug(LL_DEBUG1, "Error adding subscribed mailbox: %s\n", err.data);
1242 FREE(&err.data);
1243 }
1244
1245 if (subscribe)
1246 mutt_message(_("Subscribed to %s"), mdata->name);
1247 else
1248 mutt_message(_("Unsubscribed from %s"), mdata->name);
1249 imap_mdata_free((void *) &mdata);
1250 return 0;
1251}
struct Buffer * buf_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:55
void imap_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:39
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
Quote string according to IMAP rules.
Definition: util.c:844
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:104
String manipulation buffer.
Definition: buffer.h:34
char * munge_name
Munged version of the mailbox name.
Definition: mdata.h:42
char * name
Mailbox name.
Definition: mdata.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_complete()

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

Try to complete an IMAP folder path.

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

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

Definition at line 1263 of file imap.c.

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

◆ imap_fast_trash()

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

Use server COPY command to copy deleted messages to trash.

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

Definition at line 1344 of file imap.c.

1345{
1346 char prompt[1024] = { 0 };
1347 int rc = -1;
1348 bool triedcreate = false;
1349 enum QuadOption err_continue = MUTT_NO;
1350
1352 struct ImapAccountData *dest_adata = NULL;
1353 struct ImapMboxData *dest_mdata = NULL;
1354
1355 if (imap_adata_find(dest, &dest_adata, &dest_mdata) < 0)
1356 return -1;
1357
1358 struct Buffer sync_cmd = buf_make(0);
1359
1360 /* check that the save-to folder is in the same account */
1361 if (!imap_account_match(&(adata->conn->account), &(dest_adata->conn->account)))
1362 {
1363 mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1364 goto out;
1365 }
1366
1367 for (int i = 0; i < m->msg_count; i++)
1368 {
1369 struct Email *e = m->emails[i];
1370 if (!e)
1371 break;
1372 if (e->active && e->changed && e->deleted && !e->purge)
1373 {
1374 rc = imap_sync_message_for_copy(m, e, &sync_cmd, &err_continue);
1375 if (rc < 0)
1376 {
1377 mutt_debug(LL_DEBUG1, "could not sync\n");
1378 goto out;
1379 }
1380 }
1381 }
1382
1383 /* loop in case of TRYCREATE */
1384 do
1385 {
1386 struct UidArray uida = ARRAY_HEAD_INITIALIZER;
1387 select_email_uids(m->emails, m->msg_count, MUTT_TRASH, false, false, &uida);
1388 ARRAY_SORT(&uida, imap_sort_uid, NULL);
1389 rc = imap_exec_msg_set(adata, "UID COPY", dest_mdata->munge_name, &uida);
1390 if (rc == 0)
1391 {
1392 mutt_debug(LL_DEBUG1, "No messages to trash\n");
1393 rc = -1;
1394 goto out;
1395 }
1396 else if (rc < 0)
1397 {
1398 mutt_debug(LL_DEBUG1, "could not queue copy\n");
1399 goto out;
1400 }
1401 else if (m->verbose)
1402 {
1403 mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1404 rc, dest_mdata->name);
1405 }
1406 ARRAY_FREE(&uida);
1407
1408 /* let's get it on */
1409 rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1410 if (rc == IMAP_EXEC_ERROR)
1411 {
1412 if (triedcreate)
1413 {
1414 mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", dest_mdata->name);
1415 break;
1416 }
1417 /* bail out if command failed for reasons other than nonexistent target */
1418 if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1419 break;
1420 mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1421 snprintf(prompt, sizeof(prompt), _("Create %s?"), dest_mdata->name);
1422 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
1423 if (c_confirm_create &&
1424 (query_yesorno_help(prompt, MUTT_YES, NeoMutt->sub, "confirm_create") != MUTT_YES))
1425 {
1427 goto out;
1428 }
1429 if (imap_create_mailbox(adata, dest_mdata->name) < 0)
1430 break;
1431 triedcreate = true;
1432 }
1433 } while (rc == IMAP_EXEC_ERROR);
1434
1435 if (rc != IMAP_EXEC_SUCCESS)
1436 {
1437 imap_error("imap_fast_trash", adata->buf);
1438 goto out;
1439 }
1440
1441 rc = IMAP_EXEC_SUCCESS;
1442
1443out:
1444 buf_dealloc(&sync_cmd);
1445 imap_mdata_free((void *) &dest_mdata);
1446
1447 return ((rc == IMAP_EXEC_SUCCESS) ? 0 : -1);
1448}
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:389
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:70
@ IMAP_EXEC_ERROR
Imap command failure.
Definition: private.h:83
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition: util.c:1051
char * imap_get_qualifier(char *buf)
Get the qualifier from a tagged response.
Definition: util.c:765
int imap_create_mailbox(struct ImapAccountData *adata, const char *mailbox)
Create a new mailbox.
Definition: imap.c:429
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:918
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:240
@ MUTT_TRASH
Trashed messages.
Definition: mutt.h:84
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
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition: question.c:345
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 640 of file imap.c.

641{
642 struct ImapMboxData *mdata = imap_mdata_get(m);
644
645 if (!mdata || !edata)
646 return;
647
648 imap_msn_remove(&mdata->msn, edata->msn - 1);
649 edata->msn = 0;
650}
void imap_msn_remove(struct MSNArray *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 192 of file browse.c.

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

393{
394 struct ImapAccountData *adata = NULL;
395 struct ImapMboxData *mdata = NULL;
396 struct Buffer *name = buf_pool_get();
397 int rc = -1;
398
399 if (imap_adata_find(path, &adata, &mdata) < 0)
400 {
401 mutt_debug(LL_DEBUG1, "Couldn't find open connection to %s\n", path);
402 goto done;
403 }
404
405 /* append a delimiter if necessary */
406 const size_t n = buf_strcpy(name, mdata->real_name);
407 if ((n != 0) && (name->data[n - 1] != adata->delim))
408 {
409 buf_addch(name, adata->delim);
410 }
411
412 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
413 if (mw_get_field(_("Create mailbox: "), name, MUTT_COMP_NO_FLAGS, HC_FILE,
414 &CompleteMailboxOps, &cdata) != 0)
415 {
416 goto done;
417 }
418
419 if (buf_is_empty(name))
420 {
421 mutt_error(_("Mailbox must have a name"));
422 goto done;
423 }
424
425 if (imap_create_mailbox(adata, buf_string(name)) < 0)
426 goto done;
427
428 imap_mdata_free((void *) &mdata);
429 mutt_message(_("Mailbox created"));
430 mutt_sleep(0);
431 rc = 0;
432
433done:
434 imap_mdata_free((void *) &mdata);
435 buf_pool_release(&name);
436 return rc;
437}
const struct CompleteOps CompleteMailboxOps
Auto-Completion of Files / Mailboxes.
Definition: complete.c:160
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:275
@ HC_FILE
Files.
Definition: lib.h:52
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1428
Input for the file completion function.
Definition: curs_lib.h:49
+ 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 447 of file browse.c.

448{
449 struct ImapAccountData *adata = NULL;
450 struct ImapMboxData *mdata = NULL;
451 struct Buffer *buf = NULL;
452 struct Buffer *newname = NULL;
453 int rc = -1;
454
455 if (imap_adata_find(path, &adata, &mdata) < 0)
456 {
457 mutt_debug(LL_DEBUG1, "Couldn't find open connection to %s\n", path);
458 goto done;
459 }
460
461 if (mdata->real_name[0] == '\0')
462 {
463 mutt_error(_("Can't rename root folder"));
464 goto done;
465 }
466
467 buf = buf_pool_get();
468 newname = buf_pool_get();
469
470 buf_printf(buf, _("Rename mailbox %s to: "), mdata->name);
471 buf_strcpy(newname, mdata->name);
472
473 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
475 &CompleteMailboxOps, &cdata) != 0)
476 {
477 goto done;
478 }
479
480 if (buf_is_empty(newname))
481 {
482 mutt_error(_("Mailbox must have a name"));
483 goto done;
484 }
485
486 imap_fix_path(adata->delim, buf_string(newname), buf->data, buf->dsize);
487
488 if (imap_rename_mailbox(adata, mdata->name, buf_string(buf)) < 0)
489 {
490 mutt_error(_("Rename failed: %s"), imap_get_qualifier(adata->buf));
491 goto done;
492 }
493
494 mutt_message(_("Mailbox renamed"));
495 mutt_sleep(0);
496 rc = 0;
497
498done:
499 imap_mdata_free((void *) &mdata);
500 buf_pool_release(&buf);
501 buf_pool_release(&newname);
502
503 return rc;
504}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
int imap_rename_mailbox(struct ImapAccountData *adata, char *oldname, const char *newname)
Rename a mailbox.
Definition: imap.c:470
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 EmailArray *  ea,
const char *  dest,
enum MessageSaveOpt  save_opt 
)

Server COPY messages to another folder.

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

Definition at line 1668 of file message.c.

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

547{
548 struct Account *np = NULL;
549 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
550 {
551 if (np->type != MUTT_IMAP)
552 continue;
553
554 struct ImapAccountData *adata = np->adata;
555 if (!adata)
556 continue;
557
558 struct Connection *conn = adata->conn;
559 if (!conn || (conn->fd < 0))
560 continue;
561
562 mutt_message(_("Closing connection to %s..."), conn->account.host);
563 imap_logout(np->adata);
565 }
566}
static void imap_logout(struct ImapAccountData *adata)
Gracefully log out of server.
Definition: imap.c:519
#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:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_expand_path()

int imap_expand_path ( struct Buffer path)

Buffer wrapper around imap_path_canon()

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

Definition at line 2369 of file imap.c.

2370{
2371 buf_alloc(path, PATH_MAX);
2372 return imap_path_canon(path);
2373}
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:349
int imap_path_canon(struct Buffer *path)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition: imap.c:2343
+ 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 471 of file util.c.

472{
473 static unsigned short ImapPort = 0;
474 static unsigned short ImapsPort = 0;
475
476 if (ImapPort == 0)
477 {
478 struct servent *service = getservbyname("imap", "tcp");
479 if (service)
480 ImapPort = ntohs(service->s_port);
481 else
482 ImapPort = IMAP_PORT;
483 mutt_debug(LL_DEBUG3, "Using default IMAP port %d\n", ImapPort);
484 }
485
486 if (ImapsPort == 0)
487 {
488 struct servent *service = getservbyname("imaps", "tcp");
489 if (service)
490 ImapsPort = ntohs(service->s_port);
491 else
492 ImapsPort = IMAP_SSL_PORT;
493 mutt_debug(LL_DEBUG3, "Using default IMAPS port %d\n", ImapsPort);
494 }
495
496 /* Defaults */
497 cac->port = ImapPort;
499 cac->service = "imap";
501
502 struct Url *url = url_parse(path);
503 if (!url)
504 return -1;
505
506 if ((url->scheme != U_IMAP) && (url->scheme != U_IMAPS))
507 {
508 url_free(&url);
509 return -1;
510 }
511
512 if ((mutt_account_fromurl(cac, url) < 0) || (cac->host[0] == '\0'))
513 {
514 url_free(&url);
515 return -1;
516 }
517
518 if (url->scheme == U_IMAPS)
519 cac->flags |= MUTT_ACCT_SSL;
520
521 mutt_str_copy(mailbox, url->path, mailboxlen);
522
523 url_free(&url);
524
525 if ((cac->flags & MUTT_ACCT_SSL) && !(cac->flags & MUTT_ACCT_PORT))
526 cac->port = ImapsPort;
527
528 return 0;
529}
#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:44
#define IMAP_SSL_PORT
Port for IMAP over SSL/TLS.
Definition: private.h:45
int mutt_account_fromurl(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
Definition: mutt_account.c: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 578 of file util.c.

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

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

◆ imap_wait_keep_alive()

int imap_wait_keep_alive ( pid_t  pid)

Wait for a process to change state.

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

Definition at line 976 of file util.c.

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

◆ imap_keep_alive()

void imap_keep_alive ( void  )

Poll the current folder to keep the connection alive.

Definition at line 952 of file util.c.

953{
954 time_t now = mutt_date_now();
955 struct Account *np = NULL;
956 const short c_imap_keep_alive = cs_subset_number(NeoMutt->sub, "imap_keep_alive");
957 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
958 {
959 if (np->type != MUTT_IMAP)
960 continue;
961
962 struct ImapAccountData *adata = np->adata;
963 if (!adata || !adata->mailbox)
964 continue;
965
966 if ((adata->state >= IMAP_AUTHENTICATED) && (now >= (adata->lastread + c_imap_keep_alive)))
967 imap_check_mailbox(adata->mailbox, true);
968 }
969}
+ 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:813
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}
+ 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 buf_init(&buf);
244 buf_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 buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
#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: