NeoMutt  2022-04-29-247-gc6aae8
Teaching an old dog new tricks
DOXYGEN
imap.c File Reference

IMAP network mailbox. More...

#include "config.h"
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "conn/lib.h"
#include "mutt.h"
#include "lib.h"
#include "enter/lib.h"
#include "progress/lib.h"
#include "question/lib.h"
#include "adata.h"
#include "auth.h"
#include "command_parse.h"
#include "commands.h"
#include "edata.h"
#include "hook.h"
#include "init.h"
#include "mdata.h"
#include "msn.h"
#include "mutt_commands.h"
#include "mutt_logging.h"
#include "mutt_socket.h"
#include "muttlib.h"
#include "mx.h"
#include "sort.h"
#include <libintl.h>
+ Include dependency graph for imap.c:

Go to the source code of this file.

Functions

void imap_init (void)
 Setup feature commands. More...
 
static int check_capabilities (struct ImapAccountData *adata)
 Make sure we can log in to this server. More...
 
static char * get_flags (struct ListHead *hflags, char *s)
 Make a simple list out of a FLAGS response. More...
 
static void set_flag (struct Mailbox *m, AclFlags aclflag, bool flag, const char *str, char *flags, size_t flsize)
 Append str to flags if we currently have permission according to aclflag. More...
 
static int make_msg_set (struct Mailbox *m, struct Buffer *buf, enum MessageType flag, bool changed, bool invert, int *pos)
 Make a message set. More...
 
static bool compare_flags_for_copy (struct Email *e)
 Compare local flags against the server. More...
 
static int sync_helper (struct Mailbox *m, AclFlags right, enum MessageType flag, const char *name)
 Sync flag changes to the server. More...
 
static size_t longest_common_prefix (char *dest, const char *src, size_t start, size_t dlen)
 Find longest prefix common to two strings. More...
 
static int complete_hosts (char *buf, size_t buflen)
 Look for completion matches for mailboxes. More...
 
int imap_create_mailbox (struct ImapAccountData *adata, const char *mailbox)
 Create a new mailbox. More...
 
int imap_access (const char *path)
 Check permissions on an IMAP mailbox with a new connection. More...
 
int imap_rename_mailbox (struct ImapAccountData *adata, char *oldname, const char *newname)
 Rename a mailbox. More...
 
int imap_delete_mailbox (struct Mailbox *m, char *path)
 Delete a mailbox. More...
 
static void imap_logout (struct ImapAccountData *adata)
 Gracefully log out of server. More...
 
void imap_logout_all (void)
 Close all open connections. More...
 
int imap_read_literal (FILE *fp, struct ImapAccountData *adata, unsigned long bytes, struct Progress *progress)
 Read bytes bytes from server into file. More...
 
void imap_notify_delete_email (struct Mailbox *m, struct Email *e)
 Inform IMAP that an Email has been deleted. More...
 
void imap_expunge_mailbox (struct Mailbox *m, bool resort)
 Purge messages from the server. More...
 
int imap_open_connection (struct ImapAccountData *adata)
 Open an IMAP connection. More...
 
void imap_close_connection (struct ImapAccountData *adata)
 Close an IMAP connection. More...
 
bool imap_has_flag (struct ListHead *flag_list, const char *flag)
 Does the flag exist in the list. More...
 
static int compare_uid (const void *a, const void *b)
 Compare two Emails by UID - Implements sort_t -. More...
 
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. More...
 
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. More...
 
enum MxStatus imap_check_mailbox (struct Mailbox *m, bool force)
 Use the NOOP or IDLE command to poll for new mail. More...
 
static int imap_status (struct ImapAccountData *adata, struct ImapMboxData *mdata, bool queue)
 Refresh the number of total and new messages. More...
 
static enum MxStatus imap_mbox_check_stats (struct Mailbox *m, uint8_t flags)
 Check the Mailbox statistics - Implements MxOps::mbox_check_stats() -. 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 MxStatus imap_sync_mailbox (struct Mailbox *m, bool expunge, bool close)
 Sync all the changes to the server. More...
 
static bool imap_ac_owns_path (struct Account *a, const char *path)
 Check whether an Account owns a Mailbox path - Implements MxOps::ac_owns_path() -. More...
 
static bool imap_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -. More...
 
static void imap_mbox_select (struct Mailbox *m)
 Select a Mailbox. More...
 
int imap_login (struct ImapAccountData *adata)
 Open an IMAP connection. More...
 
static enum MxOpenReturns imap_mbox_open (struct Mailbox *m)
 Open a mailbox - Implements MxOps::mbox_open() -. More...
 
static bool imap_mbox_open_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a Mailbox for appending - Implements MxOps::mbox_open_append() -. More...
 
static enum MxStatus imap_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -. More...
 
static enum MxStatus imap_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -. More...
 
static bool imap_msg_open_new (struct Mailbox *m, struct Message *msg, const struct Email *e)
 Open a new message in a Mailbox - Implements MxOps::msg_open_new() -. More...
 
static int imap_tags_edit (struct Mailbox *m, const char *tags, struct Buffer *buf)
 Prompt and validate new messages tags - Implements MxOps::tags_edit() -. More...
 
static int imap_tags_commit (struct Mailbox *m, struct Email *e, const char *buf)
 Save the tags to a message - Implements MxOps::tags_commit() -. 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...
 
int imap_expand_path (struct Buffer *buf)
 Buffer wrapper around imap_path_canon() More...
 
static int imap_path_pretty (char *buf, size_t buflen, const char *folder)
 Abbreviate a Mailbox path - Implements MxOps::path_pretty() -. More...
 
static int imap_path_parent (char *buf, size_t buflen)
 Find the parent of a Mailbox path - Implements MxOps::path_parent() -. More...
 
static int imap_path_is_empty (const char *path)
 Is the mailbox empty - Implements MxOps::path_is_empty() -. More...
 

Variables

static const struct Command imap_commands []
 
struct MxOps MxImapOps
 IMAP Mailbox - Implements MxOps -. More...
 

Detailed Description

IMAP network mailbox.

Authors
  • Michael R. Elkins
  • Brandon Long
  • 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 imap.c.

Function Documentation

◆ imap_init()

void imap_init ( void  )

Setup feature commands.

Definition at line 84 of file imap.c.

85{
87}
static const struct Command imap_commands[]
Definition: imap.c:74
#define COMMANDS_REGISTER(cmds)
Definition: mutt_commands.h:47
+ Here is the caller graph for this function:

◆ check_capabilities()

static int check_capabilities ( struct ImapAccountData adata)
static

Make sure we can log in to this server.

Parameters
adataImap Account data
Return values
0Success
-1Failure

Definition at line 95 of file imap.c.

96{
97 if (imap_exec(adata, "CAPABILITY", IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
98 {
99 imap_error("check_capabilities", adata->buf);
100 return -1;
101 }
102
103 if (!((adata->capabilities & IMAP_CAP_IMAP4) || (adata->capabilities & IMAP_CAP_IMAP4REV1)))
104 {
105 mutt_error(_("This IMAP server is ancient. NeoMutt does not work with it."));
106 return -1;
107 }
108
109 return 0;
110}
#define mutt_error(...)
Definition: logging.h:87
int imap_exec(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Execute a command and wait for the response from the server.
Definition: command.c:1247
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: private.h:73
#define IMAP_CAP_IMAP4
Server supports IMAP4.
Definition: private.h:123
#define IMAP_CAP_IMAP4REV1
Server supports IMAP4rev1.
Definition: private.h:124
@ IMAP_EXEC_SUCCESS
Imap command executed or queued successfully.
Definition: private.h:84
void imap_error(const char *where, const char *msg)
Show an error and abort.
Definition: util.c:663
#define _(a)
Definition: message.h:28
ImapCapFlags capabilities
Capability flags.
Definition: adata.h:55
char * buf
Definition: adata.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_flags()

static char * get_flags ( struct ListHead *  hflags,
char *  s 
)
static

Make a simple list out of a FLAGS response.

Parameters
hflagsList to store flags
sString containing flags
Return values
ptrEnd of the flags
NULLFailure

return stream following FLAGS response

Definition at line 121 of file imap.c.

122{
123 /* sanity-check string */
124 const size_t plen = mutt_istr_startswith(s, "FLAGS");
125 if (plen == 0)
126 {
127 mutt_debug(LL_DEBUG1, "not a FLAGS response: %s\n", s);
128 return NULL;
129 }
130 s += plen;
131 SKIPWS(s);
132 if (*s != '(')
133 {
134 mutt_debug(LL_DEBUG1, "bogus FLAGS response: %s\n", s);
135 return NULL;
136 }
137
138 /* update caller's flags handle */
139 while (*s && (*s != ')'))
140 {
141 s++;
142 SKIPWS(s);
143 const char *flag_word = s;
144 while (*s && (*s != ')') && !IS_SPACE(*s))
145 s++;
146 const char ctmp = *s;
147 *s = '\0';
148 if (*flag_word)
149 mutt_list_insert_tail(hflags, mutt_str_dup(flag_word));
150 *s = ctmp;
151 }
152
153 /* note bad flags response */
154 if (*s != ')')
155 {
156 mutt_debug(LL_DEBUG1, "Unterminated FLAGS response: %s\n", s);
157 mutt_list_free(hflags);
158
159 return NULL;
160 }
161
162 s++;
163
164 return s;
165}
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
#define IS_SPACE(ch)
Definition: string2.h:38
#define SKIPWS(ch)
Definition: string2.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_flag()

static void set_flag ( struct Mailbox m,
AclFlags  aclflag,
bool  flag,
const char *  str,
char *  flags,
size_t  flsize 
)
static

Append str to flags if we currently have permission according to aclflag.

Parameters
[in]mSelected Imap Mailbox
[in]aclflagPermissions, see AclFlags
[in]flagDoes the email have the flag set?
[in]strServer flag name
[out]flagsBuffer for server command
[in]flsizeLength of buffer

Definition at line 176 of file imap.c.

178{
179 if (m->rights & aclflag)
180 if (flag && imap_has_flag(&imap_mdata_get(m)->flags, str))
181 mutt_str_cat(flags, flsize, str);
182}
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: mdata.c:60
bool imap_has_flag(struct ListHead *flag_list, const char *flag)
Does the flag exist in the list.
Definition: imap.c:878
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:265
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:117
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ make_msg_set()

static int make_msg_set ( struct Mailbox m,
struct Buffer buf,
enum MessageType  flag,
bool  changed,
bool  invert,
int *  pos 
)
static

Make a message set.

Parameters
[in]mSelected Imap Mailbox
[in]bufBuffer to store message set
[in]flagFlags to match, e.g. MUTT_DELETED
[in]changedMatched messages that have been altered
[in]invertFlag matches should be inverted
[out]posCursor used for multiple calls to this function
Return values
numMessages in the set
Note
Headers must be in SORT_ORDER. See imap_exec_msgset() for args. Pos is an opaque pointer a la strtok(). It should be 0 at first call.

Definition at line 197 of file imap.c.

199{
200 int count = 0; /* number of messages in message set */
201 unsigned int setstart = 0; /* start of current message range */
202 int n;
203 bool started = false;
204
206 if (!adata || (adata->mailbox != m))
207 return -1;
208
209 for (n = *pos; (n < m->msg_count) && (mutt_buffer_len(buf) < IMAP_MAX_CMDLEN); n++)
210 {
211 struct Email *e = m->emails[n];
212 if (!e)
213 break;
214 bool match = false; /* whether current message matches flag condition */
215 /* don't include pending expunged messages.
216 *
217 * TODO: can we unset active in cmd_parse_expunge() and
218 * cmd_parse_vanished() instead of checking for index != INT_MAX. */
219 if (e->active && (e->index != INT_MAX))
220 {
221 switch (flag)
222 {
223 case MUTT_DELETED:
224 if (e->deleted != imap_edata_get(e)->deleted)
225 match = invert ^ e->deleted;
226 break;
227 case MUTT_FLAG:
228 if (e->flagged != imap_edata_get(e)->flagged)
229 match = invert ^ e->flagged;
230 break;
231 case MUTT_OLD:
232 if (e->old != imap_edata_get(e)->old)
233 match = invert ^ e->old;
234 break;
235 case MUTT_READ:
236 if (e->read != imap_edata_get(e)->read)
237 match = invert ^ e->read;
238 break;
239 case MUTT_REPLIED:
240 if (e->replied != imap_edata_get(e)->replied)
241 match = invert ^ e->replied;
242 break;
243 case MUTT_TAG:
244 if (e->tagged)
245 match = true;
246 break;
247 case MUTT_TRASH:
248 if (e->deleted && !e->purge)
249 match = true;
250 break;
251 default:
252 break;
253 }
254 }
255
256 if (match && (!changed || e->changed))
257 {
258 count++;
259 if (setstart == 0)
260 {
261 setstart = imap_edata_get(e)->uid;
262 if (started)
263 {
264 mutt_buffer_add_printf(buf, ",%u", imap_edata_get(e)->uid);
265 }
266 else
267 {
268 mutt_buffer_add_printf(buf, "%u", imap_edata_get(e)->uid);
269 started = true;
270 }
271 }
272 /* tie up if the last message also matches */
273 else if (n == (m->msg_count - 1))
274 mutt_buffer_add_printf(buf, ":%u", imap_edata_get(e)->uid);
275 }
276 /* End current set if message doesn't match. */
277 else if (setstart)
278 {
279 if (imap_edata_get(m->emails[n - 1])->uid > setstart)
280 mutt_buffer_add_printf(buf, ":%u", imap_edata_get(m->emails[n - 1])->uid);
281 setstart = 0;
282 }
283 }
284
285 *pos = n;
286
287 return count;
288}
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:371
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:211
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: adata.c:89
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:65
#define IMAP_MAX_CMDLEN
Maximum length of command lines before they must be split (for lazy servers)
Definition: private.h:62
@ MUTT_TRASH
Trashed messages.
Definition: mutt.h:105
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:93
@ MUTT_OLD
Old messages.
Definition: mutt.h:91
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:100
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:99
@ MUTT_DELETED
Deleted messages.
Definition: mutt.h:98
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:92
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
bool purge
Skip trash folder when deleting.
Definition: email.h:77
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 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
int index
The absolute (unsorted) message number.
Definition: email.h:110
bool tagged
Email is tagged.
Definition: email.h:107
IMAP-specific Account data -.
Definition: adata.h:40
unsigned int uid
32-bit Message UID
Definition: edata.h:44
bool deleted
Email has been deleted.
Definition: edata.h:38
bool old
Email has been seen.
Definition: edata.h:37
bool read
Email has been read.
Definition: edata.h:36
bool flagged
Email has been flagged.
Definition: edata.h:39
bool replied
Email has been replied to.
Definition: edata.h:40
int msg_count
Total number of messages.
Definition: mailbox.h:88
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ compare_flags_for_copy()

static bool compare_flags_for_copy ( struct Email e)
static

Compare local flags against the server.

Parameters
eEmail
Return values
trueFlags have changed
falseFlags match cached server flags

The comparison of flags EXCLUDES the deleted flag.

Definition at line 298 of file imap.c.

299{
300 struct ImapEmailData *edata = e->edata;
301
302 if (e->read != edata->read)
303 return true;
304 if (e->old != edata->old)
305 return true;
306 if (e->flagged != edata->flagged)
307 return true;
308 if (e->replied != edata->replied)
309 return true;
310
311 return false;
312}
void * edata
Driver-specific data.
Definition: email.h:72
IMAP-specific Email data -.
Definition: edata.h:34
+ Here is the caller graph for this function:

◆ sync_helper()

static int sync_helper ( struct Mailbox m,
AclFlags  right,
enum MessageType  flag,
const char *  name 
)
static

Sync flag changes to the server.

Parameters
mSelected Imap Mailbox
rightACL, see AclFlags
flagNeoMutt flag, e.g. MUTT_DELETED
nameName of server flag
Return values
>=0Success, number of messages
-1Failure

Definition at line 323 of file imap.c.

325{
326 int count = 0;
327 int rc;
328 char buf[1024] = { 0 };
329
330 if (!m)
331 return -1;
332
333 if ((m->rights & right) == 0)
334 return 0;
335
336 if ((right == MUTT_ACL_WRITE) && !imap_has_flag(&imap_mdata_get(m)->flags, name))
337 return 0;
338
339 snprintf(buf, sizeof(buf), "+FLAGS.SILENT (%s)", name);
340 rc = imap_exec_msgset(m, "UID STORE", buf, flag, true, false);
341 if (rc < 0)
342 return rc;
343 count += rc;
344
345 buf[0] = '-';
346 rc = imap_exec_msgset(m, "UID STORE", buf, flag, true, true);
347 if (rc < 0)
348 return rc;
349 count += rc;
350
351 return count;
352}
int imap_exec_msgset(struct Mailbox *m, const char *pre, const char *post, enum MessageType flag, bool changed, bool invert)
Prepare commands for all messages matching conditions.
Definition: imap.c:930
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ longest_common_prefix()

static size_t longest_common_prefix ( char *  dest,
const char *  src,
size_t  start,
size_t  dlen 
)
static

Find longest prefix common to two strings.

Parameters
destDestination buffer
srcSource buffer
startStarting offset into string
dlenDestination buffer length
Return values
numLength of the common string

Trim dest to the length of the longest prefix it shares with src.

Definition at line 364 of file imap.c.

365{
366 size_t pos = start;
367
368 while ((pos < dlen) && dest[pos] && (dest[pos] == src[pos]))
369 pos++;
370 dest[pos] = '\0';
371
372 return pos;
373}
+ Here is the caller graph for this function:

◆ complete_hosts()

static int complete_hosts ( char *  buf,
size_t  buflen 
)
static

Look for completion matches for mailboxes.

Parameters
bufPartial mailbox name to complete
buflenLength of buffer
Return values
0Success
-1Failure

look for IMAP URLs to complete from defined mailboxes. Could be extended to complete over open connections and account/folder hooks too.

Definition at line 385 of file imap.c.

386{
387 // struct Connection *conn = NULL;
388 int rc = -1;
389 size_t matchlen;
390
391 matchlen = mutt_str_len(buf);
392 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
394 struct MailboxNode *np = NULL;
395 STAILQ_FOREACH(np, &ml, entries)
396 {
398 continue;
399
400 if (rc)
401 {
402 mutt_str_copy(buf, mailbox_path(np->mailbox), buflen);
403 rc = 0;
404 }
405 else
406 longest_common_prefix(buf, mailbox_path(np->mailbox), matchlen, buflen);
407 }
409
410#if 0
411 TAILQ_FOREACH(conn, mutt_socket_head(), entries)
412 {
413 struct Url url = { 0 };
414 char urlstr[1024] = { 0 };
415
416 if (conn->account.type != MUTT_ACCT_TYPE_IMAP)
417 continue;
418
419 mutt_account_tourl(&conn->account, &url);
420 /* FIXME: how to handle multiple users on the same host? */
421 url.user = NULL;
422 url.path = NULL;
423 url_tostring(&url, urlstr, sizeof(urlstr), U_NO_FLAGS);
424 if (mutt_strn_equal(buf, urlstr, matchlen))
425 {
426 if (rc)
427 {
428 mutt_str_copy(buf, urlstr, buflen);
429 rc = 0;
430 }
431 else
432 longest_common_prefix(buf, urlstr, matchlen, buflen);
433 }
434 }
435#endif
436
437 return rc;
438}
static size_t longest_common_prefix(char *dest, const char *src, size_t start, size_t dlen)
Find longest prefix common to two strings.
Definition: imap.c:364
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
@ MUTT_MAILBOX_ANY
Match any Mailbox type.
Definition: mailbox.h:42
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:496
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:652
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:79
@ MUTT_ACCT_TYPE_IMAP
Imap Account.
Definition: mutt_account.h:37
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 TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
List of Mailboxes.
Definition: mailbox.h:153
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:154
Container for Accounts, Notifications.
Definition: neomutt.h:37
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * user
Username.
Definition: url.h:71
char * path
Path.
Definition: url.h:75
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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_create_mailbox()

int imap_create_mailbox ( struct ImapAccountData adata,
const char *  mailbox 
)

Create a new mailbox.

Parameters
adataImap Account data
mailboxMailbox to create
Return values
0Success
-1Failure

Definition at line 447 of file imap.c.

448{
449 char buf[2048], mbox[1024];
450
451 imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), mailbox);
452 snprintf(buf, sizeof(buf), "CREATE %s", mbox);
453
455 {
456 mutt_error(_("CREATE failed: %s"), imap_cmd_trailer(adata));
457 return -1;
458 }
459
460 return 0;
461}
const char * imap_cmd_trailer(struct ImapAccountData *adata)
Extra information after tagged command response if any.
Definition: command.c:1210
void imap_munge_mbox_name(bool unicode, char *dest, size_t dlen, const char *src)
Quote awkward characters in a mailbox name.
Definition: util.c:911
bool unicode
If true, we can send UTF-8, and the server will use UTF8 rather than mUTF7.
Definition: adata.h:62
+ 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 473 of file imap.c.

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

◆ imap_rename_mailbox()

int imap_rename_mailbox ( struct ImapAccountData adata,
char *  oldname,
const char *  newname 
)

Rename a mailbox.

Parameters
adataImap Account data
oldnameExisting mailbox
newnameNew name for mailbox
Return values
0Success
-1Failure

Definition at line 488 of file imap.c.

489{
490 char oldmbox[1024] = { 0 };
491 char newmbox[1024] = { 0 };
492 int rc = 0;
493
494 imap_munge_mbox_name(adata->unicode, oldmbox, sizeof(oldmbox), oldname);
495 imap_munge_mbox_name(adata->unicode, newmbox, sizeof(newmbox), newname);
496
497 struct Buffer *buf = mutt_buffer_pool_get();
498 mutt_buffer_printf(buf, "RENAME %s %s", oldmbox, newmbox);
499
501 rc = -1;
502
504
505 return rc;
506}
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
String manipulation buffer.
Definition: buffer.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_delete_mailbox()

int imap_delete_mailbox ( struct Mailbox m,
char *  path 
)

Delete a mailbox.

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

Definition at line 515 of file imap.c.

516{
517 char buf[PATH_MAX + 7];
518 char mbox[PATH_MAX] = { 0 };
519 struct Url *url = url_parse(path);
520
522 imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), url->path);
523 url_free(&url);
524 snprintf(buf, sizeof(buf), "DELETE %s", mbox);
526 return -1;
527
528 return 0;
529}
#define PATH_MAX
Definition: mutt.h:40
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:127
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_logout()

static void imap_logout ( struct ImapAccountData adata)
static

Gracefully log out of server.

Parameters
adataImap Account data

Definition at line 535 of file imap.c.

536{
537 /* we set status here to let imap_handle_untagged know we _expect_ to
538 * receive a bye response (so it doesn't freak out and close the conn) */
539 if (adata->state == IMAP_DISCONNECTED)
540 {
541 return;
542 }
543
544 adata->status = IMAP_BYE;
545 imap_cmd_start(adata, "LOGOUT");
546 const short c_imap_poll_timeout = cs_subset_number(NeoMutt->sub, "imap_poll_timeout");
547 if ((c_imap_poll_timeout <= 0) ||
548 (mutt_socket_poll(adata->conn, c_imap_poll_timeout) != 0))
549 {
550 while (imap_cmd_step(adata) == IMAP_RES_CONTINUE)
551 ; // do nothing
552 }
553 mutt_socket_close(adata->conn);
554 adata->state = IMAP_DISCONNECTED;
555}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1062
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
@ IMAP_DISCONNECTED
Disconnected from server.
Definition: private.h:107
@ IMAP_BYE
Logged out from server.
Definition: private.h:98
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:57
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:98
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:193
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: adata.h:44
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: adata.h:45
struct Connection * conn
Connection to IMAP server.
Definition: adata.h:41
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_logout_all()

void imap_logout_all ( void  )

Close all open connections.

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

Definition at line 562 of file imap.c.

563{
564 struct Account *np = NULL;
565 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
566 {
567 if (np->type != MUTT_IMAP)
568 continue;
569
570 struct ImapAccountData *adata = np->adata;
571 if (!adata)
572 continue;
573
574 struct Connection *conn = adata->conn;
575 if (!conn || (conn->fd < 0))
576 continue;
577
578 mutt_message(_("Closing connection to %s..."), conn->account.host);
579 imap_logout(np->adata);
581 }
582}
#define mutt_message(...)
Definition: logging.h:86
static void imap_logout(struct ImapAccountData *adata)
Gracefully log out of server.
Definition: imap.c:535
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
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
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
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_read_literal()

int imap_read_literal ( FILE *  fp,
struct ImapAccountData adata,
unsigned long  bytes,
struct Progress *  progress 
)

Read bytes bytes from server into file.

Parameters
fpFile handle for email file
adataImap Account data
bytesNumber of bytes to read
progressProgress bar
Return values
0Success
-1Failure

Not explicitly buffered, relies on FILE buffering.

Note
Strips \r from \r\n. Apparently even literals use \r\n-terminated strings ?!

Definition at line 598 of file imap.c.

600{
601 char c;
602 bool r = false;
603 struct Buffer buf = { 0 }; // Do not allocate, maybe it won't be used
604
605 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
606 if (c_debug_level >= IMAP_LOG_LTRL)
607 mutt_buffer_alloc(&buf, bytes + 1);
608
609 mutt_debug(LL_DEBUG2, "reading %lu bytes\n", bytes);
610
611 for (unsigned long pos = 0; pos < bytes; pos++)
612 {
613 if (mutt_socket_readchar(adata->conn, &c) != 1)
614 {
615 mutt_debug(LL_DEBUG1, "error during read, %lu bytes read\n", pos);
616 adata->status = IMAP_FATAL;
617
619 return -1;
620 }
621
622 if (r && (c != '\n'))
623 fputc('\r', fp);
624
625 if (c == '\r')
626 {
627 r = true;
628 continue;
629 }
630 else
631 r = false;
632
633 fputc(c, fp);
634
635 if (progress && !(pos % 1024))
636 progress_update(progress, pos, -1);
637 if (c_debug_level >= IMAP_LOG_LTRL)
638 mutt_buffer_addch(&buf, c);
639 }
640
641 if (c_debug_level >= IMAP_LOG_LTRL)
642 {
643 mutt_debug(IMAP_LOG_LTRL, "\n%s", buf.data);
645 }
646 return 0;
647}
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:275
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
#define IMAP_LOG_LTRL
Definition: private.h:50
@ IMAP_FATAL
Unrecoverable error occurred.
Definition: private.h:97
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
int mutt_socket_readchar(struct Connection *conn, char *c)
Simple read buffering to speed things up.
Definition: socket.c:211
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_notify_delete_email()

void imap_notify_delete_email ( struct Mailbox m,
struct Email e 
)

Inform IMAP that an Email has been deleted.

Parameters
mMailbox
eEmail

Definition at line 654 of file imap.c.

655{
656 struct ImapMboxData *mdata = imap_mdata_get(m);
658
659 if (!mdata || !edata)
660 return;
661
662 imap_msn_remove(&mdata->msn, edata->msn - 1);
663 edata->msn = 0;
664}
void imap_msn_remove(struct MSN *msn, size_t idx)
Remove an entry from the cache.
Definition: msn.c:113
IMAP-specific Mailbox data -.
Definition: mdata.h:39
void * mdata
Driver specific data.
Definition: mailbox.h:132
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_expunge_mailbox()

void imap_expunge_mailbox ( struct Mailbox m,
bool  resort 
)

Purge messages from the server.

Parameters
mMailbox
resortTrigger a resort?

Purge IMAP portion of expunged messages from the context. Must not be done while something has a handle on any headers (eg inside pager or editor). That is, check IMAP_REOPEN_ALLOW.

Definition at line 675 of file imap.c.

676{
678 struct ImapMboxData *mdata = imap_mdata_get(m);
679 if (!adata || !mdata)
680 return;
681
682 struct Email *e = NULL;
683
684#ifdef USE_HCACHE
685 imap_hcache_open(adata, mdata);
686#endif
687
688 for (int i = 0; i < m->msg_count; i++)
689 {
690 e = m->emails[i];
691 if (!e)
692 break;
693
694 if (e->index == INT_MAX)
695 {
696 mutt_debug(LL_DEBUG2, "Expunging message UID %u\n", imap_edata_get(e)->uid);
697
698 e->deleted = true;
699
700 imap_cache_del(m, e);
701#ifdef USE_HCACHE
702 imap_hcache_del(mdata, imap_edata_get(e)->uid);
703#endif
704
705 mutt_hash_int_delete(mdata->uid_hash, imap_edata_get(e)->uid, e);
706
707 imap_edata_free((void **) &e->edata);
708 }
709 else
710 {
711 /* NeoMutt has several places where it turns off e->active as a
712 * hack. For example to avoid FLAG updates, or to exclude from
713 * imap_exec_msgset.
714 *
715 * Unfortunately, when a reopen is allowed and the IMAP_EXPUNGE_PENDING
716 * flag becomes set (e.g. a flag update to a modified header),
717 * this function will be called by imap_cmd_finish().
718 *
719 * The ctx_update_tables() will free and remove these "inactive" headers,
720 * despite that an EXPUNGE was not received for them.
721 * This would result in memory leaks and segfaults due to dangling
722 * pointers in the msn_index and uid_hash.
723 *
724 * So this is another hack to work around the hacks. We don't want to
725 * remove the messages, so make sure active is on. */
726 e->active = true;
727 }
728 }
729
730#ifdef USE_HCACHE
731 imap_hcache_close(mdata);
732#endif
733
735 if (resort)
736 {
738 }
739}
void mutt_hash_int_delete(struct HashTable *table, unsigned int intkey, const void *data)
Remove an element from a Hash Table.
Definition: hash.c:444
void imap_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:39
int imap_cache_del(struct Mailbox *m, struct Email *e)
Delete an email from the body cache.
Definition: message.c:1857
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition: util.c:339
int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
Delete an item from the header cache.
Definition: util.c:398
void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata)
Open a header cache.
Definition: util.c:297
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:222
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:177
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:178
struct HashTable * uid_hash
Definition: mdata.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_open_connection()

int imap_open_connection ( struct ImapAccountData adata)

Open an IMAP connection.

Parameters
adataImap Account data
Return values
0Success
-1Failure

Definition at line 747 of file imap.c.

748{
749 if (mutt_socket_open(adata->conn) < 0)
750 return -1;
751
752 adata->state = IMAP_CONNECTED;
753
754 if (imap_cmd_step(adata) != IMAP_RES_OK)
755 {
757 return -1;
758 }
759
760 if (mutt_istr_startswith(adata->buf, "* OK"))
761 {
762 if (!mutt_istr_startswith(adata->buf, "* OK [CAPABILITY") && check_capabilities(adata))
763 {
764 goto bail;
765 }
766#ifdef USE_SSL
767 /* Attempt STARTTLS if available and desired. */
768 const bool c_ssl_force_tls = cs_subset_bool(NeoMutt->sub, "ssl_force_tls");
769 if ((adata->conn->ssf == 0) &&
770 (c_ssl_force_tls || (adata->capabilities & IMAP_CAP_STARTTLS)))
771 {
772 enum QuadOption ans;
773
774 const enum QuadOption c_ssl_starttls = cs_subset_quad(NeoMutt->sub, "ssl_starttls");
775 if (c_ssl_force_tls)
776 ans = MUTT_YES;
777 else if ((ans = query_quadoption(c_ssl_starttls, _("Secure connection with TLS?"))) == MUTT_ABORT)
778 {
779 goto bail;
780 }
781 if (ans == MUTT_YES)
782 {
783 enum ImapExecResult rc = imap_exec(adata, "STARTTLS", IMAP_CMD_SINGLE);
784 // Clear any data after the STARTTLS acknowledgement
785 mutt_socket_empty(adata->conn);
786
787 if (rc == IMAP_EXEC_FATAL)
788 goto bail;
789 if (rc != IMAP_EXEC_ERROR)
790 {
791 if (mutt_ssl_starttls(adata->conn))
792 {
793 mutt_error(_("Could not negotiate TLS connection"));
794 goto bail;
795 }
796 else
797 {
798 /* RFC2595 demands we recheck CAPABILITY after TLS completes. */
799 if (imap_exec(adata, "CAPABILITY", IMAP_CMD_NO_FLAGS))
800 goto bail;
801 }
802 }
803 }
804 }
805
806 if (c_ssl_force_tls && (adata->conn->ssf == 0))
807 {
808 mutt_error(_("Encrypted connection unavailable"));
809 goto bail;
810 }
811#endif
812 }
813 else if (mutt_istr_startswith(adata->buf, "* PREAUTH"))
814 {
815#ifdef USE_SSL
816 /* Unless using a secure $tunnel, an unencrypted PREAUTH response may be a
817 * MITM attack. The only way to stop "STARTTLS" MITM attacks is via
818 * $ssl_force_tls: an attacker can easily spoof "* OK" and strip the
819 * STARTTLS capability. So consult $ssl_force_tls, not $ssl_starttls, to
820 * decide whether to abort. Note that if using $tunnel and
821 * $tunnel_is_secure, adata->conn->ssf will be set to 1. */
822 const bool c_ssl_force_tls = cs_subset_bool(NeoMutt->sub, "ssl_force_tls");
823 if ((adata->conn->ssf == 0) && c_ssl_force_tls)
824 {
825 mutt_error(_("Encrypted connection unavailable"));
826 goto bail;
827 }
828#endif
829
830 adata->state = IMAP_AUTHENTICATED;
831 if (check_capabilities(adata) != 0)
832 goto bail;
833 FREE(&adata->capstr);
834 }
835 else
836 {
837 imap_error("imap_open_connection()", adata->buf);
838 goto bail;
839 }
840
841 return 0;
842
843bail:
845 FREE(&adata->capstr);
846 return -1;
847}
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
int mutt_ssl_starttls(struct Connection *conn)
Negotiate TLS over an already opened connection.
Definition: gnutls.c:1143
@ IMAP_AUTHENTICATED
Connection is authenticated.
Definition: private.h:109
@ IMAP_CONNECTED
Connected to server.
Definition: private.h:108
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:56
#define IMAP_CAP_STARTTLS
RFC2595: STARTTLS.
Definition: private.h:133
ImapExecResult
Imap_exec return code.
Definition: private.h:83
@ IMAP_EXEC_ERROR
Imap command failure.
Definition: private.h:85
@ IMAP_EXEC_FATAL
Imap connection failure.
Definition: private.h:86
#define IMAP_CMD_SINGLE
Run a single command.
Definition: private.h:77
void imap_close_connection(struct ImapAccountData *adata)
Close an IMAP connection.
Definition: imap.c:853
static int check_capabilities(struct ImapAccountData *adata)
Make sure we can log in to this server.
Definition: imap.c:95
#define FREE(x)
Definition: memory.h:43
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
void mutt_socket_empty(struct Connection *conn)
Clear out any queued data.
Definition: socket.c:314
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
Definition: socket.c:77
unsigned int ssf
Security strength factor, in bits (see notes)
Definition: connection.h:51
char * capstr
Capability string from the server.
Definition: adata.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_close_connection()

void imap_close_connection ( struct ImapAccountData adata)

Close an IMAP connection.

Parameters
adataImap Account data

Definition at line 853 of file imap.c.

854{
855 if (adata->state != IMAP_DISCONNECTED)
856 {
857 mutt_socket_close(adata->conn);
858 adata->state = IMAP_DISCONNECTED;
859 }
860 adata->seqno = 0;
861 adata->nextcmd = 0;
862 adata->lastcmd = 0;
863 adata->status = 0;
864 memset(adata->cmds, 0, sizeof(struct ImapCommand) * adata->cmdslots);
865}
int lastcmd
Last command in the queue.
Definition: adata.h:72
int nextcmd
Next command to be sent.
Definition: adata.h:71
struct ImapCommand * cmds
Queue of commands for the server.
Definition: adata.h:69
int cmdslots
Size of the command queue.
Definition: adata.h:70
unsigned int seqno
tag sequence number, e.g. '{seqid}0001'
Definition: adata.h:57
IMAP command structure.
Definition: private.h:161
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_has_flag()

bool imap_has_flag ( struct ListHead *  flag_list,
const char *  flag 
)

Does the flag exist in the list.

Parameters
flag_listList of server flags
flagFlag to find
Return values
trueFlag exists

Do a caseless comparison of the flag against a flag list, return true if found or flag list has '*'. Note that "flag" might contain additional whitespace at the end, so we really need to compare up to the length of each element in "flag_list".

Definition at line 878 of file imap.c.

879{
880 if (STAILQ_EMPTY(flag_list))
881 return false;
882
883 const size_t flaglen = mutt_str_len(flag);
884 struct ListNode *np = NULL;
885 STAILQ_FOREACH(np, flag_list, entries)
886 {
887 const size_t nplen = strlen(np->data);
888 if ((flaglen >= nplen) && ((flag[nplen] == '\0') || (flag[nplen] == ' ')) &&
889 mutt_istrn_equal(np->data, flag, nplen))
890 {
891 return true;
892 }
893
894 if (mutt_str_equal(np->data, "\\*"))
895 return true;
896 }
897
898 return false;
899}
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:524
#define STAILQ_EMPTY(head)
Definition: queue.h:348
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_exec_msgset()

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.

Parameters
mSelected Imap Mailbox
preprefix commands
postpostfix commands
flagflag type on which to filter, e.g. MUTT_REPLIED
changedinclude only changed messages in message set
invertinvert sense of flag, eg MUTT_READ matches unread messages
Return values
numMatched messages
-1Failure

pre/post: commands are of the form "%s %s %s %s", tag, pre, message set, post Prepares commands for all messages matching conditions (must be flushed with imap_exec)

Definition at line 930 of file imap.c.

932{
934 if (!adata || (adata->mailbox != m))
935 return -1;
936
937 struct Email **emails = NULL;
938 int pos;
939 int rc;
940 int count = 0;
941
942 struct Buffer cmd = mutt_buffer_make(0);
943
944 /* We make a copy of the headers just in case resorting doesn't give
945 exactly the original order (duplicate messages?), because other parts of
946 the mv are tied to the header order. This may be overkill. */
947 const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
948 if (c_sort != SORT_ORDER)
949 {
950 emails = m->emails;
951 // We overcommit here, just in case new mail arrives whilst we're sync-ing
952 m->emails = mutt_mem_malloc(m->email_max * sizeof(struct Email *));
953 memcpy(m->emails, emails, m->email_max * sizeof(struct Email *));
954
956 qsort(m->emails, m->msg_count, sizeof(struct Email *), compare_uid);
957 }
958
959 pos = 0;
960
961 do
962 {
963 mutt_buffer_reset(&cmd);
964 mutt_buffer_add_printf(&cmd, "%s ", pre);
965 rc = make_msg_set(m, &cmd, flag, changed, invert, &pos);
966 if (rc > 0)
967 {
968 mutt_buffer_add_printf(&cmd, " %s", post);
970 {
971 rc = -1;
972 goto out;
973 }
974 count += rc;
975 }
976 } while (rc > 0);
977
978 rc = count;
979
980out:
982 if (c_sort != SORT_ORDER)
983 {
984 cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
985 FREE(&m->emails);
986 m->emails = emails;
987 }
988
989 return rc;
990}
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
static int compare_uid(const void *a, const void *b)
Compare two Emails by UID - Implements sort_t -.
Definition: imap.c:904
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: private.h:75
static int make_msg_set(struct Mailbox *m, struct Buffer *buf, enum MessageType flag, bool changed, bool invert, int *pos)
Make a message set.
Definition: imap.c:197
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:48
int email_max
Number of pointers in emails.
Definition: mailbox.h:97
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_sync_message_for_copy()

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.

Parameters
[in]mMailbox
[in]eEmail
[in]cmdBuffer for the command string
[out]err_continueDid the user force a continue?
Return values
0Success
-1Failure

Update the IMAP server to reflect the flags for a single message before performing a "UID COPY".

Note
This does not sync the "deleted" flag state, because it is not desirable to propagate that flag into the copy.

Definition at line 1007 of file imap.c.

1009{
1011 if (!adata || (adata->mailbox != m))
1012 return -1;
1013
1014 char flags[1024] = { 0 };
1015 char *tags = NULL;
1016 char uid[11] = { 0 };
1017
1018 if (!compare_flags_for_copy(e))
1019 {
1020 if (e->deleted == imap_edata_get(e)->deleted)
1021 e->changed = false;
1022 return 0;
1023 }
1024
1025 snprintf(uid, sizeof(uid), "%u", imap_edata_get(e)->uid);
1026 mutt_buffer_reset(cmd);
1027 mutt_buffer_addstr(cmd, "UID STORE ");
1028 mutt_buffer_addstr(cmd, uid);
1029
1030 flags[0] = '\0';
1031
1032 set_flag(m, MUTT_ACL_SEEN, e->read, "\\Seen ", flags, sizeof(flags));
1033 set_flag(m, MUTT_ACL_WRITE, e->old, "Old ", flags, sizeof(flags));
1034 set_flag(m, MUTT_ACL_WRITE, e->flagged, "\\Flagged ", flags, sizeof(flags));
1035 set_flag(m, MUTT_ACL_WRITE, e->replied, "\\Answered ", flags, sizeof(flags));
1036 set_flag(m, MUTT_ACL_DELETE, imap_edata_get(e)->deleted, "\\Deleted ", flags,
1037 sizeof(flags));
1038
1039 if (m->rights & MUTT_ACL_WRITE)
1040 {
1041 /* restore system flags */
1042 if (imap_edata_get(e)->flags_system)
1043 mutt_str_cat(flags, sizeof(flags), imap_edata_get(e)->flags_system);
1044 /* set custom flags */
1046 if (tags)
1047 {
1048 mutt_str_cat(flags, sizeof(flags), tags);
1049 FREE(&tags);
1050 }
1051 }
1052
1054
1055 /* UW-IMAP is OK with null flags, Cyrus isn't. The only solution is to
1056 * explicitly revoke all system flags (if we have permission) */
1057 if (*flags == '\0')
1058 {
1059 set_flag(m, MUTT_ACL_SEEN, true, "\\Seen ", flags, sizeof(flags));
1060 set_flag(m, MUTT_ACL_WRITE, true, "Old ", flags, sizeof(flags));
1061 set_flag(m, MUTT_ACL_WRITE, true, "\\Flagged ", flags, sizeof(flags));
1062 set_flag(m, MUTT_ACL_WRITE, true, "\\Answered ", flags, sizeof(flags));
1063 set_flag(m, MUTT_ACL_DELETE, !imap_edata_get(e)->deleted, "\\Deleted ",
1064 flags, sizeof(flags));
1065
1066 /* erase custom flags */
1067 if ((m->rights & MUTT_ACL_WRITE) && imap_edata_get(e)->flags_remote)
1068 mutt_str_cat(flags, sizeof(flags), imap_edata_get(e)->flags_remote);
1069
1071
1072 mutt_buffer_addstr(cmd, " -FLAGS.SILENT (");
1073 }
1074 else
1075 mutt_buffer_addstr(cmd, " FLAGS.SILENT (");
1076
1077 mutt_buffer_addstr(cmd, flags);
1078 mutt_buffer_addstr(cmd, ")");
1079
1080 /* after all this it's still possible to have no flags, if you
1081 * have no ACL rights */
1082 if (*flags && (imap_exec(adata, cmd->data, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS) &&
1083 err_continue && (*err_continue != MUTT_YES))
1084 {
1085 *err_continue = imap_continue("imap_sync_message: STORE failed", adata->buf);
1086 if (*err_continue != MUTT_YES)
1087 return -1;
1088 }
1089
1090 /* server have now the updated flags */
1091 FREE(&imap_edata_get(e)->flags_remote);
1093
1094 if (e->deleted == imap_edata_get(e)->deleted)
1095 e->changed = false;
1096
1097 return 0;
1098}
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
enum QuadOption imap_continue(const char *msg, const char *resp)
Display a message and ask the user if they want to go on.
Definition: util.c:652
static void set_flag(struct Mailbox *m, AclFlags aclflag, bool flag, const char *str, char *flags, size_t flsize)
Append str to flags if we currently have permission according to aclflag.
Definition: imap.c:176
static bool compare_flags_for_copy(struct Email *e)
Compare local flags against the server.
Definition: imap.c:298
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:63
#define MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition: mailbox.h:70
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:636
struct TagList tags
For drivers that support server tagging.
Definition: email.h:70
char * flags_remote
Definition: edata.h:48
char * driver_tags_get_with_hidden(struct TagList *list)
Get tags with hiddens.
Definition: tags.c:158
+ 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 1106 of file imap.c.

1107{
1108 if (!m || !m->account)
1109 return MX_STATUS_ERROR;
1110
1112 struct ImapMboxData *mdata = imap_mdata_get(m);
1113
1114 /* overload keyboard timeout to avoid many mailbox checks in a row.
1115 * Most users don't like having to wait exactly when they press a key. */
1116 int rc = 0;
1117
1118 /* try IDLE first, unless force is set */
1119 const bool c_imap_idle = cs_subset_bool(NeoMutt->sub, "imap_idle");
1120 const short c_imap_keepalive = cs_subset_number(NeoMutt->sub, "imap_keepalive");
1121 if (!force && c_imap_idle && (adata->capabilities & IMAP_CAP_IDLE) &&
1122 ((adata->state != IMAP_IDLE) || (mutt_date_epoch() >= adata->lastread + c_imap_keepalive)))
1123 {
1124 if (imap_cmd_idle(adata) < 0)
1125 return MX_STATUS_ERROR;
1126 }
1127 if (adata->state == IMAP_IDLE)
1128 {
1129 while ((rc = mutt_socket_poll(adata->conn, 0)) > 0)
1130 {
1131 if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
1132 {
1133 mutt_debug(LL_DEBUG1, "Error reading IDLE response\n");
1134 return MX_STATUS_ERROR;
1135 }
1136 }
1137 if (rc < 0)
1138 {
1139 mutt_debug(LL_DEBUG1, "Poll failed, disabling IDLE\n");
1140 adata->capabilities &= ~IMAP_CAP_IDLE; // Clear the flag
1141 }
1142 }
1143
1144 const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
1145 if ((force || ((adata->state != IMAP_IDLE) &&
1146 (mutt_date_epoch() >= adata->lastread + c_timeout))) &&
1147 (imap_exec(adata, "NOOP", IMAP_CMD_POLL) != IMAP_EXEC_SUCCESS))
1148 {
1149 return MX_STATUS_ERROR;
1150 }
1151
1152 /* We call this even when we haven't run NOOP in case we have pending
1153 * changes to process, since we can reopen here. */
1154 imap_cmd_finish(adata);
1155
1156 enum MxStatus check = MX_STATUS_OK;
1157 if (mdata->check_status & IMAP_EXPUNGE_PENDING)
1158 check = MX_STATUS_REOPENED;
1159 else if (mdata->check_status & IMAP_NEWMAIL_PENDING)
1160 check = MX_STATUS_NEW_MAIL;
1161 else if (mdata->check_status & IMAP_FLAGS_PENDING)
1162 check = MX_STATUS_FLAGS;
1163 else if (rc < 0)
1164 check = MX_STATUS_ERROR;
1165
1166 mdata->check_status = IMAP_OPEN_NO_FLAGS;
1167
1168 return check;
1169}
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
int imap_cmd_idle(struct ImapAccountData *adata)
Enter the IDLE state.
Definition: command.c:1379
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition: command.c:1312
#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
#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
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:84
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:85
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:86
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mxapi.h:90
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:89
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:87
time_t lastread
last time we read a command for the server
Definition: adata.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_status()

static int imap_status ( struct ImapAccountData adata,
struct ImapMboxData mdata,
bool  queue 
)
static

Refresh the number of total and new messages.

Parameters
adataIMAP Account data
mdataIMAP Mailbox data
queueQueue the STATUS command
Return values
numTotal number of messages

Definition at line 1178 of file imap.c.

1179{
1180 char *uidvalidity_flag = NULL;
1181 char cmd[2048] = { 0 };
1182
1183 if (!adata || !mdata)
1184 return -1;
1185
1186 /* Don't issue STATUS on the selected mailbox, it will be NOOPed or
1187 * IDLEd elsewhere.
1188 * adata->mailbox may be NULL for connections other than the current
1189 * mailbox's. */
1190 if (adata->mailbox && (adata->mailbox->mdata == mdata))
1191 {
1192 adata->mailbox->has_new = false;
1193 return mdata->messages;
1194 }
1195
1196 if (adata->capabilities & IMAP_CAP_IMAP4REV1)
1197 uidvalidity_flag = "UIDVALIDITY";
1198 else if (adata->capabilities & IMAP_CAP_STATUS)
1199 uidvalidity_flag = "UID-VALIDITY";
1200 else
1201 {
1202 mutt_debug(LL_DEBUG2, "Server doesn't support STATUS\n");
1203 return -1;
1204 }
1205
1206 snprintf(cmd, sizeof(cmd), "STATUS %s (UIDNEXT %s UNSEEN RECENT MESSAGES)",
1207 mdata->munge_name, uidvalidity_flag);
1208
1209 int rc = imap_exec(adata, cmd, queue ? IMAP_CMD_QUEUE : IMAP_CMD_NO_FLAGS | IMAP_CMD_POLL);
1210 if (rc < 0)
1211 {
1212 mutt_debug(LL_DEBUG1, "Error queueing command\n");
1213 return rc;
1214 }
1215 return mdata->messages;
1216}
#define IMAP_CAP_STATUS
Server supports STATUS command.
Definition: private.h:125
struct Mailbox * mailbox
Current selected mailbox.
Definition: adata.h:76
unsigned int messages
Definition: mdata.h:53
char * munge_name
Munged version of the mailbox name.
Definition: mdata.h:41
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_path_status()

int imap_path_status ( const char *  path,
bool  queue 
)

Refresh the number of total and new messages.

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

Definition at line 1238 of file imap.c.

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

◆ imap_mailbox_status()

int imap_mailbox_status ( struct Mailbox m,
bool  queue 
)

Refresh the number of total and new messages.

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

Definition at line 1273 of file imap.c.

1274{
1276 struct ImapMboxData *mdata = imap_mdata_get(m);
1277 if (!adata || !mdata)
1278 return -1;
1279 return imap_status(adata, mdata, queue);
1280}
static int imap_status(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1178
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_subscribe()

int imap_subscribe ( char *  path,
bool  subscribe 
)

Subscribe to a mailbox.

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

Definition at line 1289 of file imap.c.

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

◆ imap_complete()

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

Try to complete an IMAP folder path.

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

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

Definition at line 1345 of file imap.c.

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

◆ imap_fast_trash()

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

Use server COPY command to copy deleted messages to trash.

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

Definition at line 1424 of file imap.c.

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

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

◆ imap_mbox_select()

static void imap_mbox_select ( struct Mailbox m)
static

Select a Mailbox.

Parameters
mMailbox

Definition at line 1815 of file imap.c.

1816{
1818 struct ImapMboxData *mdata = imap_mdata_get(m);
1819 if (!adata || !mdata)
1820 return;
1821
1822 const char *condstore = NULL;
1823#ifdef USE_HCACHE
1824 const bool c_imap_condstore = cs_subset_bool(NeoMutt->sub, "imap_condstore");
1825 if ((adata->capabilities & IMAP_CAP_CONDSTORE) && c_imap_condstore)
1826 condstore = " (CONDSTORE)";
1827 else
1828#endif
1829 condstore = "";
1830
1831 char buf[PATH_MAX] = { 0 };
1832 snprintf(buf, sizeof(buf), "%s %s%s", m->readonly ? "EXAMINE" : "SELECT",
1833 mdata->munge_name, condstore);
1834
1835 adata->state = IMAP_SELECTED;
1836
1837 imap_cmd_start(adata, buf);
1838}
#define IMAP_CAP_CONDSTORE
RFC7162.
Definition: private.h:138
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:115
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_login()

int imap_login ( struct ImapAccountData adata)

Open an IMAP connection.

Parameters
adataImap Account data
Return values
0Success
-1Failure

Ensure ImapAccountData is connected and logged into the imap server.

Definition at line 1848 of file imap.c.

1849{
1850 if (!adata)
1851 return -1;
1852
1853 if (adata->state == IMAP_DISCONNECTED)
1854 {
1855 mutt_buffer_reset(&adata->cmdbuf); // purge outstanding queued commands
1856 imap_open_connection(adata);
1857 }
1858 if (adata->state == IMAP_CONNECTED)
1859 {
1861 {
1862 adata->state = IMAP_AUTHENTICATED;
1863 FREE(&adata->capstr);
1864 if (adata->conn->ssf != 0)
1865 {
1866 mutt_debug(LL_DEBUG2, "Communication encrypted at %d bits\n",
1867 adata->conn->ssf);
1868 }
1869 }
1870 else
1872 }
1873 if (adata->state == IMAP_AUTHENTICATED)
1874 {
1875 /* capabilities may have changed */
1876 imap_exec(adata, "CAPABILITY", IMAP_CMD_PASS);
1877
1878#ifdef USE_ZLIB
1879 /* RFC4978 */
1880 const bool c_imap_deflate = cs_subset_bool(NeoMutt->sub, "imap_deflate");
1881 if ((adata->capabilities & IMAP_CAP_COMPRESS) && c_imap_deflate &&
1882 (imap_exec(adata, "COMPRESS DEFLATE", IMAP_CMD_PASS) == IMAP_EXEC_SUCCESS))
1883 {
1884 mutt_debug(LL_DEBUG2, "IMAP compression is enabled on connection to %s\n",
1885 adata->conn->account.host);
1886 mutt_zstrm_wrap_conn(adata->conn);
1887 }
1888#endif
1889
1890 /* enable RFC6855, if the server supports that */
1891 const bool c_imap_rfc5161 = cs_subset_bool(NeoMutt->sub, "imap_rfc5161");
1892 if (c_imap_rfc5161 && (adata->capabilities & IMAP_CAP_ENABLE))
1893 imap_exec(adata, "ENABLE UTF8=ACCEPT", IMAP_CMD_QUEUE);
1894
1895 /* enable QRESYNC. Advertising QRESYNC also means CONDSTORE
1896 * is supported (even if not advertised), so flip that bit. */
1897 if (adata->capabilities & IMAP_CAP_QRESYNC)
1898 {
1900 const bool c_imap_qresync = cs_subset_bool(NeoMutt->sub, "imap_qresync");
1901 if (c_imap_rfc5161 && c_imap_qresync)
1902 imap_exec(adata, "ENABLE QRESYNC", IMAP_CMD_QUEUE);
1903 }
1904
1905 /* get root delimiter, '/' as default */
1906 adata->delim = '/';
1907 imap_exec(adata, "LIST \"\" \"\"", IMAP_CMD_QUEUE);
1908
1909 /* we may need the root delimiter before we open a mailbox */
1910 imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1911
1912 /* select the mailbox that used to be open before disconnect */
1913 if (adata->mailbox)
1914 {
1915 imap_mbox_select(adata->mailbox);
1916 }
1917 }
1918
1919 if (adata->state < IMAP_AUTHENTICATED)
1920 return -1;
1921
1922 return 0;
1923}
@ IMAP_AUTH_SUCCESS
Authentication successful.
Definition: auth.h:39
void mutt_account_unsetpass(struct ConnAccount *cac)
Unset ConnAccount's password.
Definition: connaccount.c:177
int imap_authenticate(struct ImapAccountData *adata)
Authenticate to an IMAP server.
Definition: auth.c:110
#define IMAP_CAP_ENABLE
RFC5161.
Definition: private.h:137
#define IMAP_CMD_PASS
Command contains a password. Suppress logging.
Definition: private.h:74
#define IMAP_CAP_QRESYNC
RFC7162.
Definition: private.h:139
#define IMAP_CAP_COMPRESS
RFC4978: COMPRESS=DEFLATE.
Definition: private.h:141
int imap_open_connection(struct ImapAccountData *adata)
Open an IMAP connection.
Definition: imap.c:747
static void imap_mbox_select(struct Mailbox *m)
Select a Mailbox.
Definition: imap.c:1815
char delim
Path delimiter.
Definition: adata.h:75
struct Buffer cmdbuf
Definition: adata.h:73
void mutt_zstrm_wrap_conn(struct Connection *conn)
Wrap a compression layer around a Connection.
Definition: zstrm.c:288
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_expand_path()

int imap_expand_path ( struct Buffer buf)

Buffer wrapper around imap_path_canon()

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

Definition at line 2440 of file imap.c.

2441{
2443 return imap_path_canon(buf->data, PATH_MAX);
2444}
int imap_path_canon(char *buf, size_t buflen)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition: imap.c:2414
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ imap_commands

const struct Command imap_commands[]
static
Initial value:
= {
{ "subscribe-to", parse_subscribe_to, 0 },
{ "unsubscribe-from", parse_unsubscribe_from, 0 },
}
enum CommandResult parse_unsubscribe_from(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'unsubscribe-from' command - Implements Command::parse() -.
enum CommandResult parse_subscribe_to(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'subscribe-to' command - Implements Command::parse() -.

Definition at line 74 of file imap.c.