NeoMutt  2024-03-23-142-g2b2e76
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
imap.c File Reference

IMAP network mailbox. More...

#include "config.h"
#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.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 "editor/lib.h"
#include "history/lib.h"
#include "parse/lib.h"
#include "progress/lib.h"
#include "question/lib.h"
#include "adata.h"
#include "auth.h"
#include "commands.h"
#include "edata.h"
#include "external.h"
#include "hook.h"
#include "mdata.h"
#include "msg_set.h"
#include "msn.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.
 
static int check_capabilities (struct ImapAccountData *adata)
 Make sure we can log in to this server.
 
static char * get_flags (struct ListHead *hflags, char *s)
 Make a simple list out of a FLAGS response.
 
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.
 
static bool compare_flags_for_copy (struct Email *e)
 Compare local flags against the server.
 
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.
 
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.
 
static size_t longest_common_prefix (struct Buffer *buf, const char *src, size_t start)
 Find longest prefix common to two strings.
 
static int complete_hosts (struct Buffer *buf)
 Look for completion matches for mailboxes.
 
int imap_create_mailbox (struct ImapAccountData *adata, const char *mailbox)
 Create a new mailbox.
 
int imap_access (const char *path)
 Check permissions on an IMAP mailbox with a new connection.
 
int imap_rename_mailbox (struct ImapAccountData *adata, char *oldname, const char *newname)
 Rename a mailbox.
 
int imap_delete_mailbox (struct Mailbox *m, char *path)
 Delete a mailbox.
 
static void imap_logout (struct ImapAccountData *adata)
 Gracefully log out of server.
 
void imap_logout_all (void)
 Close all open connections.
 
int imap_read_literal (FILE *fp, struct ImapAccountData *adata, unsigned long bytes, struct Progress *progress)
 Read bytes bytes from server into file.
 
void imap_notify_delete_email (struct Mailbox *m, struct Email *e)
 Inform IMAP that an Email has been deleted.
 
void imap_expunge_mailbox (struct Mailbox *m, bool resort)
 Purge messages from the server.
 
int imap_open_connection (struct ImapAccountData *adata)
 Open an IMAP connection.
 
void imap_close_connection (struct ImapAccountData *adata)
 Close an IMAP connection.
 
bool imap_has_flag (struct ListHead *flag_list, const char *flag)
 Does the flag exist in the list.
 
static int imap_sort_email_uid (const void *a, const void *b, void *sdata)
 Compare two Emails by UID - Implements sort_t -.
 
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.
 
enum MxStatus imap_check_mailbox (struct Mailbox *m, bool force)
 Use the NOOP or IDLE command to poll for new mail.
 
static int imap_status (struct ImapAccountData *adata, struct ImapMboxData *mdata, bool queue)
 Refresh the number of total and new messages.
 
static enum MxStatus imap_mbox_check_stats (struct Mailbox *m, uint8_t flags)
 Check the Mailbox statistics - Implements MxOps::mbox_check_stats() -.
 
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 MxStatus imap_sync_mailbox (struct Mailbox *m, bool expunge, bool close)
 Sync all the changes to the server.
 
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() -.
 
static bool imap_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -.
 
static void imap_mbox_select (struct Mailbox *m)
 Select a Mailbox.
 
int imap_login (struct ImapAccountData *adata)
 Open an IMAP connection.
 
static enum MxOpenReturns imap_mbox_open (struct Mailbox *m)
 Open a mailbox - Implements MxOps::mbox_open() -.
 
static bool imap_mbox_open_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a Mailbox for appending - Implements MxOps::mbox_open_append() -.
 
static enum MxStatus imap_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -.
 
static enum MxStatus imap_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -.
 
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() -.
 
static int imap_tags_edit (struct Mailbox *m, const char *tags, struct Buffer *buf)
 Prompt and validate new messages tags - Implements MxOps::tags_edit() -.
 
static int imap_tags_commit (struct Mailbox *m, struct Email *e, const char *buf)
 Save the tags to a message - Implements MxOps::tags_commit() -.
 
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 *path)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
 
int imap_expand_path (struct Buffer *path)
 Buffer wrapper around imap_path_canon()
 
static int imap_path_is_empty (struct Buffer *path)
 Is the mailbox empty - Implements MxOps::path_is_empty() -.
 

Variables

static const struct Command ImapCommands []
 Imap Commands.
 
const struct MxOps MxImapOps
 IMAP Mailbox - Implements MxOps -.
 

Detailed Description

IMAP network mailbox.

Authors
  • Michael R. Elkins
  • Brandon Long
  • Brendan Cully
  • Richard Russon
  • Mehdi Abaakouk
  • Pietro Cerutti
  • Federico Kircheis
  • Ian Zimmerman
  • Sergey Alirzaev
  • Reto Brunner
  • Anna Figueiredo Gomes
  • Dennis Schön

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

97{
99}
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:86
#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:

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

108{
109 if (imap_exec(adata, "CAPABILITY", IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
110 {
111 imap_error("check_capabilities", adata->buf);
112 return -1;
113 }
114
115 if (!((adata->capabilities & IMAP_CAP_IMAP4) || (adata->capabilities & IMAP_CAP_IMAP4REV1)))
116 {
117 mutt_error(_("This IMAP server is ancient. NeoMutt does not work with it."));
118 return -1;
119 }
120
121 return 0;
122}
#define mutt_error(...)
Definition: logging2.h:92
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:1307
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: private.h:71
#define IMAP_CAP_IMAP4
Server supports IMAP4.
Definition: private.h:121
#define IMAP_CAP_IMAP4REV1
Server supports IMAP4rev1.
Definition: private.h:122
@ IMAP_EXEC_SUCCESS
Imap command executed or queued successfully.
Definition: private.h:82
void imap_error(const char *where, const char *msg)
Show an error and abort.
Definition: util.c:657
#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 133 of file imap.c.

134{
135 /* sanity-check string */
136 const size_t plen = mutt_istr_startswith(s, "FLAGS");
137 if (plen == 0)
138 {
139 mutt_debug(LL_DEBUG1, "not a FLAGS response: %s\n", s);
140 return NULL;
141 }
142 s += plen;
143 SKIPWS(s);
144 if (*s != '(')
145 {
146 mutt_debug(LL_DEBUG1, "bogus FLAGS response: %s\n", s);
147 return NULL;
148 }
149
150 /* update caller's flags handle */
151 while (*s && (*s != ')'))
152 {
153 s++;
154 SKIPWS(s);
155 const char *flag_word = s;
156 while (*s && (*s != ')') && !isspace(*s))
157 s++;
158 const char ctmp = *s;
159 *s = '\0';
160 if (*flag_word)
161 mutt_list_insert_tail(hflags, mutt_str_dup(flag_word));
162 *s = ctmp;
163 }
164
165 /* note bad flags response */
166 if (*s != ')')
167 {
168 mutt_debug(LL_DEBUG1, "Unterminated FLAGS response: %s\n", s);
169 mutt_list_free(hflags);
170
171 return NULL;
172 }
173
174 s++;
175
176 return s;
177}
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
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: logging2.h:43
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:242
#define SKIPWS(ch)
Definition: string2.h:45
+ 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 188 of file imap.c.

190{
191 if (m->rights & aclflag)
192 if (flag && imap_has_flag(&imap_mdata_get(m)->flags, str))
193 mutt_str_cat(flags, flsize, str);
194}
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:875
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:268
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:119
+ 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 204 of file imap.c.

205{
206 struct ImapEmailData *edata = e->edata;
207
208 if (e->read != edata->read)
209 return true;
210 if (e->old != edata->old)
211 return true;
212 if (e->flagged != edata->flagged)
213 return true;
214 if (e->replied != edata->replied)
215 return true;
216
217 return false;
218}
bool read
Email is read.
Definition: email.h:50
void * edata
Driver-specific data.
Definition: email.h:74
bool old
Email is seen, but unread.
Definition: email.h:49
bool flagged
Marked important?
Definition: email.h:47
bool replied
Email has been replied to.
Definition: email.h:51
IMAP-specific Email data -.
Definition: edata.h:35
+ Here is the caller graph for this function:

◆ select_email_uids()

static int select_email_uids ( struct Email **  emails,
int  num_emails,
enum MessageType  flag,
bool  changed,
bool  invert,
struct UidArray *  uida 
)
static

Create a list of Email UIDs by type.

Parameters
emailsArray of Emails
num_emailsNumber of Emails in the array
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
uidaArray to fill with UIDs
Return values
numNumber of UIDs added
-1Error

Definition at line 231 of file imap.c.

233{
234 if (!emails || !uida)
235 return -1;
236
237 for (int i = 0; i < num_emails; i++)
238 {
239 struct Email *e = emails[i];
240 if (changed && !e->changed)
241 continue;
242
243 /* don't include pending expunged messages.
244 *
245 * TODO: can we unset active in cmd_parse_expunge() and
246 * cmd_parse_vanished() instead of checking for index != INT_MAX. */
247 if (!e || !e->active || (e->index == INT_MAX))
248 continue;
249
251
252 bool match = false;
253 switch (flag)
254 {
255 case MUTT_DELETED:
256 if (e->deleted != edata->deleted)
257 match = invert ^ e->deleted;
258 break;
259 case MUTT_FLAG:
260 if (e->flagged != edata->flagged)
261 match = invert ^ e->flagged;
262 break;
263 case MUTT_OLD:
264 if (e->old != edata->old)
265 match = invert ^ e->old;
266 break;
267 case MUTT_READ:
268 if (e->read != edata->read)
269 match = invert ^ e->read;
270 break;
271 case MUTT_REPLIED:
272 if (e->replied != edata->replied)
273 match = invert ^ e->replied;
274 break;
275 case MUTT_TRASH:
276 if (e->deleted && !e->purge)
277 match = true;
278 break;
279 default:
280 break;
281 }
282
283 if (match)
284 ARRAY_ADD(uida, edata->uid);
285 }
286
287 return ARRAY_SIZE(uida);
288}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:156
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:87
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:67
@ MUTT_TRASH
Trashed messages.
Definition: mutt.h:85
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:73
@ MUTT_OLD
Old messages.
Definition: mutt.h:71
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:79
@ MUTT_DELETED
Deleted messages.
Definition: mutt.h:78
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:72
The envelope/body of an email.
Definition: email.h:39
bool purge
Skip trash folder when deleting.
Definition: email.h:79
bool active
Message is not to be removed.
Definition: email.h:76
bool changed
Email has been edited.
Definition: email.h:77
bool deleted
Email is deleted.
Definition: email.h:78
int index
The absolute (unsorted) message number.
Definition: email.h:113
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sync_helper()

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

Sync flag changes to the server.

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

Definition at line 301 of file imap.c.

303{
305 if (!adata)
306 return -1;
307
308 if ((m->rights & right) == 0)
309 return 0;
310
311 if ((right == MUTT_ACL_WRITE) && !imap_has_flag(&imap_mdata_get(m)->flags, name))
312 return 0;
313
314 int count = 0;
315 char buf[1024] = { 0 };
316
317 struct UidArray uida = ARRAY_HEAD_INITIALIZER;
318
319 // Set the flag (+FLAGS) on matching emails
320 select_email_uids(emails, num_emails, flag, true, false, &uida);
321 snprintf(buf, sizeof(buf), "+FLAGS.SILENT (%s)", name);
322 int rc = imap_exec_msg_set(adata, "UID STORE", buf, &uida);
323 if (rc < 0)
324 return rc;
325 count += rc;
326 ARRAY_FREE(&uida);
327
328 // Clear the flag (-FLAGS) on non-matching emails
329 select_email_uids(emails, num_emails, flag, true, true, &uida);
330 buf[0] = '-';
331 rc = imap_exec_msg_set(adata, "UID STORE", buf, &uida);
332 if (rc < 0)
333 return rc;
334 count += rc;
335 ARRAY_FREE(&uida);
336
337 return count;
338}
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:58
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:71
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: adata.c:123
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:231
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:133
char * name
Name of Account.
Definition: account.h:38
void * adata
Private data (for Mailbox backends)
Definition: account.h:42
IMAP-specific Account data -.
Definition: adata.h:40
+ 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 ( struct Buffer buf,
const char *  src,
size_t  start 
)
static

Find longest prefix common to two strings.

Parameters
bufDestination buffer
srcSource buffer
startStarting offset into string
Return values
numLength of the common string

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

Definition at line 349 of file imap.c.

350{
351 size_t pos = start;
352
353 size_t len = buf_len(buf);
354 while ((pos < len) && buf->data[pos] && (buf->data[pos] == src[pos]))
355 pos++;
356 buf->data[pos] = '\0';
357
358 buf_fix_dptr(buf);
359
360 return pos;
361}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:490
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
char * data
Pointer to data.
Definition: buffer.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ complete_hosts()

static int complete_hosts ( struct Buffer buf)
static

Look for completion matches for mailboxes.

Parameters
bufPartial mailbox name to complete
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 372 of file imap.c.

373{
374 int rc = -1;
375 size_t matchlen;
376
377 matchlen = buf_len(buf);
378 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
380 struct MailboxNode *np = NULL;
381 STAILQ_FOREACH(np, &ml, entries)
382 {
384 continue;
385
386 if (rc)
387 {
389 rc = 0;
390 }
391 else
392 {
393 longest_common_prefix(buf, mailbox_path(np->mailbox), matchlen);
394 }
395 }
397
398#if 0
399 TAILQ_FOREACH(conn, mutt_socket_head(), entries)
400 {
401 struct Url url = { 0 };
402 char urlstr[1024] = { 0 };
403
404 if (conn->account.type != MUTT_ACCT_TYPE_IMAP)
405 continue;
406
407 mutt_account_tourl(&conn->account, &url);
408 /* FIXME: how to handle multiple users on the same host? */
409 url.user = NULL;
410 url.path = NULL;
411 url_tostring(&url, urlstr, sizeof(urlstr), U_NO_FLAGS);
412 if (mutt_strn_equal(buf, urlstr, matchlen))
413 {
414 if (rc)
415 {
416 mutt_str_copy(buf, urlstr, buflen);
417 rc = 0;
418 }
419 else
420 {
421 longest_common_prefix(buf, urlstr, matchlen);
422 }
423 }
424 }
425#endif
426
427 return rc;
428}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
@ MUTT_MAILBOX_ANY
Match any Mailbox type.
Definition: mailbox.h:42
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:349
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:474
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:230
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:630
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:80
@ MUTT_ACCT_TYPE_IMAP
Imap Account.
Definition: mutt_account.h:38
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:163
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:186
#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:166
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:167
Container for Accounts, Notifications.
Definition: neomutt.h:41
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:423
#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 437 of file imap.c.

438{
439 char buf[2048] = { 0 };
440 char mbox[1024] = { 0 };
441
442 imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), mailbox);
443 snprintf(buf, sizeof(buf), "CREATE %s", mbox);
444
446 {
447 mutt_error(_("CREATE failed: %s"), imap_cmd_trailer(adata));
448 return -1;
449 }
450
451 return 0;
452}
const char * imap_cmd_trailer(struct ImapAccountData *adata)
Extra information after tagged command response if any.
Definition: command.c:1270
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:921
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 464 of file imap.c.

465{
466 if (imap_path_status(path, false) >= 0)
467 return 0;
468 return -1;
469}
int imap_path_status(const char *path, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1171
+ 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 479 of file imap.c.

480{
481 char oldmbox[1024] = { 0 };
482 char newmbox[1024] = { 0 };
483 int rc = 0;
484
485 imap_munge_mbox_name(adata->unicode, oldmbox, sizeof(oldmbox), oldname);
486 imap_munge_mbox_name(adata->unicode, newmbox, sizeof(newmbox), newname);
487
488 struct Buffer *buf = buf_pool_get();
489 buf_printf(buf, "RENAME %s %s", oldmbox, newmbox);
490
492 rc = -1;
493
494 buf_pool_release(&buf);
495
496 return rc;
497}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
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
String manipulation buffer.
Definition: buffer.h:36
+ 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 506 of file imap.c.

507{
508 char buf[PATH_MAX + 7];
509 char mbox[PATH_MAX] = { 0 };
510 struct Url *url = url_parse(path);
511 if (!url)
512 return -1;
513
515 imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), url->path);
516 url_free(&url);
517 snprintf(buf, sizeof(buf), "DELETE %s", mbox);
519 return -1;
520
521 return 0;
522}
#define PATH_MAX
Definition: mutt.h:42
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:239
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:124
+ 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 528 of file imap.c.

529{
530 /* we set status here to let imap_handle_untagged know we _expect_ to
531 * receive a bye response (so it doesn't freak out and close the conn) */
532 if (adata->state == IMAP_DISCONNECTED)
533 {
534 return;
535 }
536
537 adata->status = IMAP_BYE;
538 imap_cmd_start(adata, "LOGOUT");
539 const short c_imap_poll_timeout = cs_subset_number(NeoMutt->sub, "imap_poll_timeout");
540 if ((c_imap_poll_timeout <= 0) ||
541 (mutt_socket_poll(adata->conn, c_imap_poll_timeout) != 0))
542 {
543 while (imap_cmd_step(adata) == IMAP_RES_CONTINUE)
544 ; // do nothing
545 }
546 mutt_socket_close(adata->conn);
547 adata->state = IMAP_DISCONNECTED;
548}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:144
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1118
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1132
@ IMAP_DISCONNECTED
Disconnected from server.
Definition: private.h:105
@ IMAP_BYE
Logged out from server.
Definition: private.h:96
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:100
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:182
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:45
+ 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 555 of file imap.c.

556{
557 struct Account *np = NULL;
558 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
559 {
560 if (np->type != MUTT_IMAP)
561 continue;
562
563 struct ImapAccountData *adata = np->adata;
564 if (!adata)
565 continue;
566
567 struct Connection *conn = adata->conn;
568 if (!conn || (conn->fd < 0))
569 continue;
570
571 mutt_message(_("Closing connection to %s..."), conn->account.host);
572 imap_logout(np->adata);
574 }
575}
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
#define mutt_message(...)
Definition: logging2.h:91
static void imap_logout(struct ImapAccountData *adata)
Gracefully log out of server.
Definition: imap.c:528
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:36
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:37
char host[128]
Server to login to.
Definition: connaccount.h:54
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:49
int fd
Socket file descriptor.
Definition: connection.h:53
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_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 591 of file imap.c.

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

650{
651 struct ImapMboxData *mdata = imap_mdata_get(m);
653
654 if (!mdata || !edata)
655 return;
656
657 imap_msn_remove(&mdata->msn, edata->msn - 1);
658 edata->msn = 0;
659}
void imap_msn_remove(struct MSNArray *msn, size_t idx)
Remove an entry from the cache.
Definition: msn.c:114
IMAP-specific Mailbox data -.
Definition: mdata.h:40
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 670 of file imap.c.

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

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

743{
744 if (mutt_socket_open(adata->conn) < 0)
745 return -1;
746
747 adata->state = IMAP_CONNECTED;
748
749 if (imap_cmd_step(adata) != IMAP_RES_OK)
750 {
752 return -1;
753 }
754
755 if (mutt_istr_startswith(adata->buf, "* OK"))
756 {
757 if (!mutt_istr_startswith(adata->buf, "* OK [CAPABILITY") && check_capabilities(adata))
758 {
759 goto bail;
760 }
761#ifdef USE_SSL
762 /* Attempt STARTTLS if available and desired. */
763 const bool c_ssl_force_tls = cs_subset_bool(NeoMutt->sub, "ssl_force_tls");
764 if ((adata->conn->ssf == 0) &&
765 (c_ssl_force_tls || (adata->capabilities & IMAP_CAP_STARTTLS)))
766 {
767 enum QuadOption ans;
768
769 if (c_ssl_force_tls)
770 {
771 ans = MUTT_YES;
772 }
773 else if ((ans = query_quadoption(_("Secure connection with TLS?"),
774 NeoMutt->sub, "ssl_starttls")) == MUTT_ABORT)
775 {
776 goto bail;
777 }
778 if (ans == MUTT_YES)
779 {
780 enum ImapExecResult rc = imap_exec(adata, "STARTTLS", IMAP_CMD_SINGLE);
781 // Clear any data after the STARTTLS acknowledgement
782 mutt_socket_empty(adata->conn);
783
784 if (rc == IMAP_EXEC_FATAL)
785 goto bail;
786 if (rc != IMAP_EXEC_ERROR)
787 {
788 if (mutt_ssl_starttls(adata->conn))
789 {
790 mutt_error(_("Could not negotiate TLS connection"));
791 goto bail;
792 }
793 else
794 {
795 /* RFC2595 demands we recheck CAPABILITY after TLS completes. */
796 if (imap_exec(adata, "CAPABILITY", IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
797 goto bail;
798 }
799 }
800 }
801 }
802
803 if (c_ssl_force_tls && (adata->conn->ssf == 0))
804 {
805 mutt_error(_("Encrypted connection unavailable"));
806 goto bail;
807 }
808#endif
809 }
810 else if (mutt_istr_startswith(adata->buf, "* PREAUTH"))
811 {
812#ifdef USE_SSL
813 /* Unless using a secure $tunnel, an unencrypted PREAUTH response may be a
814 * MITM attack. The only way to stop "STARTTLS" MITM attacks is via
815 * $ssl_force_tls: an attacker can easily spoof "* OK" and strip the
816 * STARTTLS capability. So consult $ssl_force_tls, not $ssl_starttls, to
817 * decide whether to abort. Note that if using $tunnel and
818 * $tunnel_is_secure, adata->conn->ssf will be set to 1. */
819 const bool c_ssl_force_tls = cs_subset_bool(NeoMutt->sub, "ssl_force_tls");
820 if ((adata->conn->ssf == 0) && c_ssl_force_tls)
821 {
822 mutt_error(_("Encrypted connection unavailable"));
823 goto bail;
824 }
825#endif
826
827 adata->state = IMAP_AUTHENTICATED;
828 if (check_capabilities(adata) != 0)
829 goto bail;
830 FREE(&adata->capstr);
831 }
832 else
833 {
834 imap_error("imap_open_connection()", adata->buf);
835 goto bail;
836 }
837
838 return 0;
839
840bail:
842 FREE(&adata->capstr);
843 return -1;
844}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
int mutt_ssl_starttls(struct Connection *conn)
Negotiate TLS over an already opened connection.
Definition: gnutls.c:1151
@ IMAP_AUTHENTICATED
Connection is authenticated.
Definition: private.h:107
@ IMAP_CONNECTED
Connected to server.
Definition: private.h:106
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
#define IMAP_CAP_STARTTLS
RFC2595: STARTTLS.
Definition: private.h:131
ImapExecResult
Imap_exec return code.
Definition: private.h:81
@ IMAP_EXEC_ERROR
Imap command failure.
Definition: private.h:83
@ IMAP_EXEC_FATAL
Imap connection failure.
Definition: private.h:84
#define IMAP_CMD_SINGLE
Run a single command.
Definition: private.h:75
void imap_close_connection(struct ImapAccountData *adata)
Close an IMAP connection.
Definition: imap.c:850
static int check_capabilities(struct ImapAccountData *adata)
Make sure we can log in to this server.
Definition: imap.c:107
#define FREE(x)
Definition: memory.h:45
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(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition: question.c:366
void mutt_socket_empty(struct Connection *conn)
Clear out any queued data.
Definition: socket.c:306
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
Definition: socket.c:76
unsigned int ssf
Security strength factor, in bits (see notes)
Definition: connection.h:50
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 850 of file imap.c.

851{
852 if (adata->state != IMAP_DISCONNECTED)
853 {
854 mutt_socket_close(adata->conn);
855 adata->state = IMAP_DISCONNECTED;
856 }
857 adata->seqno = 0;
858 adata->nextcmd = 0;
859 adata->lastcmd = 0;
860 adata->status = 0;
861 memset(adata->cmds, 0, sizeof(struct ImapCommand) * adata->cmdslots);
862}
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:160
+ 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 875 of file imap.c.

876{
877 if (STAILQ_EMPTY(flag_list))
878 return false;
879
880 const size_t flaglen = mutt_str_len(flag);
881 struct ListNode *np = NULL;
882 STAILQ_FOREACH(np, flag_list, entries)
883 {
884 const size_t nplen = strlen(np->data);
885 if ((flaglen >= nplen) && ((flag[nplen] == '\0') || (flag[nplen] == ' ')) &&
886 mutt_istrn_equal(np->data, flag, nplen))
887 {
888 return true;
889 }
890
891 if (mutt_str_equal(np->data, "\\*"))
892 return true;
893 }
894
895 return false;
896}
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:709
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:545
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:502
#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_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 927 of file imap.c.

929{
931 if (!adata || (adata->mailbox != m))
932 return -1;
933
934 char flags[1024] = { 0 };
935 char uid[11] = { 0 };
936
938 {
939 if (e->deleted == imap_edata_get(e)->deleted)
940 e->changed = false;
941 return 0;
942 }
943
944 snprintf(uid, sizeof(uid), "%u", imap_edata_get(e)->uid);
945 buf_reset(cmd);
946 buf_addstr(cmd, "UID STORE ");
947 buf_addstr(cmd, uid);
948
949 flags[0] = '\0';
950
951 set_flag(m, MUTT_ACL_SEEN, e->read, "\\Seen ", flags, sizeof(flags));
952 set_flag(m, MUTT_ACL_WRITE, e->old, "Old ", flags, sizeof(flags));
953 set_flag(m, MUTT_ACL_WRITE, e->flagged, "\\Flagged ", flags, sizeof(flags));
954 set_flag(m, MUTT_ACL_WRITE, e->replied, "\\Answered ", flags, sizeof(flags));
955 set_flag(m, MUTT_ACL_DELETE, imap_edata_get(e)->deleted, "\\Deleted ", flags,
956 sizeof(flags));
957
958 if (m->rights & MUTT_ACL_WRITE)
959 {
960 /* restore system flags */
961 if (imap_edata_get(e)->flags_system)
962 mutt_str_cat(flags, sizeof(flags), imap_edata_get(e)->flags_system);
963 /* set custom flags */
964 struct Buffer *tags = buf_pool_get();
966 if (!buf_is_empty(tags))
967 {
968 mutt_str_cat(flags, sizeof(flags), buf_string(tags));
969 }
970 buf_pool_release(&tags);
971 }
972
974
975 /* UW-IMAP is OK with null flags, Cyrus isn't. The only solution is to
976 * explicitly revoke all system flags (if we have permission) */
977 if (*flags == '\0')
978 {
979 set_flag(m, MUTT_ACL_SEEN, true, "\\Seen ", flags, sizeof(flags));
980 set_flag(m, MUTT_ACL_WRITE, true, "Old ", flags, sizeof(flags));
981 set_flag(m, MUTT_ACL_WRITE, true, "\\Flagged ", flags, sizeof(flags));
982 set_flag(m, MUTT_ACL_WRITE, true, "\\Answered ", flags, sizeof(flags));
983 set_flag(m, MUTT_ACL_DELETE, !imap_edata_get(e)->deleted, "\\Deleted ",
984 flags, sizeof(flags));
985
986 /* erase custom flags */
987 if ((m->rights & MUTT_ACL_WRITE) && imap_edata_get(e)->flags_remote)
988 mutt_str_cat(flags, sizeof(flags), imap_edata_get(e)->flags_remote);
989
991
992 buf_addstr(cmd, " -FLAGS.SILENT (");
993 }
994 else
995 {
996 buf_addstr(cmd, " FLAGS.SILENT (");
997 }
998
999 buf_addstr(cmd, flags);
1000 buf_addstr(cmd, ")");
1001
1002 /* after all this it's still possible to have no flags, if you
1003 * have no ACL rights */
1004 if (*flags && (imap_exec(adata, cmd->data, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS) &&
1005 err_continue && (*err_continue != MUTT_YES))
1006 {
1007 *err_continue = imap_continue("imap_sync_message: STORE failed", adata->buf);
1008 if (*err_continue != MUTT_YES)
1009 return -1;
1010 }
1011
1012 /* server have now the updated flags */
1013 FREE(&imap_edata_get(e)->flags_remote);
1014 struct Buffer *flags_remote = buf_pool_get();
1015 driver_tags_get_with_hidden(&e->tags, flags_remote);
1016 imap_edata_get(e)->flags_remote = buf_strdup(flags_remote);
1017 buf_pool_release(&flags_remote);
1018
1019 if (e->deleted == imap_edata_get(e)->deleted)
1020 e->changed = false;
1021
1022 return 0;
1023}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:75
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:290
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:570
#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
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:646
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:188
static bool compare_flags_for_copy(struct Email *e)
Compare local flags against the server.
Definition: imap.c:204
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:614
struct TagList tags
For drivers that support server tagging.
Definition: email.h:72
char * flags_remote
Definition: edata.h:49
void driver_tags_get_with_hidden(struct TagList *tl, struct Buffer *tags)
Get all tags, also hidden ones, separated by space.
Definition: tags.c:174
+ 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 1031 of file imap.c.

1032{
1033 if (!m || !m->account)
1034 return MX_STATUS_ERROR;
1035
1037 struct ImapMboxData *mdata = imap_mdata_get(m);
1038
1039 /* overload keyboard timeout to avoid many mailbox checks in a row.
1040 * Most users don't like having to wait exactly when they press a key. */
1041 int rc = 0;
1042
1043 /* try IDLE first, unless force is set */
1044 const bool c_imap_idle = cs_subset_bool(NeoMutt->sub, "imap_idle");
1045 const short c_imap_keep_alive = cs_subset_number(NeoMutt->sub, "imap_keep_alive");
1046 if (!force && c_imap_idle && (adata->capabilities & IMAP_CAP_IDLE) &&
1047 ((adata->state != IMAP_IDLE) || (mutt_date_now() >= adata->lastread + c_imap_keep_alive)))
1048 {
1049 if (imap_cmd_idle(adata) < 0)
1050 return MX_STATUS_ERROR;
1051 }
1052 if (adata->state == IMAP_IDLE)
1053 {
1054 while ((rc = mutt_socket_poll(adata->conn, 0)) > 0)
1055 {
1056 if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
1057 {
1058 mutt_debug(LL_DEBUG1, "Error reading IDLE response\n");
1059 return MX_STATUS_ERROR;
1060 }
1061 }
1062 if (rc < 0)
1063 {
1064 mutt_debug(LL_DEBUG1, "Poll failed, disabling IDLE\n");
1065 adata->capabilities &= ~IMAP_CAP_IDLE; // Clear the flag
1066 }
1067 }
1068
1069 const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
1070 if ((force || ((adata->state != IMAP_IDLE) && (mutt_date_now() >= adata->lastread + c_timeout))) &&
1071 (imap_exec(adata, "NOOP", IMAP_CMD_POLL) != IMAP_EXEC_SUCCESS))
1072 {
1073 return MX_STATUS_ERROR;
1074 }
1075
1076 /* We call this even when we haven't run NOOP in case we have pending
1077 * changes to process, since we can reopen here. */
1078 imap_cmd_finish(adata);
1079
1080 enum MxStatus check = MX_STATUS_OK;
1081 if (mdata->check_status & IMAP_EXPUNGE_PENDING)
1082 check = MX_STATUS_REOPENED;
1083 else if (mdata->check_status & IMAP_NEWMAIL_PENDING)
1084 check = MX_STATUS_NEW_MAIL;
1085 else if (mdata->check_status & IMAP_FLAGS_PENDING)
1086 check = MX_STATUS_FLAGS;
1087 else if (rc < 0)
1088 check = MX_STATUS_ERROR;
1089
1090 mdata->check_status = IMAP_OPEN_NO_FLAGS;
1091
1092 if (force)
1093 m->last_checked = 0; // force a check on the next mx_mbox_check() call
1094 return check;
1095}
int imap_cmd_idle(struct ImapAccountData *adata)
Enter the IDLE state.
Definition: command.c:1439
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition: command.c:1372
#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
#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
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:455
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), 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
time_t lastread
last time we read a command for the server
Definition: adata.h:58
time_t last_checked
Last time we checked this mailbox for new mail.
Definition: mailbox.h:105
+ 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 1104 of file imap.c.

1105{
1106 char *uidvalidity_flag = NULL;
1107 char cmd[2048] = { 0 };
1108
1109 if (!adata || !mdata)
1110 return -1;
1111
1112 /* Don't issue STATUS on the selected mailbox, it will be NOOPed or
1113 * IDLEd elsewhere.
1114 * adata->mailbox may be NULL for connections other than the current
1115 * mailbox's. */
1116 if (adata->mailbox && (adata->mailbox->mdata == mdata))
1117 {
1118 adata->mailbox->has_new = false;
1119 return mdata->messages;
1120 }
1121
1122 if (adata->mailbox && !adata->mailbox->poll_new_mail)
1123 return mdata->messages;
1124
1125 if (adata->capabilities & IMAP_CAP_IMAP4REV1)
1126 {
1127 uidvalidity_flag = "UIDVALIDITY";
1128 }
1129 else if (adata->capabilities & IMAP_CAP_STATUS)
1130 {
1131 uidvalidity_flag = "UID-VALIDITY";
1132 }
1133 else
1134 {
1135 mutt_debug(LL_DEBUG2, "Server doesn't support STATUS\n");
1136 return -1;
1137 }
1138
1139 snprintf(cmd, sizeof(cmd), "STATUS %s (UIDNEXT %s UNSEEN RECENT MESSAGES)",
1140 mdata->munge_name, uidvalidity_flag);
1141
1142 int rc = imap_exec(adata, cmd, queue ? IMAP_CMD_QUEUE : IMAP_CMD_POLL);
1143 if (rc != IMAP_EXEC_SUCCESS)
1144 {
1145 mutt_debug(LL_DEBUG1, "Error queueing command\n");
1146 return rc;
1147 }
1148 return mdata->messages;
1149}
#define IMAP_CAP_STATUS
Server supports STATUS command.
Definition: private.h:123
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: private.h:73
struct Mailbox * mailbox
Current selected mailbox.
Definition: adata.h:76
unsigned int messages
Definition: mdata.h:54
char * munge_name
Munged version of the mailbox name.
Definition: mdata.h:42
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
bool poll_new_mail
Check for new mail.
Definition: mailbox.h:115
+ 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 1171 of file imap.c.

1172{
1173 struct Mailbox *m = mx_mbox_find2(path);
1174
1175 const bool is_temp = !m;
1176 if (is_temp)
1177 {
1178 m = mx_path_resolve(path);
1179 if (!mx_mbox_ac_link(m))
1180 {
1181 mailbox_free(&m);
1182 return 0;
1183 }
1184 }
1185
1186 int rc = imap_mailbox_status(m, queue);
1187
1188 if (is_temp)
1189 {
1190 mx_ac_remove(m, false);
1191 mailbox_free(&m);
1192 }
1193
1194 return rc;
1195}
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:90
int imap_mailbox_status(struct Mailbox *m, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1206
int mx_ac_remove(struct Mailbox *m, bool keep_account)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1738
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1603
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:249
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1634
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 1206 of file imap.c.

1207{
1209 struct ImapMboxData *mdata = imap_mdata_get(m);
1210 if (!adata || !mdata)
1211 return -1;
1212 return imap_status(adata, mdata, queue);
1213}
static int imap_status(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1104
+ 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 1222 of file imap.c.

1223{
1224 struct ImapAccountData *adata = NULL;
1225 struct ImapMboxData *mdata = NULL;
1226
1227 if (imap_adata_find(path, &adata, &mdata) < 0)
1228 return -1;
1229
1230 if (subscribe)
1231 mutt_message(_("Subscribing to %s..."), mdata->name);
1232 else
1233 mutt_message(_("Unsubscribing from %s..."), mdata->name);
1234
1235 char buf[2048] = { 0 };
1236 snprintf(buf, sizeof(buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mdata->munge_name);
1237
1238 if (imap_exec(adata, buf, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1239 {
1240 imap_mdata_free((void *) &mdata);
1241 return -1;
1242 }
1243
1244 const bool c_imap_check_subscribed = cs_subset_bool(NeoMutt->sub, "imap_check_subscribed");
1245 if (c_imap_check_subscribed)
1246 {
1247 char mbox[1024] = { 0 };
1248 size_t len = snprintf(mbox, sizeof(mbox), "%smailboxes ", subscribe ? "" : "un");
1249 imap_quote_string(mbox + len, sizeof(mbox) - len, path, true);
1250 struct Buffer *err = buf_pool_get();
1251 if (parse_rc_line(mbox, err))
1252 mutt_debug(LL_DEBUG1, "Error adding subscribed mailbox: %s\n", buf_string(err));
1253 buf_pool_release(&err);
1254 }
1255
1256 if (subscribe)
1257 mutt_message(_("Subscribed to %s"), mdata->name);
1258 else
1259 mutt_message(_("Unsubscribed from %s"), mdata->name);
1260 imap_mdata_free((void *) &mdata);
1261 return 0;
1262}
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:847
int imap_adata_find(const char *path, struct ImapAccountData **adata, struct ImapMboxData **mdata)
Find the Account data for this path.
Definition: util.c:73
enum CommandResult parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: rc.c:104
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 1274 of file imap.c.

1275{
1276 struct ImapAccountData *adata = NULL;
1277 struct ImapMboxData *mdata = NULL;
1278 char tmp[2048] = { 0 };
1279 struct ImapList listresp = { 0 };
1280 struct Buffer *completion_buf = NULL;
1281 size_t clen;
1282 int completions = 0;
1283 int rc;
1284
1285 if (imap_adata_find(path, &adata, &mdata) < 0)
1286 {
1287 buf_strcpy(buf, path);
1288 return complete_hosts(buf);
1289 }
1290
1291 /* fire off command */
1292 const bool c_imap_list_subscribed = cs_subset_bool(NeoMutt->sub, "imap_list_subscribed");
1293 snprintf(tmp, sizeof(tmp), "%s \"\" \"%s%%\"",
1294 c_imap_list_subscribed ? "LSUB" : "LIST", mdata->real_name);
1295
1296 imap_cmd_start(adata, tmp);
1297
1298 /* and see what the results are */
1299 completion_buf = buf_pool_get();
1300 buf_strcpy(completion_buf, mdata->name);
1301 imap_mdata_free((void *) &mdata);
1302
1303 adata->cmdresult = &listresp;
1304 do
1305 {
1306 listresp.name = NULL;
1307 rc = imap_cmd_step(adata);
1308
1309 if ((rc == IMAP_RES_CONTINUE) && listresp.name)
1310 {
1311 /* if the folder isn't selectable, append delimiter to force browse
1312 * to enter it on second tab. */
1313 if (listresp.noselect)
1314 {
1315 clen = strlen(listresp.name);
1316 listresp.name[clen++] = listresp.delim;
1317 listresp.name[clen] = '\0';
1318 }
1319 /* copy in first word */
1320 if (!completions)
1321 {
1322 buf_strcpy(completion_buf, listresp.name);
1323 completions++;
1324 continue;
1325 }
1326
1327 longest_common_prefix(completion_buf, listresp.name, 0);
1328 completions++;
1329 }
1330 } while (rc == IMAP_RES_CONTINUE);
1331 adata->cmdresult = NULL;
1332
1333 if (completions)
1334 {
1335 /* reformat output */
1336 imap_buf_qualify_path(buf, &adata->conn->account, completion_buf->data);
1337 buf_pretty_mailbox(buf);
1338 buf_fix_dptr(buf);
1339 buf_pool_release(&completion_buf);
1340 return 0;
1341 }
1342
1343 buf_pool_release(&completion_buf);
1344 return -1;
1345}
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:830
static int complete_hosts(struct Buffer *buf)
Look for completion matches for mailboxes.
Definition: imap.c:372
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:554
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 1355 of file imap.c.

1356{
1357 char prompt[1024] = { 0 };
1358 int rc = -1;
1359 bool triedcreate = false;
1360 enum QuadOption err_continue = MUTT_NO;
1361
1363 struct ImapAccountData *dest_adata = NULL;
1364 struct ImapMboxData *dest_mdata = NULL;
1365
1366 if (imap_adata_find(dest, &dest_adata, &dest_mdata) < 0)
1367 return -1;
1368
1369 struct Buffer *sync_cmd = buf_pool_get();
1370
1371 /* check that the save-to folder is in the same account */
1372 if (!imap_account_match(&(adata->conn->account), &(dest_adata->conn->account)))
1373 {
1374 mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1375 goto out;
1376 }
1377
1378 for (int i = 0; i < m->msg_count; i++)
1379 {
1380 struct Email *e = m->emails[i];
1381 if (!e)
1382 break;
1383 if (e->active && e->changed && e->deleted && !e->purge)
1384 {
1385 rc = imap_sync_message_for_copy(m, e, sync_cmd, &err_continue);
1386 if (rc < 0)
1387 {
1388 mutt_debug(LL_DEBUG1, "could not sync\n");
1389 goto out;
1390 }
1391 }
1392 }
1393
1394 /* loop in case of TRYCREATE */
1395 do
1396 {
1397 struct UidArray uida = ARRAY_HEAD_INITIALIZER;
1398 select_email_uids(m->emails, m->msg_count, MUTT_TRASH, false, false, &uida);
1399 ARRAY_SORT(&uida, imap_sort_uid, NULL);
1400 rc = imap_exec_msg_set(adata, "UID COPY", dest_mdata->munge_name, &uida);
1401 if (rc == 0)
1402 {
1403 mutt_debug(LL_DEBUG1, "No messages to trash\n");
1404 rc = -1;
1405 goto out;
1406 }
1407 else if (rc < 0)
1408 {
1409 mutt_debug(LL_DEBUG1, "could not queue copy\n");
1410 goto out;
1411 }
1412 else if (m->verbose)
1413 {
1414 mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1415 rc, dest_mdata->name);
1416 }
1417 ARRAY_FREE(&uida);
1418
1419 /* let's get it on */
1420 rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1421 if (rc == IMAP_EXEC_ERROR)
1422 {
1423 if (triedcreate)
1424 {
1425 mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", dest_mdata->name);
1426 break;
1427 }
1428 /* bail out if command failed for reasons other than nonexistent target */
1429 if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1430 break;
1431 mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1432 snprintf(prompt, sizeof(prompt), _("Create %s?"), dest_mdata->name);
1433 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
1434 if (c_confirm_create &&
1435 (query_yesorno_help(prompt, MUTT_YES, NeoMutt->sub, "confirm_create") != MUTT_YES))
1436 {
1438 goto out;
1439 }
1440 if (imap_create_mailbox(adata, dest_mdata->name) < 0)
1441 break;
1442 triedcreate = true;
1443 }
1444 } while (rc == IMAP_EXEC_ERROR);
1445
1446 if (rc != IMAP_EXEC_SUCCESS)
1447 {
1448 imap_error("imap_fast_trash", adata->buf);
1449 goto out;
1450 }
1451
1452 rc = IMAP_EXEC_SUCCESS;
1453
1454out:
1455 buf_pool_release(&sync_cmd);
1456 imap_mdata_free((void *) &dest_mdata);
1457
1458 return ((rc == IMAP_EXEC_SUCCESS) ? 0 : -1);
1459}
#define ARRAY_SORT(head, fn, sdata)
Sort an array.
Definition: array.h:279
int imap_sort_uid(const void *a, const void *b, void *sdata)
Compare two UIDs - Implements sort_t -.
Definition: msg_set.c:55
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition: util.c:1054
char * imap_get_qualifier(char *buf)
Get the qualifier from a tagged response.
Definition: util.c:768
int imap_create_mailbox(struct ImapAccountData *adata, const char *mailbox)
Create a new mailbox.
Definition: imap.c:437
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:927
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
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:342
bool verbose
Display status messages?
Definition: mailbox.h:117
+ 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 1470 of file imap.c.

1471{
1472 if (!m)
1473 return -1;
1474
1475 struct Email **emails = NULL;
1476 int rc;
1477
1479 struct ImapMboxData *mdata = imap_mdata_get(m);
1480
1481 if (adata->state < IMAP_SELECTED)
1482 {
1483 mutt_debug(LL_DEBUG2, "no mailbox selected\n");
1484 return -1;
1485 }
1486
1487 /* This function is only called when the calling code expects the context
1488 * to be changed. */
1490
1491 enum MxStatus check = imap_check_mailbox(m, false);
1492 if (check == MX_STATUS_ERROR)
1493 return check;
1494
1495 /* if we are expunging anyway, we can do deleted messages very quickly... */
1496 if (expunge && (m->rights & MUTT_ACL_DELETE))
1497 {
1498 struct UidArray uida = ARRAY_HEAD_INITIALIZER;
1499 select_email_uids(m->emails, m->msg_count, MUTT_DELETED, true, false, &uida);
1500 ARRAY_SORT(&uida, imap_sort_uid, NULL);
1501 rc = imap_exec_msg_set(adata, "UID STORE", "+FLAGS.SILENT (\\Deleted)", &uida);
1502 ARRAY_FREE(&uida);
1503 if (rc < 0)
1504 {
1505 mutt_error(_("Expunge failed"));
1506 return rc;
1507 }
1508
1509 if (rc > 0)
1510 {
1511 /* mark these messages as unchanged so second pass ignores them. Done
1512 * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */
1513 for (int i = 0; i < m->msg_count; i++)
1514 {
1515 struct Email *e = m->emails[i];
1516 if (!e)
1517 break;
1518 if (e->deleted && e->changed)
1519 e->active = false;
1520 }
1521 if (m->verbose)
1522 {
1523 mutt_message(ngettext("Marking %d message deleted...",
1524 "Marking %d messages deleted...", rc),
1525 rc);
1526 }
1527 }
1528 }
1529
1530#ifdef USE_HCACHE
1531 imap_hcache_open(adata, mdata);
1532#endif
1533
1534 /* save messages with real (non-flag) changes */
1535 for (int i = 0; i < m->msg_count; i++)
1536 {
1537 struct Email *e = m->emails[i];
1538 if (!e)
1539 break;
1540
1541 if (e->deleted)
1542 {
1543 imap_cache_del(m, e);
1544#ifdef USE_HCACHE
1545 imap_hcache_del(mdata, imap_edata_get(e)->uid);
1546#endif
1547 }
1548
1549 if (e->active && e->changed)
1550 {
1551#ifdef USE_HCACHE
1552 imap_hcache_put(mdata, e);
1553#endif
1554 /* if the message has been rethreaded or attachments have been deleted
1555 * we delete the message and reupload it.
1556 * This works better if we're expunging, of course. */
1557 if (e->env->changed || e->attach_del)
1558 {
1559 /* L10N: The plural is chosen by the last %d, i.e. the total number */
1560 if (m->verbose)
1561 {
1562 mutt_message(ngettext("Saving changed message... [%d/%d]",
1563 "Saving changed messages... [%d/%d]", m->msg_count),
1564 i + 1, m->msg_count);
1565 }
1566 bool save_append = m->append;
1567 m->append = true;
1569 m->append = save_append;
1570 e->env->changed = false;
1571 }
1572 }
1573 }
1574
1575#ifdef USE_HCACHE
1576 imap_hcache_close(mdata);
1577#endif
1578
1579 /* presort here to avoid doing 10 resorts in imap_exec_msg_set */
1580 emails = mutt_mem_malloc(m->msg_count * sizeof(struct Email *));
1581 memcpy(emails, m->emails, m->msg_count * sizeof(struct Email *));
1582 mutt_qsort_r(emails, m->msg_count, sizeof(struct Email *), imap_sort_email_uid, NULL);
1583
1584 rc = sync_helper(m, emails, m->msg_count, MUTT_ACL_DELETE, MUTT_DELETED, "\\Deleted");
1585 if (rc >= 0)
1586 rc |= sync_helper(m, emails, m->msg_count, MUTT_ACL_WRITE, MUTT_FLAG, "\\Flagged");
1587 if (rc >= 0)
1588 rc |= sync_helper(m, emails, m->msg_count, MUTT_ACL_WRITE, MUTT_OLD, "Old");
1589 if (rc >= 0)
1590 rc |= sync_helper(m, emails, m->msg_count, MUTT_ACL_SEEN, MUTT_READ, "\\Seen");
1591 if (rc >= 0)
1592 rc |= sync_helper(m, emails, m->msg_count, MUTT_ACL_WRITE, MUTT_REPLIED, "\\Answered");
1593
1594 FREE(&emails);
1595
1596 /* Flush the queued flags if any were changed in sync_helper. */
1597 if (rc > 0)
1598 if (imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1599 rc = -1;
1600
1601 if (rc < 0)
1602 {
1603 if (close)
1604 {
1605 if (query_yesorno(_("Error saving flags. Close anyway?"), MUTT_NO) == MUTT_YES)
1606 {
1607 adata->state = IMAP_AUTHENTICATED;
1608 return 0;
1609 }
1610 }
1611 else
1612 {
1613 mutt_error(_("Error saving flags"));
1614 }
1615 return -1;
1616 }
1617
1618 /* Update local record of server state to reflect the synchronization just
1619 * completed. imap_read_headers always overwrites hcache-origin flags, so
1620 * there is no need to mutate the hcache after flag-only changes. */
1621 for (int i = 0; i < m->msg_count; i++)
1622 {
1623 struct Email *e = m->emails[i];
1624 if (!e)
1625 break;
1626 struct ImapEmailData *edata = imap_edata_get(e);
1627 edata->deleted = e->deleted;
1628 edata->flagged = e->flagged;
1629 edata->old = e->old;
1630 edata->read = e->read;
1631 edata->replied = e->replied;
1632 e->changed = false;
1633 }
1634 m->changed = false;
1635
1636 /* We must send an EXPUNGE command if we're not closing. */
1637 if (expunge && !close && (m->rights & MUTT_ACL_DELETE))
1638 {
1639 if (m->verbose)
1640 mutt_message(_("Expunging messages from server..."));
1641 /* Set expunge bit so we don't get spurious reopened messages */
1642 mdata->reopen |= IMAP_EXPUNGE_EXPECTED;
1643 if (imap_exec(adata, "EXPUNGE", IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1644 {
1645 mdata->reopen &= ~IMAP_EXPUNGE_EXPECTED;
1646 imap_error(_("imap_sync_mailbox: EXPUNGE failed"), adata->buf);
1647 return -1;
1648 }
1649 mdata->reopen &= ~IMAP_EXPUNGE_EXPECTED;
1650 }
1651
1652 if (expunge && close)
1653 {
1654 adata->closing = true;
1655 imap_exec(adata, "CLOSE", IMAP_CMD_NO_FLAGS);
1656 adata->state = IMAP_AUTHENTICATED;
1657 }
1658
1659 const bool c_message_cache_clean = cs_subset_bool(NeoMutt->sub, "message_cache_clean");
1660 if (c_message_cache_clean)
1662
1663 return check;
1664}
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:42
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: external.h:53
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:901
int imap_cache_clean(struct Mailbox *m)
Delete all the entries in the message cache.
Definition: message.c:1888
void imap_allow_reopen(struct Mailbox *m)
Allow re-opening a folder upon expunge.
Definition: util.c:1026
@ 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:380
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:301
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition: imap.c:1031
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
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:67
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:327
struct Envelope * env
Envelope information.
Definition: email.h:68
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:102
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:90
bool closing
If true, we are waiting for CLOSE completion.
Definition: adata.h:43
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: mdata.h:45
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 1743 of file imap.c.

1744{
1746 struct ImapMboxData *mdata = imap_mdata_get(m);
1747 if (!adata || !mdata)
1748 return;
1749
1750 const char *condstore = NULL;
1751#ifdef USE_HCACHE
1752 const bool c_imap_condstore = cs_subset_bool(NeoMutt->sub, "imap_condstore");
1753 if ((adata->capabilities & IMAP_CAP_CONDSTORE) && c_imap_condstore)
1754 condstore = " (CONDSTORE)";
1755 else
1756#endif
1757 condstore = "";
1758
1759 char buf[PATH_MAX] = { 0 };
1760 snprintf(buf, sizeof(buf), "%s %s%s", m->readonly ? "EXAMINE" : "SELECT",
1761 mdata->munge_name, condstore);
1762
1763 adata->state = IMAP_SELECTED;
1764
1765 imap_cmd_start(adata, buf);
1766}
#define IMAP_CAP_CONDSTORE
RFC7162.
Definition: private.h:136
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:116
+ 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 1776 of file imap.c.

1777{
1778 if (!adata)
1779 return -1;
1780
1781 if (adata->state == IMAP_DISCONNECTED)
1782 {
1783 buf_reset(&adata->cmdbuf); // purge outstanding queued commands
1784 imap_open_connection(adata);
1785 }
1786 if (adata->state == IMAP_CONNECTED)
1787 {
1789 {
1790 adata->state = IMAP_AUTHENTICATED;
1791 FREE(&adata->capstr);
1792 if (adata->conn->ssf != 0)
1793 {
1794 mutt_debug(LL_DEBUG2, "Communication encrypted at %d bits\n",
1795 adata->conn->ssf);
1796 }
1797 }
1798 else
1799 {
1801 }
1802 }
1803 if (adata->state == IMAP_AUTHENTICATED)
1804 {
1805 /* capabilities may have changed */
1806 imap_exec(adata, "CAPABILITY", IMAP_CMD_PASS);
1807
1808#ifdef USE_ZLIB
1809 /* RFC4978 */
1810 const bool c_imap_deflate = cs_subset_bool(NeoMutt->sub, "imap_deflate");
1811 if ((adata->capabilities & IMAP_CAP_COMPRESS) && c_imap_deflate &&
1812 (imap_exec(adata, "COMPRESS DEFLATE", IMAP_CMD_PASS) == IMAP_EXEC_SUCCESS))
1813 {
1814 mutt_debug(LL_DEBUG2, "IMAP compression is enabled on connection to %s\n",
1815 adata->conn->account.host);
1816 mutt_zstrm_wrap_conn(adata->conn);
1817 }
1818#endif
1819
1820 /* enable RFC2971, if the server supports that */
1821 const bool c_imap_send_id = cs_subset_bool(NeoMutt->sub, "imap_send_id");
1822 if (c_imap_send_id && (adata->capabilities & IMAP_CAP_ID))
1823 {
1824 imap_exec(adata, "ID (\"name\" \"NeoMutt\" \"version\" \"" PACKAGE_VERSION "\")",
1826 }
1827
1828 /* enable RFC6855, if the server supports that */
1829 const bool c_imap_rfc5161 = cs_subset_bool(NeoMutt->sub, "imap_rfc5161");
1830 if (c_imap_rfc5161 && (adata->capabilities & IMAP_CAP_ENABLE))
1831 imap_exec(adata, "ENABLE UTF8=ACCEPT", IMAP_CMD_QUEUE);
1832
1833 /* enable QRESYNC. Advertising QRESYNC also means CONDSTORE
1834 * is supported (even if not advertised), so flip that bit. */
1835 if (adata->capabilities & IMAP_CAP_QRESYNC)
1836 {
1838 const bool c_imap_qresync = cs_subset_bool(NeoMutt->sub, "imap_qresync");
1839 if (c_imap_rfc5161 && c_imap_qresync)
1840 imap_exec(adata, "ENABLE QRESYNC", IMAP_CMD_QUEUE);
1841 }
1842
1843 /* get root delimiter, '/' as default */
1844 adata->delim = '/';
1845 imap_exec(adata, "LIST \"\" \"\"", IMAP_CMD_QUEUE);
1846
1847 /* we may need the root delimiter before we open a mailbox */
1848 imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1849
1850 /* select the mailbox that used to be open before disconnect */
1851 if (adata->mailbox)
1852 {
1853 imap_mbox_select(adata->mailbox);
1854 }
1855 }
1856
1857 if (adata->state < IMAP_AUTHENTICATED)
1858 return -1;
1859
1860 return 0;
1861}
@ IMAP_AUTH_SUCCESS
Authentication successful.
Definition: auth.h:40
void mutt_account_unsetpass(struct ConnAccount *cac)
Unset ConnAccount's password.
Definition: connaccount.c:178
int imap_authenticate(struct ImapAccountData *adata)
Authenticate to an IMAP server.
Definition: auth.c:115
#define IMAP_CAP_ENABLE
RFC5161.
Definition: private.h:135
#define IMAP_CAP_ID
RFC2971: IMAP4 ID extension.
Definition: private.h:141
#define IMAP_CMD_PASS
Command contains a password. Suppress logging.
Definition: private.h:72
#define IMAP_CAP_QRESYNC
RFC7162.
Definition: private.h:137
#define IMAP_CAP_COMPRESS
RFC4978: COMPRESS=DEFLATE.
Definition: private.h:139
int imap_open_connection(struct ImapAccountData *adata)
Open an IMAP connection.
Definition: imap.c:742
static void imap_mbox_select(struct Mailbox *m)
Select a Mailbox.
Definition: imap.c:1743
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:291
+ 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 2384 of file imap.c.

2385{
2386 buf_alloc(path, PATH_MAX);
2387 return imap_path_canon(path);
2388}
int imap_path_canon(struct Buffer *path)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition: imap.c:2358
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ ImapCommands

const struct Command ImapCommands[]
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() -.
Definition: commands.c:1547
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: commands.c:1210

Imap Commands.

Definition at line 86 of file imap.c.