NeoMutt  2020-06-26-250-g349c94
Teaching an old dog new tricks
DOXYGEN
command.c File Reference

Send/receive commands to/from an IMAP server. More...

#include "config.h"
#include <ctype.h>
#include <errno.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 "email/lib.h"
#include "core/lib.h"
#include "conn/lib.h"
#include "init.h"
#include "message.h"
#include "mutt_account.h"
#include "mutt_globals.h"
#include "mutt_logging.h"
#include "mutt_menu.h"
#include "mutt_socket.h"
#include "mx.h"
+ Include dependency graph for command.c:

Go to the source code of this file.

Macros

#define IMAP_CMD_BUFSIZE   512
 

Functions

static bool cmd_queue_full (struct ImapAccountData *adata)
 Is the IMAP command queue full? More...
 
static struct ImapCommandcmd_new (struct ImapAccountData *adata)
 Create and queue a new command control block. More...
 
static int cmd_queue (struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
 Add a IMAP command to the queue. More...
 
static void cmd_handle_fatal (struct ImapAccountData *adata)
 When ImapAccountData is in fatal state, do what we can. More...
 
static int cmd_start (struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
 Start a new IMAP command. More...
 
static int cmd_status (const char *s)
 parse response line for tagged OK/NO/BAD More...
 
static void cmd_parse_expunge (struct ImapAccountData *adata, const char *s)
 Parse expunge command. More...
 
static void cmd_parse_vanished (struct ImapAccountData *adata, char *s)
 Parse vanished command. More...
 
static void cmd_parse_fetch (struct ImapAccountData *adata, char *s)
 Load fetch response into ImapAccountData. More...
 
static void cmd_parse_capability (struct ImapAccountData *adata, char *s)
 set capability bits according to CAPABILITY response More...
 
static void cmd_parse_list (struct ImapAccountData *adata, char *s)
 Parse a server LIST command (list mailboxes) More...
 
static void cmd_parse_lsub (struct ImapAccountData *adata, char *s)
 Parse a server LSUB (list subscribed mailboxes) More...
 
static void cmd_parse_myrights (struct ImapAccountData *adata, const char *s)
 Set rights bits according to MYRIGHTS response. More...
 
static struct Mailboxfind_mailbox (struct ImapAccountData *adata, const char *name)
 Find a Mailbox by its name. More...
 
static void cmd_parse_status (struct ImapAccountData *adata, char *s)
 Parse status from server. More...
 
static void cmd_parse_enabled (struct ImapAccountData *adata, const char *s)
 Record what the server has enabled. More...
 
static void cmd_parse_exists (struct ImapAccountData *adata, const char *pn)
 Parse EXISTS message from serer. More...
 
static int cmd_handle_untagged (struct ImapAccountData *adata)
 fallback parser for otherwise unhandled messages More...
 
int imap_cmd_start (struct ImapAccountData *adata, const char *cmdstr)
 Given an IMAP command, send it to the server. More...
 
int imap_cmd_step (struct ImapAccountData *adata)
 Reads server responses from an IMAP command. More...
 
bool imap_code (const char *s)
 Was the command successful. More...
 
const char * imap_cmd_trailer (struct ImapAccountData *adata)
 Extra information after tagged command response if any. More...
 
int imap_exec (struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
 Execute a command and wait for the response from the server. More...
 
void imap_cmd_finish (struct ImapAccountData *adata)
 Attempt to perform cleanup. More...
 
int imap_cmd_idle (struct ImapAccountData *adata)
 Enter the IDLE state. More...
 

Variables

static const char *const Capabilities []
 Server capabilities strings that we understand. More...
 

Detailed Description

Send/receive commands to/from an IMAP server.

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 command.c.

Macro Definition Documentation

◆ IMAP_CMD_BUFSIZE

#define IMAP_CMD_BUFSIZE   512

Definition at line 55 of file command.c.

Function Documentation

◆ cmd_queue_full()

static bool cmd_queue_full ( struct ImapAccountData adata)
static

Is the IMAP command queue full?

Parameters
adataImap Account data
Return values
trueQueue is full

Definition at line 90 of file command.c.

91 {
92  if (((adata->nextcmd + 1) % adata->cmdslots) == adata->lastcmd)
93  return true;
94 
95  return false;
96 }
+ Here is the caller graph for this function:

◆ cmd_new()

static struct ImapCommand* cmd_new ( struct ImapAccountData adata)
static

Create and queue a new command control block.

Parameters
adataImap Account data
Return values
NULLif the pipeline is full
ptrNew command

Definition at line 104 of file command.c.

105 {
106  struct ImapCommand *cmd = NULL;
107 
108  if (cmd_queue_full(adata))
109  {
110  mutt_debug(LL_DEBUG3, "IMAP command queue full\n");
111  return NULL;
112  }
113 
114  cmd = adata->cmds + adata->nextcmd;
115  adata->nextcmd = (adata->nextcmd + 1) % adata->cmdslots;
116 
117  snprintf(cmd->seq, sizeof(cmd->seq), "%c%04u", adata->seqid, adata->seqno++);
118  if (adata->seqno > 9999)
119  adata->seqno = 0;
120 
121  cmd->state = IMAP_RES_NEW;
122 
123  return cmd;
124 }
struct ImapCommand * cmds
Definition: private.h:199
#define IMAP_RES_NEW
ImapCommand.state additions.
Definition: private.h:58
unsigned int seqno
tag sequence number, e.g. &#39;{seqid}0001&#39;
Definition: private.h:187
unsigned char seqid
tag sequence prefix
Definition: private.h:186
IMAP command structure.
Definition: private.h:158
char seq[SEQ_LEN+1]
Command tag, e.g. &#39;a0001&#39;.
Definition: private.h:160
int state
Command state, e.g. IMAP_RES_NEW.
Definition: private.h:161
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:42
static bool cmd_queue_full(struct ImapAccountData *adata)
Is the IMAP command queue full?
Definition: command.c:90
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_queue()

static int cmd_queue ( struct ImapAccountData adata,
const char *  cmdstr,
ImapCmdFlags  flags 
)
static

Add a IMAP command to the queue.

Parameters
adataImap Account data
cmdstrCommand string
flagsServer flags, see ImapCmdFlags
Return values
0Success
<0Failure, e.g. IMAP_RES_BAD

If the queue is full, attempts to drain it.

Definition at line 136 of file command.c.

137 {
138  if (cmd_queue_full(adata))
139  {
140  mutt_debug(LL_DEBUG3, "Draining IMAP command pipeline\n");
141 
142  const int rc = imap_exec(adata, NULL, flags & IMAP_CMD_POLL);
143 
144  if (rc == IMAP_EXEC_ERROR)
145  return IMAP_RES_BAD;
146  }
147 
148  struct ImapCommand *cmd = cmd_new(adata);
149  if (!cmd)
150  return IMAP_RES_BAD;
151 
152  if (mutt_buffer_add_printf(&adata->cmdbuf, "%s %s\r\n", cmd->seq, cmdstr) < 0)
153  return IMAP_RES_BAD;
154 
155  return 0;
156 }
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: private.h:75
static struct ImapCommand * cmd_new(struct ImapAccountData *adata)
Create and queue a new command control block.
Definition: command.c:104
struct Buffer cmdbuf
Definition: private.h:203
IMAP command structure.
Definition: private.h:158
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
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
char seq[SEQ_LEN+1]
Command tag, e.g. &#39;a0001&#39;.
Definition: private.h:160
Imap command failure.
Definition: private.h:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:42
static bool cmd_queue_full(struct ImapAccountData *adata)
Is the IMAP command queue full?
Definition: command.c:90
#define IMAP_RES_BAD
<tag> BAD ...
Definition: private.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_handle_fatal()

static void cmd_handle_fatal ( struct ImapAccountData adata)
static

When ImapAccountData is in fatal state, do what we can.

Parameters
adataImap Account data

Definition at line 162 of file command.c.

163 {
164  adata->status = IMAP_FATAL;
165 
166  if (!adata->mailbox)
167  return;
168 
169  struct ImapMboxData *mdata = adata->mailbox->mdata;
170 
171  if ((adata->state >= IMAP_SELECTED) && (mdata->reopen & IMAP_REOPEN_ALLOW))
172  {
174  mutt_socket_close(adata->conn);
175  mutt_error(_("Mailbox %s@%s closed"), adata->conn->account.user,
176  adata->conn->account.host);
177  adata->state = IMAP_DISCONNECTED;
178  }
179 
180  imap_close_connection(adata);
181  if (!adata->recovering)
182  {
183  adata->recovering = true;
184  if (imap_login(adata))
186  adata->recovering = false;
187  }
188 }
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
Unrecoverable error occurred.
Definition: private.h:96
int imap_login(struct ImapAccountData *adata)
Open an IMAP connection.
Definition: imap.c:1799
#define IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition: private.h:65
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: private.h:174
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:222
char user[128]
Username.
Definition: connaccount.h:55
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
void imap_close_connection(struct ImapAccountData *adata)
Close an IMAP connection.
Definition: imap.c:807
char host[128]
Server to login to.
Definition: connaccount.h:53
Disconnected from server.
Definition: private.h:106
void mx_fastclose_mailbox(struct Mailbox *m)
free up memory associated with the Mailbox
Definition: mx.c:446
Mailbox is selected.
Definition: private.h:109
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
void * mdata
Driver specific data.
Definition: mailbox.h:136
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:175
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:96
IMAP-specific Mailbox data -.
Definition: private.h:216
#define mutt_error(...)
Definition: logging.h:84
bool recovering
Definition: private.h:172
struct Connection * conn
Definition: private.h:171
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_start()

static int cmd_start ( struct ImapAccountData adata,
const char *  cmdstr,
ImapCmdFlags  flags 
)
static

Start a new IMAP command.

Parameters
adataImap Account data
cmdstrCommand string
flagsCommand flags, see ImapCmdFlags
Return values
0Success
<0Failure, e.g. IMAP_RES_BAD

Definition at line 198 of file command.c.

199 {
200  int rc;
201 
202  if (adata->status == IMAP_FATAL)
203  {
204  cmd_handle_fatal(adata);
205  return -1;
206  }
207 
208  if (cmdstr && ((rc = cmd_queue(adata, cmdstr, flags)) < 0))
209  return rc;
210 
211  if (flags & IMAP_CMD_QUEUE)
212  return 0;
213 
214  if (mutt_buffer_is_empty(&adata->cmdbuf))
215  return IMAP_RES_BAD;
216 
217  rc = mutt_socket_send_d(adata->conn, adata->cmdbuf.data,
219  mutt_buffer_reset(&adata->cmdbuf);
220 
221  /* unidle when command queue is flushed */
222  if (adata->state == IMAP_IDLE)
223  adata->state = IMAP_SELECTED;
224 
225  return (rc < 0) ? IMAP_RES_BAD : 0;
226 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
Unrecoverable error occurred.
Definition: private.h:96
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: private.h:174
#define IMAP_LOG_PASS
Definition: private.h:50
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:162
struct Buffer cmdbuf
Definition: private.h:203
#define mutt_socket_send_d(conn, buf, dbg)
Definition: mutt_socket.h:38
Mailbox is selected.
Definition: private.h:109
static int cmd_queue(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Add a IMAP command to the queue.
Definition: command.c:136
struct ListHead flags
Definition: private.h:227
#define IMAP_CMD_PASS
Command contains a password. Suppress logging.
Definition: private.h:73
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:175
char * data
Pointer to data.
Definition: buffer.h:35
Connection is idle.
Definition: private.h:112
#define IMAP_LOG_CMD
Definition: private.h:48
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: private.h:74
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
struct Connection * conn
Definition: private.h:171
#define IMAP_RES_BAD
<tag> BAD ...
Definition: private.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_status()

static int cmd_status ( const char *  s)
static

parse response line for tagged OK/NO/BAD

Parameters
sStatus string from server
Return values
0Success
<0Failure, e.g. IMAP_RES_BAD

Definition at line 234 of file command.c.

235 {
236  s = imap_next_word((char *) s);
237 
238  if (mutt_istr_startswith(s, "OK"))
239  return IMAP_RES_OK;
240  if (mutt_istr_startswith(s, "NO"))
241  return IMAP_RES_NO;
242 
243  return IMAP_RES_BAD;
244 }
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
#define IMAP_RES_NO
<tag> NO ...
Definition: private.h:53
#define IMAP_RES_BAD
<tag> BAD ...
Definition: private.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_expunge()

static void cmd_parse_expunge ( struct ImapAccountData adata,
const char *  s 
)
static

Parse expunge command.

Parameters
adataImap Account data
sString containing MSN of message to expunge

cmd_parse_expunge: mark headers with new sequence ID and mark adata to be reopened at our earliest convenience

Definition at line 254 of file command.c.

255 {
256  unsigned int exp_msn;
257  struct Email *e = NULL;
258 
259  mutt_debug(LL_DEBUG2, "Handling EXPUNGE\n");
260 
261  struct ImapMboxData *mdata = adata->mailbox->mdata;
262 
263  if ((mutt_str_atoui(s, &exp_msn) < 0) || (exp_msn < 1) || (exp_msn > mdata->max_msn))
264  return;
265 
266  e = mdata->msn_index[exp_msn - 1];
267  if (e)
268  {
269  /* imap_expunge_mailbox() will rewrite e->index.
270  * It needs to resort using SORT_ORDER anyway, so setting to INT_MAX
271  * makes the code simpler and possibly more efficient. */
272  e->index = INT_MAX;
273  imap_edata_get(e)->msn = 0;
274  }
275 
276  /* decrement seqno of those above. */
277  for (unsigned int cur = exp_msn; cur < mdata->max_msn; cur++)
278  {
279  e = mdata->msn_index[cur];
280  if (e)
281  imap_edata_get(e)->msn--;
282  mdata->msn_index[cur - 1] = e;
283  }
284 
285  mdata->msn_index[mdata->max_msn - 1] = NULL;
286  mdata->max_msn--;
287 
288  mdata->reopen |= IMAP_EXPUNGE_PENDING;
289 }
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:98
The envelope/body of an email.
Definition: email.h:37
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:222
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
unsigned int msn
Message Sequence Number.
Definition: message.h:45
unsigned int max_msn
the largest MSN fetched so far
Definition: private.h:239
Log at debug level 2.
Definition: logging.h:41
void * mdata
Driver specific data.
Definition: mailbox.h:136
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:287
IMAP-specific Mailbox data -.
Definition: private.h:216
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:67
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_vanished()

static void cmd_parse_vanished ( struct ImapAccountData adata,
char *  s 
)
static

Parse vanished command.

Parameters
adataImap Account data
sString containing MSN of message to expunge

Handle VANISHED (RFC7162), which is like expunge, but passes a seqset of UIDs. An optional (EARLIER) argument specifies not to decrement subsequent MSNs.

Definition at line 299 of file command.c.

300 {
301  bool earlier = false;
302  int rc;
303  unsigned int uid = 0;
304 
305  struct ImapMboxData *mdata = adata->mailbox->mdata;
306 
307  mutt_debug(LL_DEBUG2, "Handling VANISHED\n");
308 
309  if (mutt_istr_startswith(s, "(EARLIER)"))
310  {
311  /* The RFC says we should not decrement msns with the VANISHED EARLIER tag.
312  * My experimentation says that's crap. */
313  earlier = true;
314  s = imap_next_word(s);
315  }
316 
317  char *end_of_seqset = s;
318  while (*end_of_seqset)
319  {
320  if (!strchr("0123456789:,", *end_of_seqset))
321  *end_of_seqset = '\0';
322  else
323  end_of_seqset++;
324  }
325 
326  struct SeqsetIterator *iter = mutt_seqset_iterator_new(s);
327  if (!iter)
328  {
329  mutt_debug(LL_DEBUG2, "VANISHED: empty seqset [%s]?\n", s);
330  return;
331  }
332 
333  while ((rc = mutt_seqset_iterator_next(iter, &uid)) == 0)
334  {
335  struct Email *e = mutt_hash_int_find(mdata->uid_hash, uid);
336  if (!e)
337  continue;
338 
339  unsigned int exp_msn = imap_edata_get(e)->msn;
340 
341  /* imap_expunge_mailbox() will rewrite e->index.
342  * It needs to resort using SORT_ORDER anyway, so setting to INT_MAX
343  * makes the code simpler and possibly more efficient. */
344  e->index = INT_MAX;
345  imap_edata_get(e)->msn = 0;
346 
347  if ((exp_msn < 1) || (exp_msn > mdata->max_msn))
348  {
349  mutt_debug(LL_DEBUG1, "VANISHED: msn for UID %u is incorrect\n", uid);
350  continue;
351  }
352  if (mdata->msn_index[exp_msn - 1] != e)
353  {
354  mutt_debug(LL_DEBUG1, "VANISHED: msn_index for UID %u is incorrect\n", uid);
355  continue;
356  }
357 
358  mdata->msn_index[exp_msn - 1] = NULL;
359 
360  if (!earlier)
361  {
362  /* decrement seqno of those above. */
363  for (unsigned int cur = exp_msn; cur < mdata->max_msn; cur++)
364  {
365  e = mdata->msn_index[cur];
366  if (e)
367  imap_edata_get(e)->msn--;
368  mdata->msn_index[cur - 1] = e;
369  }
370 
371  mdata->msn_index[mdata->max_msn - 1] = NULL;
372  mdata->max_msn--;
373  }
374  }
375 
376  if (rc < 0)
377  mutt_debug(LL_DEBUG1, "VANISHED: illegal seqset %s\n", s);
378 
379  mdata->reopen |= IMAP_EXPUNGE_PENDING;
380 
382 }
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:98
The envelope/body of an email.
Definition: email.h:37
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:222
struct SeqsetIterator * mutt_seqset_iterator_new(const char *seqset)
Create a new Sequence Set Iterator.
Definition: util.c:1209
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
unsigned int msn
Message Sequence Number.
Definition: message.h:45
void * mutt_hash_int_find(const struct HashTable *table, unsigned int intkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:384
unsigned int max_msn
the largest MSN fetched so far
Definition: private.h:239
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
Log at debug level 2.
Definition: logging.h:41
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct HashTable * uid_hash
Definition: private.h:236
void mutt_seqset_iterator_free(struct SeqsetIterator **ptr)
Free a Sequence Set Iterator.
Definition: util.c:1289
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: private.h:216
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:67
int mutt_seqset_iterator_next(struct SeqsetIterator *iter, unsigned int *next)
Get the next UID from a Sequence Set.
Definition: util.c:1230
UID Sequence Set Iterator.
Definition: private.h:248
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_fetch()

static void cmd_parse_fetch ( struct ImapAccountData adata,
char *  s 
)
static

Load fetch response into ImapAccountData.

Parameters
adataImap Account data
sString containing MSN of message to fetch

Currently only handles unanticipated FETCH responses, and only FLAGS data. We get these if another client has changed flags for a mailbox we've selected. Of course, a lot of code here duplicates code in message.c.

Definition at line 393 of file command.c.

394 {
395  unsigned int msn, uid;
396  struct Email *e = NULL;
397  char *flags = NULL;
398  int uid_checked = 0;
399  bool server_changes = false;
400 
401  struct ImapMboxData *mdata = imap_mdata_get(adata->mailbox);
402 
403  mutt_debug(LL_DEBUG3, "Handling FETCH\n");
404 
405  if (mutt_str_atoui(s, &msn) < 0)
406  {
407  mutt_debug(LL_DEBUG3, "Skipping FETCH response - illegal MSN\n");
408  return;
409  }
410 
411  if ((msn < 1) || (msn > mdata->max_msn))
412  {
413  mutt_debug(LL_DEBUG3, "Skipping FETCH response - MSN %u out of range\n", msn);
414  return;
415  }
416 
417  e = mdata->msn_index[msn - 1];
418  if (!e || !e->active)
419  {
420  mutt_debug(LL_DEBUG3, "Skipping FETCH response - MSN %u not in msn_index\n", msn);
421  return;
422  }
423 
424  mutt_debug(LL_DEBUG2, "Message UID %u updated\n", imap_edata_get(e)->uid);
425  /* skip FETCH */
426  s = imap_next_word(s);
427  s = imap_next_word(s);
428 
429  if (*s != '(')
430  {
431  mutt_debug(LL_DEBUG1, "Malformed FETCH response\n");
432  return;
433  }
434  s++;
435 
436  while (*s)
437  {
438  SKIPWS(s);
439  size_t plen = mutt_istr_startswith(s, "FLAGS");
440  if (plen != 0)
441  {
442  flags = s;
443  if (uid_checked)
444  break;
445 
446  s += plen;
447  SKIPWS(s);
448  if (*s != '(')
449  {
450  mutt_debug(LL_DEBUG1, "bogus FLAGS response: %s\n", s);
451  return;
452  }
453  s++;
454  while (*s && (*s != ')'))
455  s++;
456  if (*s == ')')
457  s++;
458  else
459  {
460  mutt_debug(LL_DEBUG1, "Unterminated FLAGS response: %s\n", s);
461  return;
462  }
463  }
464  else if ((plen = mutt_istr_startswith(s, "UID")))
465  {
466  s += plen;
467  SKIPWS(s);
468  if (mutt_str_atoui(s, &uid) < 0)
469  {
470  mutt_debug(LL_DEBUG1, "Illegal UID. Skipping update\n");
471  return;
472  }
473  if (uid != imap_edata_get(e)->uid)
474  {
475  mutt_debug(LL_DEBUG1, "UID vs MSN mismatch. Skipping update\n");
476  return;
477  }
478  uid_checked = 1;
479  if (flags)
480  break;
481  s = imap_next_word(s);
482  }
483  else if ((plen = mutt_istr_startswith(s, "MODSEQ")))
484  {
485  s += plen;
486  SKIPWS(s);
487  if (*s != '(')
488  {
489  mutt_debug(LL_DEBUG1, "bogus MODSEQ response: %s\n", s);
490  return;
491  }
492  s++;
493  while (*s && (*s != ')'))
494  s++;
495  if (*s == ')')
496  s++;
497  else
498  {
499  mutt_debug(LL_DEBUG1, "Unterminated MODSEQ response: %s\n", s);
500  return;
501  }
502  }
503  else if (*s == ')')
504  break; /* end of request */
505  else if (*s)
506  {
507  mutt_debug(LL_DEBUG2, "Only handle FLAGS updates\n");
508  break;
509  }
510  }
511 
512  if (flags)
513  {
514  imap_set_flags(adata->mailbox, e, flags, &server_changes);
515  if (server_changes)
516  {
517  /* If server flags could conflict with NeoMutt's flags, reopen the mailbox. */
518  if (e->changed)
519  mdata->reopen |= IMAP_EXPUNGE_PENDING;
520  else
522  }
523  }
524 }
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:98
The envelope/body of an email.
Definition: email.h:37
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
#define IMAP_FLAGS_PENDING
Flags have changed on the server.
Definition: private.h:69
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:222
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
bool changed
Email has been edited.
Definition: email.h:48
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
unsigned int max_msn
the largest MSN fetched so far
Definition: private.h:239
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
Log at debug level 2.
Definition: logging.h:41
ImapOpenFlags check_status
Flags, e.g. IMAP_NEWMAIL_PENDING.
Definition: private.h:223
#define SKIPWS(ch)
Definition: string2.h:46
void * mdata
Driver specific data.
Definition: mailbox.h:136
bool active
Message is not to be removed.
Definition: email.h:59
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:287
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: private.h:216
char * imap_set_flags(struct Mailbox *m, struct Email *e, char *s, bool *server_changes)
fill the message header according to the server flags
Definition: message.c:1824
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:67
Log at debug level 3.
Definition: logging.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_capability()

static void cmd_parse_capability ( struct ImapAccountData adata,
char *  s 
)
static

set capability bits according to CAPABILITY response

Parameters
adataImap Account data
sCommand string with capabilities

Definition at line 531 of file command.c.

532 {
533  mutt_debug(LL_DEBUG3, "Handling CAPABILITY\n");
534 
535  s = imap_next_word(s);
536  char *bracket = strchr(s, ']');
537  if (bracket)
538  *bracket = '\0';
539  FREE(&adata->capstr);
540  adata->capstr = mutt_str_dup(s);
541  adata->capabilities = 0;
542 
543  while (*s)
544  {
545  for (size_t i = 0; Capabilities[i]; i++)
546  {
547  size_t len = mutt_istr_startswith(s, Capabilities[i]);
548  if (len != 0 && ((s[len] == '\0') || IS_SPACE(s[len])))
549  {
550  adata->capabilities |= (1 << i);
551  mutt_debug(LL_DEBUG3, " Found capability \"%s\": %lu\n", Capabilities[i], i);
552  break;
553  }
554  }
555  s = imap_next_word(s);
556  }
557 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
char * capstr
Definition: private.h:184
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
ImapCapFlags capabilities
Definition: private.h:185
#define IS_SPACE(ch)
Definition: string2.h:38
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:42
static const char *const Capabilities[]
Server capabilities strings that we understand.
Definition: command.c:62
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_list()

static void cmd_parse_list ( struct ImapAccountData adata,
char *  s 
)
static

Parse a server LIST command (list mailboxes)

Parameters
adataImap Account data
sCommand string with folder list

Definition at line 564 of file command.c.

565 {
566  struct ImapList *list = NULL;
567  struct ImapList lb = { 0 };
568  char delimbuf[5]; /* worst case: "\\"\0 */
569  unsigned int litlen;
570 
571  if (adata->cmdresult)
572  list = adata->cmdresult;
573  else
574  list = &lb;
575 
576  memset(list, 0, sizeof(struct ImapList));
577 
578  /* flags */
579  s = imap_next_word(s);
580  if (*s != '(')
581  {
582  mutt_debug(LL_DEBUG1, "Bad LIST response\n");
583  return;
584  }
585  s++;
586  while (*s)
587  {
588  if (mutt_istr_startswith(s, "\\NoSelect"))
589  list->noselect = true;
590  else if (mutt_istr_startswith(s, "\\NonExistent")) /* rfc5258 */
591  list->noselect = true;
592  else if (mutt_istr_startswith(s, "\\NoInferiors"))
593  list->noinferiors = true;
594  else if (mutt_istr_startswith(s, "\\HasNoChildren")) /* rfc5258*/
595  list->noinferiors = true;
596 
597  s = imap_next_word(s);
598  if (*(s - 2) == ')')
599  break;
600  }
601 
602  /* Delimiter */
603  if (!mutt_istr_startswith(s, "NIL"))
604  {
605  delimbuf[0] = '\0';
606  mutt_str_cat(delimbuf, 5, s);
607  imap_unquote_string(delimbuf);
608  list->delim = delimbuf[0];
609  }
610 
611  /* Name */
612  s = imap_next_word(s);
613  /* Notes often responds with literals here. We need a real tokenizer. */
614  if (imap_get_literal_count(s, &litlen) == 0)
615  {
616  if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
617  {
618  adata->status = IMAP_FATAL;
619  return;
620  }
621 
622  if (strlen(adata->buf) < litlen)
623  {
624  mutt_debug(LL_DEBUG1, "Error parsing LIST mailbox\n");
625  return;
626  }
627 
628  list->name = adata->buf;
629  s = list->name + litlen;
630  if (s[0] != '\0')
631  {
632  s[0] = '\0';
633  s++;
634  SKIPWS(s);
635  }
636  }
637  else
638  {
639  list->name = s;
640  /* Exclude rfc5258 RECURSIVEMATCH CHILDINFO suffix */
641  s = imap_next_word(s);
642  if (s[0] != '\0')
643  s[-1] = '\0';
644  imap_unmunge_mbox_name(adata->unicode, list->name);
645  }
646 
647  if (list->name[0] == '\0')
648  {
649  adata->delim = list->delim;
650  mutt_debug(LL_DEBUG3, "Root delimiter: %c\n", adata->delim);
651  }
652 }
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
Unrecoverable error occurred.
Definition: private.h:96
Items in an IMAP browser.
Definition: private.h:147
char delim
Definition: private.h:150
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
#define SKIPWS(ch)
Definition: string2.h:46
void imap_unquote_string(char *s)
equally stupid unquoting routine
Definition: util.c:1008
char * name
Definition: private.h:149
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:175
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
bool noinferiors
Definition: private.h:152
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:390
int imap_get_literal_count(const char *buf, unsigned int *bytes)
write number of bytes in an IMAP literal into bytes
Definition: util.c:879
Log at debug level 1.
Definition: logging.h:40
char * buf
Definition: private.h:189
struct ImapList * cmdresult
Definition: private.h:196
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
void imap_unmunge_mbox_name(bool unicode, char *s)
Remove quoting from a mailbox name.
Definition: util.c:1062
Log at debug level 3.
Definition: logging.h:42
bool noselect
Definition: private.h:151
bool unicode
If true, we can send UTF-8, and the server will use UTF8 rather than mUTF7.
Definition: private.h:192
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_lsub()

static void cmd_parse_lsub ( struct ImapAccountData adata,
char *  s 
)
static

Parse a server LSUB (list subscribed mailboxes)

Parameters
adataImap Account data
sCommand string with folder list

Definition at line 659 of file command.c.

660 {
661  char buf[256];
662  char quoted_name[256];
663  struct Buffer err;
664  struct Url url = { 0 };
665  struct ImapList list = { 0 };
666 
667  if (adata->cmdresult)
668  {
669  /* caller will handle response itself */
670  cmd_parse_list(adata, s);
671  return;
672  }
673 
675  return;
676 
677  adata->cmdresult = &list;
678  cmd_parse_list(adata, s);
679  adata->cmdresult = NULL;
680  /* noselect is for a gmail quirk */
681  if (!list.name || list.noselect)
682  return;
683 
684  mutt_debug(LL_DEBUG3, "Subscribing to %s\n", list.name);
685 
686  mutt_str_copy(buf, "mailboxes \"", sizeof(buf));
687  mutt_account_tourl(&adata->conn->account, &url);
688  /* escape \ and " */
689  imap_quote_string(quoted_name, sizeof(quoted_name), list.name, true);
690  url.path = quoted_name + 1;
691  url.path[strlen(url.path) - 1] = '\0';
692  if (mutt_str_equal(url.user, C_ImapUser))
693  url.user = NULL;
694  url_tostring(&url, buf + 11, sizeof(buf) - 11, 0);
695  mutt_str_cat(buf, sizeof(buf), "\"");
696  mutt_buffer_init(&err);
697  err.dsize = 256;
698  err.data = mutt_mem_malloc(err.dsize);
699  if (mutt_parse_rc_line(buf, &err))
700  mutt_debug(LL_DEBUG1, "Error adding subscribed mailbox: %s\n", err.data);
701  FREE(&err.data);
702 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:66
String manipulation buffer.
Definition: buffer.h:33
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:1041
Items in an IMAP browser.
Definition: private.h:147
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:79
char * C_ImapUser
Config: (imap) Username for the IMAP server.
Definition: config.c:58
char * user
Username.
Definition: url.h:69
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
char * name
Definition: private.h:149
bool C_ImapCheckSubscribed
Config: (imap) When opening a mailbox, ask the server for a list of subscribed folders.
Definition: config.c:37
char * path
Path.
Definition: url.h:73
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:390
Log at debug level 1.
Definition: logging.h:40
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:721
#define FREE(x)
Definition: memory.h:40
int url_tostring(struct Url *url, char *dest, size_t len, int flags)
Output the URL string for a given Url object.
Definition: url.c:418
struct ImapList * cmdresult
Definition: private.h:196
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
static void cmd_parse_list(struct ImapAccountData *adata, char *s)
Parse a server LIST command (list mailboxes)
Definition: command.c:564
Log at debug level 3.
Definition: logging.h:42
bool noselect
Definition: private.h:151
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
quote string according to IMAP rules
Definition: util.c:971
struct Connection * conn
Definition: private.h:171
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_myrights()

static void cmd_parse_myrights ( struct ImapAccountData adata,
const char *  s 
)
static

Set rights bits according to MYRIGHTS response.

Parameters
adataImap Account data
sCommand string with rights info

Definition at line 709 of file command.c.

710 {
711  mutt_debug(LL_DEBUG2, "Handling MYRIGHTS\n");
712 
713  s = imap_next_word((char *) s);
714  s = imap_next_word((char *) s);
715 
716  /* zero out current rights set */
717  adata->mailbox->rights = 0;
718 
719  while (*s && !isspace((unsigned char) *s))
720  {
721  switch (*s)
722  {
723  case 'a':
724  adata->mailbox->rights |= MUTT_ACL_ADMIN;
725  break;
726  case 'e':
727  adata->mailbox->rights |= MUTT_ACL_EXPUNGE;
728  break;
729  case 'i':
730  adata->mailbox->rights |= MUTT_ACL_INSERT;
731  break;
732  case 'k':
733  adata->mailbox->rights |= MUTT_ACL_CREATE;
734  break;
735  case 'l':
736  adata->mailbox->rights |= MUTT_ACL_LOOKUP;
737  break;
738  case 'p':
739  adata->mailbox->rights |= MUTT_ACL_POST;
740  break;
741  case 'r':
742  adata->mailbox->rights |= MUTT_ACL_READ;
743  break;
744  case 's':
745  adata->mailbox->rights |= MUTT_ACL_SEEN;
746  break;
747  case 't':
748  adata->mailbox->rights |= MUTT_ACL_DELETE;
749  break;
750  case 'w':
751  adata->mailbox->rights |= MUTT_ACL_WRITE;
752  break;
753  case 'x':
754  adata->mailbox->rights |= MUTT_ACL_DELMX;
755  break;
756 
757  /* obsolete rights */
758  case 'c':
760  break;
761  case 'd':
763  break;
764  default:
765  mutt_debug(LL_DEBUG1, "Unknown right: %c\n", *s);
766  }
767  s++;
768  }
769 }
#define MUTT_ACL_READ
Read the mailbox.
Definition: mailbox.h:72
#define MUTT_ACL_CREATE
Create a mailbox.
Definition: mailbox.h:65
#define MUTT_ACL_DELMX
Delete a mailbox.
Definition: mailbox.h:67
#define MUTT_ACL_INSERT
Add/copy into the mailbox (used when editing a message)
Definition: mailbox.h:69
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
#define MUTT_ACL_EXPUNGE
Expunge messages.
Definition: mailbox.h:68
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:66
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
Log at debug level 2.
Definition: logging.h:41
#define MUTT_ACL_POST
Post (submit messages to the server)
Definition: mailbox.h:71
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:74
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
Log at debug level 1.
Definition: logging.h:40
#define MUTT_ACL_ADMIN
Administer the account (get/set permissions)
Definition: mailbox.h:64
#define MUTT_ACL_SEEN
Change the &#39;seen&#39; status of a message.
Definition: mailbox.h:73
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define MUTT_ACL_LOOKUP
Lookup mailbox (visible to &#39;list&#39;)
Definition: mailbox.h:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_mailbox()

static struct Mailbox* find_mailbox ( struct ImapAccountData adata,
const char *  name 
)
static

Find a Mailbox by its name.

Parameters
adataImap Account data
nameMailbox to find
Return values
ptrMailbox

Definition at line 777 of file command.c.

778 {
779  if (!adata || !adata->account || !name)
780  return NULL;
781 
782  struct MailboxNode *np = NULL;
783  STAILQ_FOREACH(np, &adata->account->mailboxes, entries)
784  {
785  struct ImapMboxData *mdata = imap_mdata_get(np->mailbox);
786  if (mutt_str_equal(name, mdata->name))
787  return np->mailbox;
788  }
789 
790  return NULL;
791 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
struct MailboxList mailboxes
List of Mailboxes.
Definition: account.h:41
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct Account * account
Parent Account.
Definition: private.h:208
char * name
Definition: private.h:149
char * name
Mailbox name.
Definition: private.h:218
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
IMAP-specific Mailbox data -.
Definition: private.h:216
List of Mailboxes.
Definition: mailbox.h:150
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:152
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_status()

static void cmd_parse_status ( struct ImapAccountData adata,
char *  s 
)
static

Parse status from server.

Parameters
adataImap Account data
sCommand string with status info

first cut: just do mailbox update. Later we may wish to cache all mailbox information, even that not desired by mailbox

Definition at line 801 of file command.c.

802 {
803  unsigned int litlen = 0;
804 
805  char *mailbox = imap_next_word(s);
806 
807  /* We need a real tokenizer. */
808  if (imap_get_literal_count(mailbox, &litlen) == 0)
809  {
810  if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
811  {
812  adata->status = IMAP_FATAL;
813  return;
814  }
815 
816  if (strlen(adata->buf) < litlen)
817  {
818  mutt_debug(LL_DEBUG1, "Error parsing STATUS mailbox\n");
819  return;
820  }
821 
822  mailbox = adata->buf;
823  s = mailbox + litlen;
824  s[0] = '\0';
825  s++;
826  SKIPWS(s);
827  }
828  else
829  {
830  s = imap_next_word(mailbox);
831  s[-1] = '\0';
832  imap_unmunge_mbox_name(adata->unicode, mailbox);
833  }
834 
835  struct Mailbox *m = find_mailbox(adata, mailbox);
836  struct ImapMboxData *mdata = imap_mdata_get(m);
837  if (!mdata)
838  {
839  mutt_debug(LL_DEBUG3, "Received status for an unexpected mailbox: %s\n", mailbox);
840  return;
841  }
842  uint32_t olduv = mdata->uidvalidity;
843  unsigned int oldun = mdata->uid_next;
844 
845  if (*s++ != '(')
846  {
847  mutt_debug(LL_DEBUG1, "Error parsing STATUS\n");
848  return;
849  }
850  while ((s[0] != '\0') && (s[0] != ')'))
851  {
852  char *value = imap_next_word(s);
853 
854  errno = 0;
855  const unsigned long ulcount = strtoul(value, &value, 10);
856  if (((errno == ERANGE) && (ulcount == ULONG_MAX)) || ((unsigned int) ulcount != ulcount))
857  {
858  mutt_debug(LL_DEBUG1, "Error parsing STATUS number\n");
859  return;
860  }
861  const unsigned int count = (unsigned int) ulcount;
862 
863  if (mutt_str_startswith(s, "MESSAGES"))
864  mdata->messages = count;
865  else if (mutt_str_startswith(s, "RECENT"))
866  mdata->recent = count;
867  else if (mutt_str_startswith(s, "UIDNEXT"))
868  mdata->uid_next = count;
869  else if (mutt_str_startswith(s, "UIDVALIDITY"))
870  mdata->uidvalidity = count;
871  else if (mutt_str_startswith(s, "UNSEEN"))
872  mdata->unseen = count;
873 
874  s = value;
875  if ((s[0] != '\0') && (*s != ')'))
876  s = imap_next_word(s);
877  }
878  mutt_debug(LL_DEBUG3, "%s (UIDVALIDITY: %u, UIDNEXT: %u) %d messages, %d recent, %d unseen\n",
879  mdata->name, mdata->uidvalidity, mdata->uid_next, mdata->messages,
880  mdata->recent, mdata->unseen);
881 
882  mutt_debug(LL_DEBUG3, "Running default STATUS handler\n");
883 
884  mutt_debug(LL_DEBUG3, "Found %s in mailbox list (OV: %u ON: %u U: %d)\n",
885  mailbox, olduv, oldun, mdata->unseen);
886 
887  bool new_mail = false;
888  if (C_MailCheckRecent)
889  {
890  if ((olduv != 0) && (olduv == mdata->uidvalidity))
891  {
892  if (oldun < mdata->uid_next)
893  new_mail = (mdata->unseen > 0);
894  }
895  else if ((olduv == 0) && (oldun == 0))
896  {
897  /* first check per session, use recent. might need a flag for this. */
898  new_mail = (mdata->recent > 0);
899  }
900  else
901  new_mail = (mdata->unseen > 0);
902  }
903  else
904  new_mail = (mdata->unseen > 0);
905 
906 #ifdef USE_SIDEBAR
907  if ((m->has_new != new_mail) || (m->msg_count != mdata->messages) ||
908  (m->msg_unread != mdata->unseen))
909  {
911  }
912 #endif
913 
914  m->has_new = new_mail;
915  m->msg_count = mdata->messages;
916  m->msg_unread = mdata->unseen;
917 
918  // force back to keep detecting new mail until the mailbox is opened
919  if (m->has_new)
920  mdata->uid_next = oldun;
921 }
int msg_count
Total number of messages.
Definition: mailbox.h:91
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
if(!test_colorize_)
Definition: acutest.h:499
uint32_t uidvalidity
Definition: private.h:228
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
Unrecoverable error occurred.
Definition: private.h:96
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:49
bool has_new
Mailbox has new mail.
Definition: mailbox.h:88
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
static struct Mailbox * find_mailbox(struct ImapAccountData *adata, const char *name)
Find a Mailbox by its name.
Definition: command.c:777
#define SKIPWS(ch)
Definition: string2.h:46
void * mdata
Driver specific data.
Definition: mailbox.h:136
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:165
A mailbox.
Definition: mailbox.h:81
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:175
char * name
Mailbox name.
Definition: private.h:218
WHERE bool C_MailCheckRecent
Config: Notify the user about new mail since the last time the mailbox was opened.
Definition: mutt_globals.h:152
int imap_get_literal_count(const char *buf, unsigned int *bytes)
write number of bytes in an IMAP literal into bytes
Definition: util.c:879
unsigned int uid_next
Definition: private.h:229
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: private.h:216
char * buf
Definition: private.h:189
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
unsigned int unseen
Definition: private.h:233
unsigned int recent
Definition: private.h:232
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
void imap_unmunge_mbox_name(bool unicode, char *s)
Remove quoting from a mailbox name.
Definition: util.c:1062
Log at debug level 3.
Definition: logging.h:42
unsigned int messages
Definition: private.h:231
bool unicode
If true, we can send UTF-8, and the server will use UTF8 rather than mUTF7.
Definition: private.h:192
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_enabled()

static void cmd_parse_enabled ( struct ImapAccountData adata,
const char *  s 
)
static

Record what the server has enabled.

Parameters
adataImap Account data
sCommand string containing acceptable encodings

Definition at line 928 of file command.c.

929 {
930  mutt_debug(LL_DEBUG2, "Handling ENABLED\n");
931 
932  while ((s = imap_next_word((char *) s)) && (*s != '\0'))
933  {
934  if (mutt_istr_startswith(s, "UTF8=ACCEPT") ||
935  mutt_istr_startswith(s, "UTF8=ONLY"))
936  {
937  adata->unicode = true;
938  }
939  if (mutt_istr_startswith(s, "QRESYNC"))
940  adata->qresync = true;
941  }
942 }
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
Log at debug level 2.
Definition: logging.h:41
bool qresync
true, if QRESYNC is successfully ENABLE&#39;d
Definition: private.h:193
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
bool unicode
If true, we can send UTF-8, and the server will use UTF8 rather than mUTF7.
Definition: private.h:192
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_exists()

static void cmd_parse_exists ( struct ImapAccountData adata,
const char *  pn 
)
static

Parse EXISTS message from serer.

Parameters
adataImap Account data
pnString containing the total number of messages for the selected mailbox

Definition at line 948 of file command.c.

949 {
950  unsigned int count = 0;
951  mutt_debug(LL_DEBUG2, "Handling EXISTS\n");
952 
953  if (mutt_str_atoui(pn, &count) < 0)
954  {
955  mutt_debug(LL_DEBUG1, "Malformed EXISTS: '%s'\n", pn);
956  return;
957  }
958 
959  struct ImapMboxData *mdata = adata->mailbox->mdata;
960 
961  /* new mail arrived */
962  if (count < mdata->max_msn)
963  {
964  /* Notes 6.0.3 has a tendency to report fewer messages exist than
965  * it should. */
966  mutt_debug(LL_DEBUG1, "Message count is out of sync\n");
967  }
968  /* at least the InterChange server sends EXISTS messages freely,
969  * even when there is no new mail */
970  else if (count == mdata->max_msn)
971  mutt_debug(LL_DEBUG3, "superfluous EXISTS message\n");
972  else
973  {
974  mutt_debug(LL_DEBUG2, "New mail in %s - %d messages total\n", mdata->name, count);
975  mdata->reopen |= IMAP_NEWMAIL_PENDING;
976  mdata->new_mail_count = count;
977  }
978 }
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:222
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
unsigned int max_msn
the largest MSN fetched so far
Definition: private.h:239
unsigned int new_mail_count
Set when EXISTS notifies of new mail.
Definition: private.h:224
Log at debug level 2.
Definition: logging.h:41
void * mdata
Driver specific data.
Definition: mailbox.h:136
char * name
Mailbox name.
Definition: private.h:218
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:287
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: private.h:216
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: private.h:68
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_handle_untagged()

static int cmd_handle_untagged ( struct ImapAccountData adata)
static

fallback parser for otherwise unhandled messages

Parameters
adataImap Account data
Return values
0Success
-1Failure

Definition at line 986 of file command.c.

987 {
988  char *s = imap_next_word(adata->buf);
989  char *pn = imap_next_word(s);
990 
991  if ((adata->state >= IMAP_SELECTED) && isdigit((unsigned char) *s))
992  {
993  /* pn vs. s: need initial seqno */
994  pn = s;
995  s = imap_next_word(s);
996 
997  /* EXISTS, EXPUNGE, FETCH are always related to the SELECTED mailbox */
998  if (mutt_istr_startswith(s, "EXISTS"))
999  cmd_parse_exists(adata, pn);
1000  else if (mutt_istr_startswith(s, "EXPUNGE"))
1001  cmd_parse_expunge(adata, pn);
1002  else if (mutt_istr_startswith(s, "FETCH"))
1003  cmd_parse_fetch(adata, pn);
1004  }
1005  else if ((adata->state >= IMAP_SELECTED) &&
1006  mutt_istr_startswith(s, "VANISHED"))
1007  cmd_parse_vanished(adata, pn);
1008  else if (mutt_istr_startswith(s, "CAPABILITY"))
1009  cmd_parse_capability(adata, s);
1010  else if (mutt_istr_startswith(s, "OK [CAPABILITY"))
1011  cmd_parse_capability(adata, pn);
1012  else if (mutt_istr_startswith(pn, "OK [CAPABILITY"))
1014  else if (mutt_istr_startswith(s, "LIST"))
1015  cmd_parse_list(adata, s);
1016  else if (mutt_istr_startswith(s, "LSUB"))
1017  cmd_parse_lsub(adata, s);
1018  else if (mutt_istr_startswith(s, "MYRIGHTS"))
1019  cmd_parse_myrights(adata, s);
1020  else if (mutt_istr_startswith(s, "SEARCH"))
1021  cmd_parse_search(adata, s);
1022  else if (mutt_istr_startswith(s, "STATUS"))
1023  cmd_parse_status(adata, s);
1024  else if (mutt_istr_startswith(s, "ENABLED"))
1025  cmd_parse_enabled(adata, s);
1026  else if (mutt_istr_startswith(s, "BYE"))
1027  {
1028  mutt_debug(LL_DEBUG2, "Handling BYE\n");
1029 
1030  /* check if we're logging out */
1031  if (adata->status == IMAP_BYE)
1032  return 0;
1033 
1034  /* server shut down our connection */
1035  s += 3;
1036  SKIPWS(s);
1037  mutt_error("%s", s);
1038  cmd_handle_fatal(adata);
1039 
1040  return -1;
1041  }
1042  else if (C_ImapServernoise && mutt_istr_startswith(s, "NO"))
1043  {
1044  mutt_debug(LL_DEBUG2, "Handling untagged NO\n");
1045 
1046  /* Display the warning message from the server */
1047  mutt_error("%s", s + 2);
1048  }
1049 
1050  return 0;
1051 }
Logged out from server.
Definition: private.h:97
static void cmd_parse_capability(struct ImapAccountData *adata, char *s)
set capability bits according to CAPABILITY response
Definition: command.c:531
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: private.h:174
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:162
void cmd_parse_search(struct ImapAccountData *adata, const char *s)
store SEARCH response for later use
Definition: search.c:258
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
Log at debug level 2.
Definition: logging.h:41
#define SKIPWS(ch)
Definition: string2.h:46
Mailbox is selected.
Definition: private.h:109
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:175
static void cmd_parse_enabled(struct ImapAccountData *adata, const char *s)
Record what the server has enabled.
Definition: command.c:928
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
bool C_ImapServernoise
Config: (imap) Display server warnings as error messages.
Definition: config.c:57
static void cmd_parse_myrights(struct ImapAccountData *adata, const char *s)
Set rights bits according to MYRIGHTS response.
Definition: command.c:709
static void cmd_parse_lsub(struct ImapAccountData *adata, char *s)
Parse a server LSUB (list subscribed mailboxes)
Definition: command.c:659
char * buf
Definition: private.h:189
static void cmd_parse_fetch(struct ImapAccountData *adata, char *s)
Load fetch response into ImapAccountData.
Definition: command.c:393
#define mutt_error(...)
Definition: logging.h:84
static void cmd_parse_expunge(struct ImapAccountData *adata, const char *s)
Parse expunge command.
Definition: command.c:254
static void cmd_parse_vanished(struct ImapAccountData *adata, char *s)
Parse vanished command.
Definition: command.c:299
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static void cmd_parse_list(struct ImapAccountData *adata, char *s)
Parse a server LIST command (list mailboxes)
Definition: command.c:564
static void cmd_parse_exists(struct ImapAccountData *adata, const char *pn)
Parse EXISTS message from serer.
Definition: command.c:948
static void cmd_parse_status(struct ImapAccountData *adata, char *s)
Parse status from server.
Definition: command.c:801
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cmd_start()

int imap_cmd_start ( struct ImapAccountData adata,
const char *  cmdstr 
)

Given an IMAP command, send it to the server.

Parameters
adataImap Account data
cmdstrCommand string to send
Return values
0Success
<0Failure, e.g. IMAP_RES_BAD

If cmdstr is NULL, sends queued commands.

Definition at line 1062 of file command.c.

1063 {
1064  return cmd_start(adata, cmdstr, IMAP_CMD_NO_FLAGS);
1065 }
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: private.h:72
static int cmd_start(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Start a new IMAP command.
Definition: command.c:198
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cmd_step()

int imap_cmd_step ( struct ImapAccountData adata)

Reads server responses from an IMAP command.

Parameters
adataImap Account data
Return values
0Success
<0Failure, e.g. IMAP_RES_BAD

detects tagged completion response, handles untagged messages, can read arbitrarily large strings (using malloc, so don't make it too large!).

Definition at line 1076 of file command.c.

1077 {
1078  if (!adata)
1079  return -1;
1080 
1081  size_t len = 0;
1082  int c;
1083  int rc;
1084  int stillrunning = 0;
1085  struct ImapCommand *cmd = NULL;
1086 
1087  if (adata->status == IMAP_FATAL)
1088  {
1089  cmd_handle_fatal(adata);
1090  return IMAP_RES_BAD;
1091  }
1092 
1093  /* read into buffer, expanding buffer as necessary until we have a full
1094  * line */
1095  do
1096  {
1097  if (len == adata->blen)
1098  {
1099  mutt_mem_realloc(&adata->buf, adata->blen + IMAP_CMD_BUFSIZE);
1100  adata->blen = adata->blen + IMAP_CMD_BUFSIZE;
1101  mutt_debug(LL_DEBUG3, "grew buffer to %lu bytes\n", adata->blen);
1102  }
1103 
1104  /* back up over '\0' */
1105  if (len)
1106  len--;
1107  c = mutt_socket_readln_d(adata->buf + len, adata->blen - len, adata->conn, MUTT_SOCK_LOG_FULL);
1108  if (c <= 0)
1109  {
1110  mutt_debug(LL_DEBUG1, "Error reading server response\n");
1111  cmd_handle_fatal(adata);
1112  return IMAP_RES_BAD;
1113  }
1114 
1115  len += c;
1116  }
1117  /* if we've read all the way to the end of the buffer, we haven't read a
1118  * full line (mutt_socket_readln strips the \r, so we always have at least
1119  * one character free when we've read a full line) */
1120  while (len == adata->blen);
1121 
1122  /* don't let one large string make cmd->buf hog memory forever */
1123  if ((adata->blen > IMAP_CMD_BUFSIZE) && (len <= IMAP_CMD_BUFSIZE))
1124  {
1126  adata->blen = IMAP_CMD_BUFSIZE;
1127  mutt_debug(LL_DEBUG3, "shrank buffer to %lu bytes\n", adata->blen);
1128  }
1129 
1130  adata->lastread = mutt_date_epoch();
1131 
1132  /* handle untagged messages. The caller still gets its shot afterwards. */
1133  if ((mutt_str_startswith(adata->buf, "* ") ||
1134  mutt_str_startswith(imap_next_word(adata->buf), "OK [")) &&
1135  cmd_handle_untagged(adata))
1136  {
1137  return IMAP_RES_BAD;
1138  }
1139 
1140  /* server demands a continuation response from us */
1141  if (adata->buf[0] == '+')
1142  return IMAP_RES_RESPOND;
1143 
1144  /* Look for tagged command completions.
1145  *
1146  * Some response handlers can end up recursively calling
1147  * imap_cmd_step() and end up handling all tagged command
1148  * completions.
1149  * (e.g. FETCH->set_flag->set_header_color->~h pattern match.)
1150  *
1151  * Other callers don't even create an adata->cmds entry.
1152  *
1153  * For both these cases, we default to returning OK */
1154  rc = IMAP_RES_OK;
1155  c = adata->lastcmd;
1156  do
1157  {
1158  cmd = &adata->cmds[c];
1159  if (cmd->state == IMAP_RES_NEW)
1160  {
1161  if (mutt_str_startswith(adata->buf, cmd->seq))
1162  {
1163  if (!stillrunning)
1164  {
1165  /* first command in queue has finished - move queue pointer up */
1166  adata->lastcmd = (adata->lastcmd + 1) % adata->cmdslots;
1167  }
1168  cmd->state = cmd_status(adata->buf);
1169  rc = cmd->state;
1170  if (cmd->state == IMAP_RES_NO || cmd->state == IMAP_RES_BAD)
1171  {
1172  mutt_message(_("IMAP command failed: %s"), adata->buf);
1173  }
1174  }
1175  else
1176  stillrunning++;
1177  }
1178 
1179  c = (c + 1) % adata->cmdslots;
1180  } while (c != adata->nextcmd);
1181 
1182  if (stillrunning)
1183  rc = IMAP_RES_CONTINUE;
1184  else
1185  {
1186  mutt_debug(LL_DEBUG3, "IMAP queue drained\n");
1187  imap_cmd_finish(adata);
1188  }
1189 
1190  return rc;
1191 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:416
struct ImapCommand * cmds
Definition: private.h:199
#define IMAP_RES_RESPOND
+
Definition: private.h:57
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
#define mutt_message(...)
Definition: logging.h:83
#define IMAP_RES_NEW
ImapCommand.state additions.
Definition: private.h:58
Unrecoverable error occurred.
Definition: private.h:96
#define _(a)
Definition: message.h:28
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:162
size_t blen
Definition: private.h:190
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:31
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
IMAP command structure.
Definition: private.h:158
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:165
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:175
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition: command.c:1311
#define IMAP_CMD_BUFSIZE
Definition: command.c:55
char seq[SEQ_LEN+1]
Command tag, e.g. &#39;a0001&#39;.
Definition: private.h:160
#define IMAP_RES_NO
<tag> NO ...
Definition: private.h:53
time_t lastread
last time we read a command for the server
Definition: private.h:188
Log at debug level 1.
Definition: logging.h:40
int state
Command state, e.g. IMAP_RES_NEW.
Definition: private.h:161
char * buf
Definition: private.h:189
static int cmd_handle_untagged(struct ImapAccountData *adata)
fallback parser for otherwise unhandled messages
Definition: command.c:986
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition: socket.c:245
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
Log at debug level 3.
Definition: logging.h:42
struct Connection * conn
Definition: private.h:171
#define IMAP_RES_BAD
<tag> BAD ...
Definition: private.h:54
static int cmd_status(const char *s)
parse response line for tagged OK/NO/BAD
Definition: command.c:234
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_code()

bool imap_code ( const char *  s)

Was the command successful.

Parameters
sIMAP command status
Return values
1Command result was OK
0If NO or BAD

Definition at line 1199 of file command.c.

1200 {
1201  return cmd_status(s) == IMAP_RES_OK;
1202 }
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
static int cmd_status(const char *s)
parse response line for tagged OK/NO/BAD
Definition: command.c:234
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cmd_trailer()

const char* imap_cmd_trailer ( struct ImapAccountData adata)

Extra information after tagged command response if any.

Parameters
adataImap Account data
Return values
ptrExtra command information (pointer into adata->buf)
""Error (static string)

Definition at line 1210 of file command.c.

1211 {
1212  static const char *notrailer = "";
1213  const char *s = adata->buf;
1214 
1215  if (!s)
1216  {
1217  mutt_debug(LL_DEBUG2, "not a tagged response\n");
1218  return notrailer;
1219  }
1220 
1221  s = imap_next_word((char *) s);
1222  if (!s || (!mutt_istr_startswith(s, "OK") && !mutt_istr_startswith(s, "NO") &&
1223  !mutt_istr_startswith(s, "BAD")))
1224  {
1225  mutt_debug(LL_DEBUG2, "not a command completion: %s\n", adata->buf);
1226  return notrailer;
1227  }
1228 
1229  s = imap_next_word((char *) s);
1230  if (!s)
1231  return notrailer;
1232 
1233  return s;
1234 }
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
Log at debug level 2.
Definition: logging.h:41
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
char * buf
Definition: private.h:189
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_exec()

int imap_exec ( struct ImapAccountData adata,
const char *  cmdstr,
ImapCmdFlags  flags 
)

Execute a command and wait for the response from the server.

Parameters
adataImap Account data
cmdstrCommand to execute
flagsFlags, see ImapCmdFlags
Return values
IMAP_EXEC_SUCCESSCommand successful or queued
IMAP_EXEC_ERRORCommand returned an error
IMAP_EXEC_FATALImap connection failure

Also, handle untagged responses.

Definition at line 1247 of file command.c.

1248 {
1249  int rc;
1250 
1251  if (flags & IMAP_CMD_SINGLE)
1252  {
1253  // Process any existing commands
1254  if (adata->nextcmd != adata->lastcmd)
1255  imap_exec(adata, NULL, IMAP_CMD_POLL);
1256  }
1257 
1258  rc = cmd_start(adata, cmdstr, flags);
1259  if (rc < 0)
1260  {
1261  cmd_handle_fatal(adata);
1262  return IMAP_EXEC_FATAL;
1263  }
1264 
1265  if (flags & IMAP_CMD_QUEUE)
1266  return IMAP_EXEC_SUCCESS;
1267 
1268  if ((flags & IMAP_CMD_POLL) && (C_ImapPollTimeout > 0) &&
1269  ((mutt_socket_poll(adata->conn, C_ImapPollTimeout)) == 0))
1270  {
1271  mutt_error(_("Connection to %s timed out"), adata->conn->account.host);
1272  cmd_handle_fatal(adata);
1273  return IMAP_EXEC_FATAL;
1274  }
1275 
1276  /* Allow interruptions, particularly useful if there are network problems. */
1278  do
1279  {
1280  rc = imap_cmd_step(adata);
1281  // The queue is empty, so the single command has been processed
1282  if ((flags & IMAP_CMD_SINGLE) && (adata->nextcmd == adata->lastcmd))
1283  break;
1284  } while (rc == IMAP_RES_CONTINUE);
1285  mutt_sig_allow_interrupt(false);
1286 
1287  if (rc == IMAP_RES_NO)
1288  return IMAP_EXEC_ERROR;
1289  if (rc != IMAP_RES_OK)
1290  {
1291  if (adata->status != IMAP_FATAL)
1292  return IMAP_EXEC_ERROR;
1293 
1294  mutt_debug(LL_DEBUG1, "command failed: %s\n", adata->buf);
1295  return IMAP_EXEC_FATAL;
1296  }
1297 
1298  return IMAP_EXEC_SUCCESS;
1299 }
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
Imap connection failure.
Definition: private.h:85
Unrecoverable error occurred.
Definition: private.h:96
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: private.h:75
#define _(a)
Definition: message.h:28
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:162
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition: signal.c:238
Imap command executed or queued successfully.
Definition: private.h:83
char host[128]
Server to login to.
Definition: connaccount.h:53
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:191
short C_ImapPollTimeout
Config: (imap) Maximum time to wait for a server response.
Definition: config.c:54
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
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:175
#define IMAP_RES_NO
<tag> NO ...
Definition: private.h:53
Imap command failure.
Definition: private.h:84
Log at debug level 1.
Definition: logging.h:40
char * buf
Definition: private.h:189
#define mutt_error(...)
Definition: logging.h:84
static int cmd_start(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Start a new IMAP command.
Definition: command.c:198
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: private.h:74
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
#define IMAP_CMD_SINGLE
Run a single command.
Definition: private.h:76
struct Connection * conn
Definition: private.h:171
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cmd_finish()

void imap_cmd_finish ( struct ImapAccountData adata)

Attempt to perform cleanup.

Parameters
adataImap Account data

If a reopen is allowed, it attempts to perform cleanup (eg fetch new mail if detected, do expunge). Called automatically by imap_cmd_step(), but may be called at any time.

mdata->check_status is set and will be used later by imap_check_mailbox().

Definition at line 1311 of file command.c.

1312 {
1313  if (!adata)
1314  return;
1315 
1316  if (adata->status == IMAP_FATAL)
1317  {
1318  adata->closing = false;
1319  cmd_handle_fatal(adata);
1320  return;
1321  }
1322 
1323  if (!(adata->state >= IMAP_SELECTED) || (adata->mailbox && adata->closing))
1324  {
1325  adata->closing = false;
1326  return;
1327  }
1328 
1329  adata->closing = false;
1330 
1331  struct ImapMboxData *mdata = imap_mdata_get(adata->mailbox);
1332 
1333  if (mdata && mdata->reopen & IMAP_REOPEN_ALLOW)
1334  {
1335  // First remove expunged emails from the msn_index
1336  if (mdata->reopen & IMAP_EXPUNGE_PENDING)
1337  {
1338  mutt_debug(LL_DEBUG2, "Expunging mailbox\n");
1339  imap_expunge_mailbox(adata->mailbox);
1340  /* Detect whether we've gotten unexpected EXPUNGE messages */
1341  if (!(mdata->reopen & IMAP_EXPUNGE_EXPECTED))
1344  }
1345 
1346  // Then add new emails to it
1347  if (mdata->reopen & IMAP_NEWMAIL_PENDING && (mdata->new_mail_count > mdata->max_msn))
1348  {
1349  if (!(mdata->reopen & IMAP_EXPUNGE_PENDING))
1351 
1352  mutt_debug(LL_DEBUG2, "Fetching new mails from %d to %d\n",
1353  mdata->max_msn + 1, mdata->new_mail_count);
1354  imap_read_headers(adata->mailbox, mdata->max_msn + 1, mdata->new_mail_count, false);
1355  }
1356 
1357  // And to finish inform about MUTT_REOPEN if needed
1358  if (mdata->reopen & IMAP_EXPUNGE_PENDING && !(mdata->reopen & IMAP_EXPUNGE_EXPECTED))
1360 
1361  if (mdata->reopen & IMAP_EXPUNGE_PENDING)
1363  }
1364 
1365  adata->status = 0;
1366 }
Unrecoverable error occurred.
Definition: private.h:96
void imap_expunge_mailbox(struct Mailbox *m)
Purge messages from the server.
Definition: imap.c:631
#define IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition: private.h:65
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: private.h:174
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:222
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:162
unsigned int max_msn
the largest MSN fetched so far
Definition: private.h:239
unsigned int new_mail_count
Set when EXISTS notifies of new mail.
Definition: private.h:224
Log at debug level 2.
Definition: logging.h:41
int imap_read_headers(struct Mailbox *m, unsigned int msn_begin, unsigned int msn_end, bool initial_download)
Read headers from the server.
Definition: message.c:1284
ImapOpenFlags check_status
Flags, e.g. IMAP_NEWMAIL_PENDING.
Definition: private.h:223
Mailbox is selected.
Definition: private.h:109
void * mdata
Driver specific data.
Definition: mailbox.h:136
bool closing
If true, we are waiting for CLOSE completion.
Definition: private.h:173
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:175
#define IMAP_EXPUNGE_EXPECTED
Messages will be expunged from the server.
Definition: private.h:66
IMAP-specific Mailbox data -.
Definition: private.h:216
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: private.h:68
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:67
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cmd_idle()

int imap_cmd_idle ( struct ImapAccountData adata)

Enter the IDLE state.

Parameters
adataImap Account data
Return values
0Success
<0Failure, e.g. IMAP_RES_BAD

Definition at line 1374 of file command.c.

1375 {
1376  int rc;
1377 
1378  if (cmd_start(adata, "IDLE", IMAP_CMD_POLL) < 0)
1379  {
1380  cmd_handle_fatal(adata);
1381  return -1;
1382  }
1383 
1384  if ((C_ImapPollTimeout > 0) && ((mutt_socket_poll(adata->conn, C_ImapPollTimeout)) == 0))
1385  {
1386  mutt_error(_("Connection to %s timed out"), adata->conn->account.host);
1387  cmd_handle_fatal(adata);
1388  return -1;
1389  }
1390 
1391  do
1392  {
1393  rc = imap_cmd_step(adata);
1394  } while (rc == IMAP_RES_CONTINUE);
1395 
1396  if (rc == IMAP_RES_RESPOND)
1397  {
1398  /* successfully entered IDLE state */
1399  adata->state = IMAP_IDLE;
1400  /* queue automatic exit when next command is issued */
1401  mutt_buffer_addstr(&adata->cmdbuf, "DONE\r\n");
1402  rc = IMAP_RES_OK;
1403  }
1404  if (rc != IMAP_RES_OK)
1405  {
1406  mutt_debug(LL_DEBUG1, "error starting IDLE\n");
1407  return -1;
1408  }
1409 
1410  return 0;
1411 }
#define IMAP_RES_RESPOND
+
Definition: private.h:57
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: private.h:174
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: private.h:75
#define _(a)
Definition: message.h:28
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:162
char host[128]
Server to login to.
Definition: connaccount.h:53
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:191
struct Buffer cmdbuf
Definition: private.h:203
short C_ImapPollTimeout
Config: (imap) Maximum time to wait for a server response.
Definition: config.c:54
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
Connection is idle.
Definition: private.h:112
Log at debug level 1.
Definition: logging.h:40
#define mutt_error(...)
Definition: logging.h:84
static int cmd_start(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Start a new IMAP command.
Definition: command.c:198
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
struct Connection * conn
Definition: private.h:171
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ Capabilities

const char* const Capabilities[]
static
Initial value:
= {
"IMAP4",
"IMAP4rev1",
"STATUS",
"ACL",
"NAMESPACE",
"AUTH=CRAM-MD5",
"AUTH=GSSAPI",
"AUTH=ANONYMOUS",
"AUTH=OAUTHBEARER",
"STARTTLS",
"LOGINDISABLED",
"IDLE",
"SASL-IR",
"ENABLE",
"CONDSTORE",
"QRESYNC",
"LIST-EXTENDED",
"COMPRESS=DEFLATE",
"X-GM-EXT-1",
NULL,
}

Server capabilities strings that we understand.

Note
This must be kept in the same order as ImapCaps.

Definition at line 62 of file command.c.