NeoMutt  2019-12-07-168-gc45f47
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "imap_private.h"
#include "mutt/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "conn/lib.h"
#include "mutt.h"
#include "globals.h"
#include "message.h"
#include "mutt_account.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 void cmd_parse_search (struct ImapAccountData *adata, const char *s)
 store SEARCH response for later use 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

bool C_ImapServernoise
 Config: (imap) Display server warnings as error messages. More...
 
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 57 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 92 of file command.c.

93 {
94  if (((adata->nextcmd + 1) % adata->cmdslots) == adata->lastcmd)
95  return true;
96 
97  return false;
98 }
+ 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 106 of file command.c.

107 {
108  struct ImapCommand *cmd = NULL;
109 
110  if (cmd_queue_full(adata))
111  {
112  mutt_debug(LL_DEBUG3, "IMAP command queue full\n");
113  return NULL;
114  }
115 
116  cmd = adata->cmds + adata->nextcmd;
117  adata->nextcmd = (adata->nextcmd + 1) % adata->cmdslots;
118 
119  snprintf(cmd->seq, sizeof(cmd->seq), "%c%04u", adata->seqid, adata->seqno++);
120  if (adata->seqno > 9999)
121  adata->seqno = 0;
122 
123  cmd->state = IMAP_RES_NEW;
124 
125  return cmd;
126 }
struct ImapCommand * cmds
Definition: imap_private.h:198
unsigned int seqno
tag sequence number, e.g. &#39;{seqid}0001&#39;
Definition: imap_private.h:185
#define IMAP_RES_NEW
ImapCommand.state additions.
Definition: imap_private.h:57
unsigned char seqid
Definition: imap_private.h:184
IMAP command structure.
Definition: imap_private.h:156
char seq[SEQ_LEN+1]
Command tag, e.g. &#39;a0001&#39;.
Definition: imap_private.h:158
int state
Command state, e.g. IMAP_RES_NEW.
Definition: imap_private.h:159
#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:92
+ 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 138 of file command.c.

139 {
140  if (cmd_queue_full(adata))
141  {
142  mutt_debug(LL_DEBUG3, "Draining IMAP command pipeline\n");
143 
144  const int rc = imap_exec(adata, NULL, flags & IMAP_CMD_POLL);
145 
146  if (rc == IMAP_EXEC_ERROR)
147  return IMAP_RES_BAD;
148  }
149 
150  struct ImapCommand *cmd = cmd_new(adata);
151  if (!cmd)
152  return IMAP_RES_BAD;
153 
154  if (mutt_buffer_add_printf(&adata->cmdbuf, "%s %s\r\n", cmd->seq, cmdstr) < 0)
155  return IMAP_RES_BAD;
156 
157  return 0;
158 }
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: imap_private.h:74
static struct ImapCommand * cmd_new(struct ImapAccountData *adata)
Create and queue a new command control block.
Definition: command.c:106
struct Buffer cmdbuf
Definition: imap_private.h:202
IMAP command structure.
Definition: imap_private.h:156
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:1270
char seq[SEQ_LEN+1]
Command tag, e.g. &#39;a0001&#39;.
Definition: imap_private.h:158
#define IMAP_RES_BAD
<tag> BAD ...
Definition: imap_private.h:53
#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:92
Imap command failure.
Definition: imap_private.h:82
+ 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 164 of file command.c.

165 {
166  adata->status = IMAP_FATAL;
167 
168  if (!adata->mailbox)
169  return;
170 
171  struct ImapMboxData *mdata = adata->mailbox->mdata;
172 
173  if ((adata->state >= IMAP_SELECTED) && (mdata->reopen & IMAP_REOPEN_ALLOW))
174  {
176  mutt_socket_close(adata->conn);
177  mutt_error(_("Mailbox %s@%s closed"), adata->conn->account.user,
178  adata->conn->account.host);
179  adata->state = IMAP_DISCONNECTED;
180  }
181 
182  imap_close_connection(adata);
183  if (!adata->recovering)
184  {
185  adata->recovering = true;
186  if (imap_login(adata))
188  adata->recovering = false;
189  }
190 }
struct ConnAccount account
Definition: connection.h:36
Mailbox is selected.
Definition: imap_private.h:107
int imap_login(struct ImapAccountData *adata)
Open an IMAP connection.
Definition: imap.c:1962
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: imap_private.h:172
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: imap_private.h:220
char user[128]
Definition: connaccount.h:60
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: imap_private.h:205
void imap_close_connection(struct ImapAccountData *adata)
Close an IMAP connection.
Definition: imap.c:949
char host[128]
Definition: connaccount.h:63
void mx_fastclose_mailbox(struct Mailbox *m)
free up memory associated with the Mailbox
Definition: mx.c:412
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:135
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: imap_private.h:173
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:95
IMAP-specific Mailbox data -.
Definition: imap_private.h:214
#define mutt_error(...)
Definition: logging.h:84
Unrecoverable error occurred.
Definition: imap_private.h:94
Disconnected from server.
Definition: imap_private.h:104
#define IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition: imap_private.h:64
struct Connection * conn
Definition: imap_private.h:169
+ 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 200 of file command.c.

201 {
202  int rc;
203 
204  if (adata->status == IMAP_FATAL)
205  {
206  cmd_handle_fatal(adata);
207  return -1;
208  }
209 
210  if (cmdstr && ((rc = cmd_queue(adata, cmdstr, flags)) < 0))
211  return rc;
212 
213  if (flags & IMAP_CMD_QUEUE)
214  return 0;
215 
216  if (mutt_buffer_is_empty(&adata->cmdbuf))
217  return IMAP_RES_BAD;
218 
219  rc = mutt_socket_send_d(adata->conn, adata->cmdbuf.data,
221  mutt_buffer_reset(&adata->cmdbuf);
222 
223  /* unidle when command queue is flushed */
224  if (adata->state == IMAP_IDLE)
225  adata->state = IMAP_SELECTED;
226 
227  return (rc < 0) ? IMAP_RES_BAD : 0;
228 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
#define IMAP_LOG_PASS
Definition: imap_private.h:49
Mailbox is selected.
Definition: imap_private.h:107
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: imap_private.h:172
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:164
Connection is idle.
Definition: imap_private.h:110
struct Buffer cmdbuf
Definition: imap_private.h:202
#define mutt_socket_send_d(conn, buf, dbg)
Definition: mutt_socket.h:39
static int cmd_queue(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Add a IMAP command to the queue.
Definition: command.c:138
struct ListHead flags
Definition: imap_private.h:225
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: imap_private.h:173
char * data
Pointer to data.
Definition: buffer.h:35
#define IMAP_LOG_CMD
Definition: imap_private.h:47
#define IMAP_CMD_PASS
Command contains a password. Suppress logging.
Definition: imap_private.h:72
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: imap_private.h:73
#define IMAP_RES_BAD
<tag> BAD ...
Definition: imap_private.h:53
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Unrecoverable error occurred.
Definition: imap_private.h:94
struct Connection * conn
Definition: imap_private.h:169
+ 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 236 of file command.c.

237 {
238  s = imap_next_word((char *) s);
239 
240  if (mutt_str_startswith(s, "OK", CASE_IGNORE))
241  return IMAP_RES_OK;
242  if (mutt_str_startswith(s, "NO", CASE_IGNORE))
243  return IMAP_RES_NO;
244 
245  return IMAP_RES_BAD;
246 }
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:937
#define IMAP_RES_NO
<tag> NO ...
Definition: imap_private.h:52
Ignore case when comparing strings.
Definition: string2.h:68
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
#define IMAP_RES_BAD
<tag> BAD ...
Definition: imap_private.h:53
#define IMAP_RES_OK
<tag> OK ...
Definition: imap_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 256 of file command.c.

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

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

396 {
397  unsigned int msn, uid;
398  struct Email *e = NULL;
399  char *flags = NULL;
400  int uid_checked = 0;
401  bool server_changes = false;
402 
403  struct ImapMboxData *mdata = imap_mdata_get(adata->mailbox);
404 
405  mutt_debug(LL_DEBUG3, "Handling FETCH\n");
406 
407  if (mutt_str_atoui(s, &msn) < 0)
408  {
409  mutt_debug(LL_DEBUG3, "Skipping FETCH response - illegal MSN\n");
410  return;
411  }
412 
413  if ((msn < 1) || (msn > mdata->max_msn))
414  {
415  mutt_debug(LL_DEBUG3, "Skipping FETCH response - MSN %u out of range\n", msn);
416  return;
417  }
418 
419  e = mdata->msn_index[msn - 1];
420  if (!e || !e->active)
421  {
422  mutt_debug(LL_DEBUG3, "Skipping FETCH response - MSN %u not in msn_index\n", msn);
423  return;
424  }
425 
426  mutt_debug(LL_DEBUG2, "Message UID %u updated\n", imap_edata_get(e)->uid);
427  /* skip FETCH */
428  s = imap_next_word(s);
429  s = imap_next_word(s);
430 
431  if (*s != '(')
432  {
433  mutt_debug(LL_DEBUG1, "Malformed FETCH response\n");
434  return;
435  }
436  s++;
437 
438  while (*s)
439  {
440  SKIPWS(s);
441  size_t plen = mutt_str_startswith(s, "FLAGS", CASE_IGNORE);
442  if (plen != 0)
443  {
444  flags = s;
445  if (uid_checked)
446  break;
447 
448  s += plen;
449  SKIPWS(s);
450  if (*s != '(')
451  {
452  mutt_debug(LL_DEBUG1, "bogus FLAGS response: %s\n", s);
453  return;
454  }
455  s++;
456  while (*s && (*s != ')'))
457  s++;
458  if (*s == ')')
459  s++;
460  else
461  {
462  mutt_debug(LL_DEBUG1, "Unterminated FLAGS response: %s\n", s);
463  return;
464  }
465  }
466  else if ((plen = mutt_str_startswith(s, "UID", CASE_IGNORE)))
467  {
468  s += plen;
469  SKIPWS(s);
470  if (mutt_str_atoui(s, &uid) < 0)
471  {
472  mutt_debug(LL_DEBUG1, "Illegal UID. Skipping update\n");
473  return;
474  }
475  if (uid != imap_edata_get(e)->uid)
476  {
477  mutt_debug(LL_DEBUG1, "UID vs MSN mismatch. Skipping update\n");
478  return;
479  }
480  uid_checked = 1;
481  if (flags)
482  break;
483  s = imap_next_word(s);
484  }
485  else if ((plen = mutt_str_startswith(s, "MODSEQ", CASE_IGNORE)))
486  {
487  s += plen;
488  SKIPWS(s);
489  if (*s != '(')
490  {
491  mutt_debug(LL_DEBUG1, "bogus MODSEQ response: %s\n", s);
492  return;
493  }
494  s++;
495  while (*s && (*s != ')'))
496  s++;
497  if (*s == ')')
498  s++;
499  else
500  {
501  mutt_debug(LL_DEBUG1, "Unterminated MODSEQ response: %s\n", s);
502  return;
503  }
504  }
505  else if (*s == ')')
506  break; /* end of request */
507  else if (*s)
508  {
509  mutt_debug(LL_DEBUG2, "Only handle FLAGS updates\n");
510  break;
511  }
512  }
513 
514  if (flags)
515  {
516  imap_set_flags(adata->mailbox, e, flags, &server_changes);
517  if (server_changes)
518  {
519  /* If server flags could conflict with NeoMutt's flags, reopen the mailbox. */
520  if (e->changed)
521  mdata->reopen |= IMAP_EXPUNGE_PENDING;
522  else
524  }
525  }
526 }
The envelope/body of an email.
Definition: email.h:37
struct Email ** msn_index
look up headers by (MSN-1)
Definition: imap_private.h:235
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: imap_private.h:66
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:100
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
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:1810
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: imap_private.h:220
#define IMAP_FLAGS_PENDING
Flags have changed on the server.
Definition: imap_private.h:68
struct Mailbox * mailbox
Definition: imap_private.h:205
bool changed
Email has been edited.
Definition: email.h:48
unsigned int max_msn
the largest MSN fetched so far
Definition: imap_private.h:237
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:251
Log at debug level 2.
Definition: logging.h:41
ImapOpenFlags check_status
Flags, e.g. IMAP_NEWMAIL_PENDING.
Definition: imap_private.h:221
#define SKIPWS(ch)
Definition: string2.h:47
void * mdata
Driver specific data.
Definition: mailbox.h:135
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:937
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:292
Ignore case when comparing strings.
Definition: string2.h:68
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: imap_private.h:214
#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_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 533 of file command.c.

534 {
535  mutt_debug(LL_DEBUG3, "Handling CAPABILITY\n");
536 
537  s = imap_next_word(s);
538  char *bracket = strchr(s, ']');
539  if (bracket)
540  *bracket = '\0';
541  FREE(&adata->capstr);
542  adata->capstr = mutt_str_strdup(s);
543  adata->capabilities = 0;
544 
545  while (*s)
546  {
547  for (size_t i = 0; Capabilities[i]; i++)
548  {
549  if (mutt_str_word_casecmp(Capabilities[i], s) == 0)
550  {
551  adata->capabilities |= (1 << i);
552  mutt_debug(LL_DEBUG3, " Found capability \"%s\": %lu\n", Capabilities[i], i);
553  break;
554  }
555  }
556  s = imap_next_word(s);
557  }
558 }
int mutt_str_word_casecmp(const char *a, const char *b)
Find word a in word list b.
Definition: string.c:996
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:937
ImapCapFlags capabilities
Definition: imap_private.h:183
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#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:64
+ 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 565 of file command.c.

566 {
567  struct ImapList *list = NULL;
568  struct ImapList lb = { 0 };
569  char delimbuf[5]; /* worst case: "\\"\0 */
570  unsigned int litlen;
571 
572  if (adata->cmdresult)
573  list = adata->cmdresult;
574  else
575  list = &lb;
576 
577  memset(list, 0, sizeof(struct ImapList));
578 
579  /* flags */
580  s = imap_next_word(s);
581  if (*s != '(')
582  {
583  mutt_debug(LL_DEBUG1, "Bad LIST response\n");
584  return;
585  }
586  s++;
587  while (*s)
588  {
589  if (mutt_str_startswith(s, "\\NoSelect", CASE_IGNORE))
590  list->noselect = true;
591  else if (mutt_str_startswith(s, "\\NonExistent", CASE_IGNORE)) /* rfc5258 */
592  list->noselect = true;
593  else if (mutt_str_startswith(s, "\\NoInferiors", CASE_IGNORE))
594  list->noinferiors = true;
595  else if (mutt_str_startswith(s, "\\HasNoChildren", CASE_IGNORE)) /* rfc5258*/
596  list->noinferiors = true;
597 
598  s = imap_next_word(s);
599  if (*(s - 2) == ')')
600  break;
601  }
602 
603  /* Delimiter */
604  if (!mutt_str_startswith(s, "NIL", CASE_IGNORE))
605  {
606  delimbuf[0] = '\0';
607  mutt_str_strcat(delimbuf, 5, s);
608  imap_unquote_string(delimbuf);
609  list->delim = delimbuf[0];
610  }
611 
612  /* Name */
613  s = imap_next_word(s);
614  /* Notes often responds with literals here. We need a real tokenizer. */
615  if (imap_get_literal_count(s, &litlen) == 0)
616  {
617  if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
618  {
619  adata->status = IMAP_FATAL;
620  return;
621  }
622 
623  if (strlen(adata->buf) < litlen)
624  {
625  mutt_debug(LL_DEBUG1, "Error parsing LIST mailbox\n");
626  return;
627  }
628 
629  list->name = adata->buf;
630  s = list->name + litlen;
631  if (s[0] != '\0')
632  {
633  s[0] = '\0';
634  s++;
635  SKIPWS(s);
636  }
637  }
638  else
639  {
640  list->name = s;
641  /* Exclude rfc5258 RECURSIVEMATCH CHILDINFO suffix */
642  s = imap_next_word(s);
643  if (s[0] != '\0')
644  s[-1] = '\0';
645  imap_unmunge_mbox_name(adata->unicode, list->name);
646  }
647 
648  if (list->name[0] == '\0')
649  {
650  adata->delim = list->delim;
651  mutt_debug(LL_DEBUG3, "Root delimiter: %c\n", adata->delim);
652  }
653 }
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1100
void imap_unmunge_mbox_name(bool unicode, char *s)
Remove quoting from a mailbox name.
Definition: util.c:1076
Items in an IMAP browser.
Definition: imap_private.h:145
char delim
Definition: imap_private.h:148
#define SKIPWS(ch)
Definition: string2.h:47
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:937
char * name
Definition: imap_private.h:147
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: imap_private.h:173
void imap_unquote_string(char *s)
equally stupid unquoting routine
Definition: util.c:1022
Ignore case when comparing strings.
Definition: string2.h:68
bool noinferiors
Definition: imap_private.h:150
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
#define IMAP_RES_CONTINUE
* ...
Definition: imap_private.h:55
char * mutt_str_strcat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:395
Log at debug level 1.
Definition: logging.h:40
int imap_get_literal_count(const char *buf, unsigned int *bytes)
write number of bytes in an IMAP literal into bytes
Definition: util.c:893
struct ImapList * cmdresult
Definition: imap_private.h:195
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Unrecoverable error occurred.
Definition: imap_private.h:94
Log at debug level 3.
Definition: logging.h:42
bool noselect
Definition: imap_private.h:149
+ 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 660 of file command.c.

661 {
662  char buf[256];
663  char errstr[256];
664  struct Buffer err, token;
665  struct Url url = { 0 };
666  struct ImapList list = { 0 };
667 
668  if (adata->cmdresult)
669  {
670  /* caller will handle response itself */
671  cmd_parse_list(adata, s);
672  return;
673  }
674 
676  return;
677 
678  adata->cmdresult = &list;
679  cmd_parse_list(adata, s);
680  adata->cmdresult = NULL;
681  /* noselect is for a gmail quirk */
682  if (!list.name || list.noselect)
683  return;
684 
685  mutt_debug(LL_DEBUG3, "Subscribing to %s\n", list.name);
686 
687  mutt_str_strfcpy(buf, "mailboxes \"", sizeof(buf));
688  mutt_account_tourl(&adata->conn->account, &url);
689  /* escape \ and " */
690  imap_quote_string(errstr, sizeof(errstr), list.name, true);
691  url.path = errstr + 1;
692  url.path[strlen(url.path) - 1] = '\0';
693  if (mutt_str_strcmp(url.user, C_ImapUser) == 0)
694  url.user = NULL;
695  url_tostring(&url, buf + 11, sizeof(buf) - 11, 0);
696  mutt_str_strcat(buf, sizeof(buf), "\"");
697  mutt_buffer_init(&token);
698  mutt_buffer_init(&err);
699  err.data = errstr;
700  err.dsize = sizeof(errstr);
701  if (mutt_parse_rc_line(buf, &token, &err))
702  mutt_debug(LL_DEBUG1, "Error adding subscribed mailbox: %s\n", errstr);
703  FREE(&token.data);
704 }
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
quote string according to IMAP rules
Definition: util.c:985
struct ConnAccount account
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
WHERE char * C_ImapUser
Config: (imap) Username for the IMAP server.
Definition: globals.h:115
Items in an IMAP browser.
Definition: imap_private.h:145
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:85
char * user
Username.
Definition: url.h:69
char * name
Definition: imap_private.h:147
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:773
WHERE bool C_ImapCheckSubscribed
Config: (imap) When opening a mailbox, ask the server for a list of subscribed folders.
Definition: globals.h:222
char * path
Path.
Definition: url.h:73
char * mutt_str_strcat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:395
Log at debug level 1.
Definition: logging.h:40
#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:423
struct ImapList * cmdresult
Definition: imap_private.h:195
#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:565
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
Log at debug level 3.
Definition: logging.h:42
bool noselect
Definition: imap_private.h:149
enum CommandResult mutt_parse_rc_line(char *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:1001
struct Connection * conn
Definition: imap_private.h:169
+ 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 711 of file command.c.

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

◆ cmd_parse_search()

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

store SEARCH response for later use

Parameters
adataImap Account data
sCommand string with search results

Definition at line 778 of file command.c.

779 {
780  unsigned int uid;
781  struct Email *e = NULL;
782  struct ImapMboxData *mdata = adata->mailbox->mdata;
783 
784  mutt_debug(LL_DEBUG2, "Handling SEARCH\n");
785 
786  while ((s = imap_next_word((char *) s)) && (*s != '\0'))
787  {
788  if (mutt_str_atoui(s, &uid) < 0)
789  continue;
790  e = mutt_hash_int_find(mdata->uid_hash, uid);
791  if (e)
792  e->matched = true;
793  }
794 }
The envelope/body of an email.
Definition: email.h:37
struct Mailbox * mailbox
Definition: imap_private.h:205
void * mutt_hash_int_find(const struct Hash *table, unsigned int intkey)
Find the HashElem data in a Hash table element using a key.
Definition: hash.c:408
Log at debug level 2.
Definition: logging.h:41
void * mdata
Driver specific data.
Definition: mailbox.h:135
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:937
struct Hash * uid_hash
Definition: imap_private.h:234
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:292
IMAP-specific Mailbox data -.
Definition: imap_private.h:214
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
bool matched
Search matches this Email.
Definition: email.h:68
+ 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 802 of file command.c.

803 {
804  if (!adata || !adata->account || !name)
805  return NULL;
806 
807  struct MailboxNode *np = NULL;
808  STAILQ_FOREACH(np, &adata->account->mailboxes, entries)
809  {
810  struct ImapMboxData *mdata = imap_mdata_get(np->mailbox);
811  if (mutt_str_strcmp(name, mdata->name) == 0)
812  return np->mailbox;
813  }
814 
815  return NULL;
816 }
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:251
const char * name
Definition: pgpmicalg.c:46
void * mdata
Driver specific data.
Definition: mailbox.h:135
struct Account * account
Parent Account.
Definition: imap_private.h:206
char * name
Mailbox name.
Definition: imap_private.h:216
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
IMAP-specific Mailbox data -.
Definition: imap_private.h:214
List of Mailboxes.
Definition: mailbox.h:144
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:146
+ 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 826 of file command.c.

827 {
828  unsigned int litlen = 0;
829 
830  char *mailbox = imap_next_word(s);
831 
832  /* We need a real tokenizer. */
833  if (imap_get_literal_count(mailbox, &litlen) == 0)
834  {
835  if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
836  {
837  adata->status = IMAP_FATAL;
838  return;
839  }
840 
841  if (strlen(adata->buf) < litlen)
842  {
843  mutt_debug(LL_DEBUG1, "Error parsing STATUS mailbox\n");
844  return;
845  }
846 
847  mailbox = adata->buf;
848  s = mailbox + litlen;
849  s[0] = '\0';
850  s++;
851  SKIPWS(s);
852  }
853  else
854  {
855  s = imap_next_word(mailbox);
856  s[-1] = '\0';
857  imap_unmunge_mbox_name(adata->unicode, mailbox);
858  }
859 
860  struct Mailbox *m = find_mailbox(adata, mailbox);
861  struct ImapMboxData *mdata = imap_mdata_get(m);
862  if (!mdata)
863  {
864  mutt_debug(LL_DEBUG3, "Received status for an unexpected mailbox: %s\n", mailbox);
865  return;
866  }
867  unsigned int olduv = mdata->uid_validity;
868  unsigned int oldun = mdata->uid_next;
869 
870  if (*s++ != '(')
871  {
872  mutt_debug(LL_DEBUG1, "Error parsing STATUS\n");
873  return;
874  }
875  while ((s[0] != '\0') && (s[0] != ')'))
876  {
877  char *value = imap_next_word(s);
878 
879  errno = 0;
880  const unsigned long ulcount = strtoul(value, &value, 10);
881  if (((errno == ERANGE) && (ulcount == ULONG_MAX)) || ((unsigned int) ulcount != ulcount))
882  {
883  mutt_debug(LL_DEBUG1, "Error parsing STATUS number\n");
884  return;
885  }
886  const unsigned int count = (unsigned int) ulcount;
887 
888  if (mutt_str_startswith(s, "MESSAGES", CASE_MATCH))
889  mdata->messages = count;
890  else if (mutt_str_startswith(s, "RECENT", CASE_MATCH))
891  mdata->recent = count;
892  else if (mutt_str_startswith(s, "UIDNEXT", CASE_MATCH))
893  mdata->uid_next = count;
894  else if (mutt_str_startswith(s, "UIDVALIDITY", CASE_MATCH))
895  mdata->uid_validity = count;
896  else if (mutt_str_startswith(s, "UNSEEN", CASE_MATCH))
897  mdata->unseen = count;
898 
899  s = value;
900  if ((s[0] != '\0') && (*s != ')'))
901  s = imap_next_word(s);
902  }
903  mutt_debug(LL_DEBUG3, "%s (UIDVALIDITY: %u, UIDNEXT: %u) %d messages, %d recent, %d unseen\n",
904  mdata->name, mdata->uid_validity, mdata->uid_next, mdata->messages,
905  mdata->recent, mdata->unseen);
906 
907  mutt_debug(LL_DEBUG3, "Running default STATUS handler\n");
908 
909  mutt_debug(LL_DEBUG3, "Found %s in mailbox list (OV: %u ON: %u U: %d)\n",
910  mailbox, olduv, oldun, mdata->unseen);
911 
912  bool new_mail = false;
913  if (C_MailCheckRecent)
914  {
915  if ((olduv != 0) && (olduv == mdata->uid_validity))
916  {
917  if (oldun < mdata->uid_next)
918  new_mail = (mdata->unseen > 0);
919  }
920  else if ((olduv == 0) && (oldun == 0))
921  {
922  /* first check per session, use recent. might need a flag for this. */
923  new_mail = (mdata->recent > 0);
924  }
925  else
926  new_mail = (mdata->unseen > 0);
927  }
928  else
929  new_mail = (mdata->unseen > 0);
930 
931 #ifdef USE_SIDEBAR
932  if ((m->has_new != new_mail) || (m->msg_count != mdata->messages) ||
933  (m->msg_unread != mdata->unseen))
934  {
936  }
937 #endif
938 
939  m->has_new = new_mail;
940  m->msg_count = mdata->messages;
941  m->msg_unread = mdata->unseen;
942 
943  // force back to keep detecting new mail until the mailbox is opened
944  if (m->has_new)
945  mdata->uid_next = oldun;
946 }
int msg_count
Total number of messages.
Definition: mailbox.h:90
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1100
WHERE bool C_MailCheckRecent
Config: Notify the user about new mail since the last time the mailbox was opened.
Definition: globals.h:239
int msg_unread
Number of unread messages.
Definition: mailbox.h:91
void imap_unmunge_mbox_name(bool unicode, char *s)
Remove quoting from a mailbox name.
Definition: util.c:1076
Match case when comparing strings.
Definition: string2.h:67
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:51
bool has_new
Mailbox has new mail.
Definition: mailbox.h:87
static struct Mailbox * find_mailbox(struct ImapAccountData *adata, const char *name)
Find a Mailbox by its name.
Definition: command.c:802
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:251
#define SKIPWS(ch)
Definition: string2.h:47
void * mdata
Driver specific data.
Definition: mailbox.h:135
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:937
A mailbox.
Definition: mailbox.h:80
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: imap_private.h:173
char * name
Mailbox name.
Definition: imap_private.h:216
unsigned int uid_validity
Definition: imap_private.h:226
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
#define IMAP_RES_CONTINUE
* ...
Definition: imap_private.h:55
unsigned int uid_next
Definition: imap_private.h:227
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: imap_private.h:214
int imap_get_literal_count(const char *buf, unsigned int *bytes)
write number of bytes in an IMAP literal into bytes
Definition: util.c:893
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
unsigned int unseen
Definition: imap_private.h:231
unsigned int recent
Definition: imap_private.h:230
Unrecoverable error occurred.
Definition: imap_private.h:94
Log at debug level 3.
Definition: logging.h:42
unsigned int messages
Definition: imap_private.h:229
+ 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 953 of file command.c.

954 {
955  mutt_debug(LL_DEBUG2, "Handling ENABLED\n");
956 
957  while ((s = imap_next_word((char *) s)) && (*s != '\0'))
958  {
959  if (mutt_str_startswith(s, "UTF8=ACCEPT", CASE_IGNORE) ||
960  mutt_str_startswith(s, "UTF8=ONLY", CASE_IGNORE))
961  {
962  adata->unicode = true;
963  }
964  if (mutt_str_startswith(s, "QRESYNC", CASE_IGNORE))
965  adata->qresync = true;
966  }
967 }
Log at debug level 2.
Definition: logging.h:41
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:937
Ignore case when comparing strings.
Definition: string2.h:68
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ 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 973 of file command.c.

974 {
975  unsigned int count = 0;
976  mutt_debug(LL_DEBUG2, "Handling EXISTS\n");
977 
978  if (mutt_str_atoui(pn, &count) < 0)
979  {
980  mutt_debug(LL_DEBUG1, "Malformed EXISTS: '%s'\n", pn);
981  return;
982  }
983 
984  struct ImapMboxData *mdata = adata->mailbox->mdata;
985 
986  /* new mail arrived */
987  if (count < mdata->max_msn)
988  {
989  /* Notes 6.0.3 has a tendency to report fewer messages exist than
990  * it should. */
991  mutt_debug(LL_DEBUG1, "Message count is out of sync\n");
992  }
993  /* at least the InterChange server sends EXISTS messages freely,
994  * even when there is no new mail */
995  else if (count == mdata->max_msn)
996  mutt_debug(LL_DEBUG3, "superfluous EXISTS message\n");
997  else
998  {
999  mutt_debug(LL_DEBUG2, "New mail in %s - %d messages total\n", mdata->name, count);
1000  mdata->reopen |= IMAP_NEWMAIL_PENDING;
1001  mdata->new_mail_count = count;
1002  }
1003 }
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: imap_private.h:220
struct Mailbox * mailbox
Definition: imap_private.h:205
unsigned int max_msn
the largest MSN fetched so far
Definition: imap_private.h:237
unsigned int new_mail_count
Set when EXISTS notifies of new mail.
Definition: imap_private.h:222
Log at debug level 2.
Definition: logging.h:41
void * mdata
Driver specific data.
Definition: mailbox.h:135
char * name
Mailbox name.
Definition: imap_private.h:216
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:292
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: imap_private.h:214
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: imap_private.h:67
#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 1011 of file command.c.

1012 {
1013  char *s = imap_next_word(adata->buf);
1014  char *pn = imap_next_word(s);
1015 
1016  if ((adata->state >= IMAP_SELECTED) && isdigit((unsigned char) *s))
1017  {
1018  /* pn vs. s: need initial seqno */
1019  pn = s;
1020  s = imap_next_word(s);
1021 
1022  /* EXISTS, EXPUNGE, FETCH are always related to the SELECTED mailbox */
1023  if (mutt_str_startswith(s, "EXISTS", CASE_IGNORE))
1024  cmd_parse_exists(adata, pn);
1025  else if (mutt_str_startswith(s, "EXPUNGE", CASE_IGNORE))
1026  cmd_parse_expunge(adata, pn);
1027  else if (mutt_str_startswith(s, "FETCH", CASE_IGNORE))
1028  cmd_parse_fetch(adata, pn);
1029  }
1030  else if ((adata->state >= IMAP_SELECTED) && mutt_str_startswith(s, "VANISHED", CASE_IGNORE))
1031  cmd_parse_vanished(adata, pn);
1032  else if (mutt_str_startswith(s, "CAPABILITY", CASE_IGNORE))
1033  cmd_parse_capability(adata, s);
1034  else if (mutt_str_startswith(s, "OK [CAPABILITY", CASE_IGNORE))
1035  cmd_parse_capability(adata, pn);
1036  else if (mutt_str_startswith(pn, "OK [CAPABILITY", CASE_IGNORE))
1038  else if (mutt_str_startswith(s, "LIST", CASE_IGNORE))
1039  cmd_parse_list(adata, s);
1040  else if (mutt_str_startswith(s, "LSUB", CASE_IGNORE))
1041  cmd_parse_lsub(adata, s);
1042  else if (mutt_str_startswith(s, "MYRIGHTS", CASE_IGNORE))
1043  cmd_parse_myrights(adata, s);
1044  else if (mutt_str_startswith(s, "SEARCH", CASE_IGNORE))
1045  cmd_parse_search(adata, s);
1046  else if (mutt_str_startswith(s, "STATUS", CASE_IGNORE))
1047  cmd_parse_status(adata, s);
1048  else if (mutt_str_startswith(s, "ENABLED", CASE_IGNORE))
1049  cmd_parse_enabled(adata, s);
1050  else if (mutt_str_startswith(s, "BYE", CASE_IGNORE))
1051  {
1052  mutt_debug(LL_DEBUG2, "Handling BYE\n");
1053 
1054  /* check if we're logging out */
1055  if (adata->status == IMAP_BYE)
1056  return 0;
1057 
1058  /* server shut down our connection */
1059  s += 3;
1060  SKIPWS(s);
1061  mutt_error("%s", s);
1062  cmd_handle_fatal(adata);
1063 
1064  return -1;
1065  }
1066  else if (C_ImapServernoise && mutt_str_startswith(s, "NO", CASE_IGNORE))
1067  {
1068  mutt_debug(LL_DEBUG2, "Handling untagged NO\n");
1069 
1070  /* Display the warning message from the server */
1071  mutt_error("%s", s + 2);
1072  }
1073 
1074  return 0;
1075 }
Mailbox is selected.
Definition: imap_private.h:107
static void cmd_parse_capability(struct ImapAccountData *adata, char *s)
set capability bits according to CAPABILITY response
Definition: command.c:533
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: imap_private.h:172
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:164
Log at debug level 2.
Definition: logging.h:41
#define SKIPWS(ch)
Definition: string2.h:47
static void cmd_parse_search(struct ImapAccountData *adata, const char *s)
store SEARCH response for later use
Definition: command.c:778
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:937
bool C_ImapServernoise
Config: (imap) Display server warnings as error messages.
Definition: command.c:55
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: imap_private.h:173
Ignore case when comparing strings.
Definition: string2.h:68
static void cmd_parse_enabled(struct ImapAccountData *adata, const char *s)
Record what the server has enabled.
Definition: command.c:953
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
static void cmd_parse_myrights(struct ImapAccountData *adata, const char *s)
Set rights bits according to MYRIGHTS response.
Definition: command.c:711
static void cmd_parse_lsub(struct ImapAccountData *adata, char *s)
Parse a server LSUB (list subscribed mailboxes)
Definition: command.c:660
static void cmd_parse_fetch(struct ImapAccountData *adata, char *s)
Load fetch response into ImapAccountData.
Definition: command.c:395
#define mutt_error(...)
Definition: logging.h:84
static void cmd_parse_expunge(struct ImapAccountData *adata, const char *s)
Parse expunge command.
Definition: command.c:256
static void cmd_parse_vanished(struct ImapAccountData *adata, char *s)
Parse vanished command.
Definition: command.c:301
#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:565
Logged out from server.
Definition: imap_private.h:95
static void cmd_parse_exists(struct ImapAccountData *adata, const char *pn)
Parse EXISTS message from serer.
Definition: command.c:973
static void cmd_parse_status(struct ImapAccountData *adata, char *s)
Parse status from server.
Definition: command.c:826
+ 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 1086 of file command.c.

1087 {
1088  return cmd_start(adata, cmdstr, IMAP_CMD_NO_FLAGS);
1089 }
static int cmd_start(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Start a new IMAP command.
Definition: command.c:200
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: imap_private.h:71
+ 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 1100 of file command.c.

1101 {
1102  if (!adata)
1103  return -1;
1104 
1105  size_t len = 0;
1106  int c;
1107  int rc;
1108  int stillrunning = 0;
1109  struct ImapCommand *cmd = NULL;
1110 
1111  if (adata->status == IMAP_FATAL)
1112  {
1113  cmd_handle_fatal(adata);
1114  return IMAP_RES_BAD;
1115  }
1116 
1117  /* read into buffer, expanding buffer as necessary until we have a full
1118  * line */
1119  do
1120  {
1121  if (len == adata->blen)
1122  {
1123  mutt_mem_realloc(&adata->buf, adata->blen + IMAP_CMD_BUFSIZE);
1124  adata->blen = adata->blen + IMAP_CMD_BUFSIZE;
1125  mutt_debug(LL_DEBUG3, "grew buffer to %lu bytes\n", adata->blen);
1126  }
1127 
1128  /* back up over '\0' */
1129  if (len)
1130  len--;
1131  c = mutt_socket_readln_d(adata->buf + len, adata->blen - len, adata->conn, MUTT_SOCK_LOG_FULL);
1132  if (c <= 0)
1133  {
1134  mutt_debug(LL_DEBUG1, "Error reading server response\n");
1135  cmd_handle_fatal(adata);
1136  return IMAP_RES_BAD;
1137  }
1138 
1139  len += c;
1140  }
1141  /* if we've read all the way to the end of the buffer, we haven't read a
1142  * full line (mutt_socket_readln strips the \r, so we always have at least
1143  * one character free when we've read a full line) */
1144  while (len == adata->blen);
1145 
1146  /* don't let one large string make cmd->buf hog memory forever */
1147  if ((adata->blen > IMAP_CMD_BUFSIZE) && (len <= IMAP_CMD_BUFSIZE))
1148  {
1150  adata->blen = IMAP_CMD_BUFSIZE;
1151  mutt_debug(LL_DEBUG3, "shrank buffer to %lu bytes\n", adata->blen);
1152  }
1153 
1154  adata->lastread = mutt_date_epoch();
1155 
1156  /* handle untagged messages. The caller still gets its shot afterwards. */
1157  if ((mutt_str_startswith(adata->buf, "* ", CASE_MATCH) ||
1158  mutt_str_startswith(imap_next_word(adata->buf), "OK [", CASE_MATCH)) &&
1159  cmd_handle_untagged(adata))
1160  {
1161  return IMAP_RES_BAD;
1162  }
1163 
1164  /* server demands a continuation response from us */
1165  if (adata->buf[0] == '+')
1166  return IMAP_RES_RESPOND;
1167 
1168  /* Look for tagged command completions.
1169  *
1170  * Some response handlers can end up recursively calling
1171  * imap_cmd_step() and end up handling all tagged command
1172  * completions.
1173  * (e.g. FETCH->set_flag->set_header_color->~h pattern match.)
1174  *
1175  * Other callers don't even create an adata->cmds entry.
1176  *
1177  * For both these cases, we default to returning OK */
1178  rc = IMAP_RES_OK;
1179  c = adata->lastcmd;
1180  do
1181  {
1182  cmd = &adata->cmds[c];
1183  if (cmd->state == IMAP_RES_NEW)
1184  {
1185  if (mutt_str_startswith(adata->buf, cmd->seq, CASE_MATCH))
1186  {
1187  if (!stillrunning)
1188  {
1189  /* first command in queue has finished - move queue pointer up */
1190  adata->lastcmd = (adata->lastcmd + 1) % adata->cmdslots;
1191  }
1192  cmd->state = cmd_status(adata->buf);
1193  /* bogus - we don't know which command result to return here. Caller
1194  * should provide a tag. */
1195  rc = cmd->state;
1196  }
1197  else
1198  stillrunning++;
1199  }
1200 
1201  c = (c + 1) % adata->cmdslots;
1202  } while (c != adata->nextcmd);
1203 
1204  if (stillrunning)
1205  rc = IMAP_RES_CONTINUE;
1206  else
1207  {
1208  mutt_debug(LL_DEBUG3, "IMAP queue drained\n");
1209  imap_cmd_finish(adata);
1210  }
1211 
1212  return rc;
1213 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:411
struct ImapCommand * cmds
Definition: imap_private.h:198
#define IMAP_RES_NEW
ImapCommand.state additions.
Definition: imap_private.h:57
Match case when comparing strings.
Definition: string2.h:67
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:164
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:32
IMAP command structure.
Definition: imap_private.h:156
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:937
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: imap_private.h:173
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition: command.c:1324
#define IMAP_CMD_BUFSIZE
Definition: command.c:57
char seq[SEQ_LEN+1]
Command tag, e.g. &#39;a0001&#39;.
Definition: imap_private.h:158
time_t lastread
last time we read a command for the server
Definition: imap_private.h:186
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
#define IMAP_RES_CONTINUE
* ...
Definition: imap_private.h:55
Log at debug level 1.
Definition: logging.h:40
int state
Command state, e.g. IMAP_RES_NEW.
Definition: imap_private.h:159
static int cmd_handle_untagged(struct ImapAccountData *adata)
fallback parser for otherwise unhandled messages
Definition: command.c:1011
#define IMAP_RES_BAD
<tag> BAD ...
Definition: imap_private.h:53
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition: socket.c:244
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Unrecoverable error occurred.
Definition: imap_private.h:94
Log at debug level 3.
Definition: logging.h:42
struct Connection * conn
Definition: imap_private.h:169
#define IMAP_RES_OK
<tag> OK ...
Definition: imap_private.h:54
#define IMAP_RES_RESPOND
+
Definition: imap_private.h:56
static int cmd_status(const char *s)
parse response line for tagged OK/NO/BAD
Definition: command.c:236
+ 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 1221 of file command.c.

1222 {
1223  return cmd_status(s) == IMAP_RES_OK;
1224 }
#define IMAP_RES_OK
<tag> OK ...
Definition: imap_private.h:54
static int cmd_status(const char *s)
parse response line for tagged OK/NO/BAD
Definition: command.c:236
+ 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 1232 of file command.c.

1233 {
1234  static const char *notrailer = "";
1235  const char *s = adata->buf;
1236 
1237  if (!s)
1238  {
1239  mutt_debug(LL_DEBUG2, "not a tagged response\n");
1240  return notrailer;
1241  }
1242 
1243  s = imap_next_word((char *) s);
1244  if (!s || (!mutt_str_startswith(s, "OK", CASE_IGNORE) &&
1245  !mutt_str_startswith(s, "NO", CASE_IGNORE) &&
1246  !mutt_str_startswith(s, "BAD", CASE_IGNORE)))
1247  {
1248  mutt_debug(LL_DEBUG2, "not a command completion: %s\n", adata->buf);
1249  return notrailer;
1250  }
1251 
1252  s = imap_next_word((char *) s);
1253  if (!s)
1254  return notrailer;
1255 
1256  return s;
1257 }
Log at debug level 2.
Definition: logging.h:41
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:937
Ignore case when comparing strings.
Definition: string2.h:68
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
#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 1270 of file command.c.

1271 {
1272  int rc;
1273 
1274  rc = cmd_start(adata, cmdstr, flags);
1275  if (rc < 0)
1276  {
1277  cmd_handle_fatal(adata);
1278  return IMAP_EXEC_FATAL;
1279  }
1280 
1281  if (flags & IMAP_CMD_QUEUE)
1282  return IMAP_EXEC_SUCCESS;
1283 
1284  if ((flags & IMAP_CMD_POLL) && (C_ImapPollTimeout > 0) &&
1285  ((mutt_socket_poll(adata->conn, C_ImapPollTimeout)) == 0))
1286  {
1287  mutt_error(_("Connection to %s timed out"), adata->conn->account.host);
1288  cmd_handle_fatal(adata);
1289  return IMAP_EXEC_FATAL;
1290  }
1291 
1292  /* Allow interruptions, particularly useful if there are network problems. */
1294  do
1295  {
1296  rc = imap_cmd_step(adata);
1297  } while (rc == IMAP_RES_CONTINUE);
1298  mutt_sig_allow_interrupt(false);
1299 
1300  if (rc == IMAP_RES_NO)
1301  return IMAP_EXEC_ERROR;
1302  if (rc != IMAP_RES_OK)
1303  {
1304  if (adata->status != IMAP_FATAL)
1305  return IMAP_EXEC_ERROR;
1306 
1307  mutt_debug(LL_DEBUG1, "command failed: %s\n", adata->buf);
1308  return IMAP_EXEC_FATAL;
1309  }
1310 
1311  return IMAP_EXEC_SUCCESS;
1312 }
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1100
struct ConnAccount account
Definition: connection.h:36
WHERE short C_ImapPollTimeout
Config: (imap) Maximum time to wait for a server response.
Definition: globals.h:156
#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:164
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: imap_private.h:74
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition: signal.c:238
Imap command executed or queued successfully.
Definition: imap_private.h:81
char host[128]
Definition: connaccount.h:63
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:190
#define IMAP_RES_NO
<tag> NO ...
Definition: imap_private.h:52
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: imap_private.h:173
Imap connection failure.
Definition: imap_private.h:83
#define IMAP_RES_CONTINUE
* ...
Definition: imap_private.h:55
Log at debug level 1.
Definition: logging.h:40
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: imap_private.h:73
#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:200
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Unrecoverable error occurred.
Definition: imap_private.h:94
struct Connection * conn
Definition: imap_private.h:169
#define IMAP_RES_OK
<tag> OK ...
Definition: imap_private.h:54
Imap command failure.
Definition: imap_private.h:82
+ 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 1324 of file command.c.

1325 {
1326  if (!adata)
1327  return;
1328 
1329  if (adata->status == IMAP_FATAL)
1330  {
1331  adata->closing = false;
1332  cmd_handle_fatal(adata);
1333  return;
1334  }
1335 
1336  if (!(adata->state >= IMAP_SELECTED) || (adata->mailbox && adata->closing))
1337  {
1338  adata->closing = false;
1339  return;
1340  }
1341 
1342  adata->closing = false;
1343 
1344  struct ImapMboxData *mdata = imap_mdata_get(adata->mailbox);
1345 
1346  if (mdata && mdata->reopen & IMAP_REOPEN_ALLOW)
1347  {
1348  // First remove expunged emails from the msn_index
1349  if (mdata->reopen & IMAP_EXPUNGE_PENDING)
1350  {
1351  mutt_debug(LL_DEBUG2, "Expunging mailbox\n");
1352  imap_expunge_mailbox(adata->mailbox);
1353  /* Detect whether we've gotten unexpected EXPUNGE messages */
1354  if (!(mdata->reopen & IMAP_EXPUNGE_EXPECTED))
1357  }
1358 
1359  // Then add new emails to it
1360  if (mdata->reopen & IMAP_NEWMAIL_PENDING && (mdata->new_mail_count > mdata->max_msn))
1361  {
1362  if (!(mdata->reopen & IMAP_EXPUNGE_PENDING))
1364 
1365  mutt_debug(LL_DEBUG2, "Fetching new mails from %d to %d\n",
1366  mdata->max_msn + 1, mdata->new_mail_count);
1367  imap_read_headers(adata->mailbox, mdata->max_msn + 1, mdata->new_mail_count, false);
1368  }
1369 
1370  // And to finish inform about MUTT_REOPEN if needed
1371  if (mdata->reopen & IMAP_EXPUNGE_PENDING && !(mdata->reopen & IMAP_EXPUNGE_EXPECTED))
1373 
1374  if (mdata->reopen & IMAP_EXPUNGE_PENDING)
1376  }
1377 
1378  adata->status = 0;
1379 }
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: imap_private.h:66
Mailbox is selected.
Definition: imap_private.h:107
void imap_expunge_mailbox(struct Mailbox *m)
Purge messages from the server.
Definition: imap.c:788
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: imap_private.h:172
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: imap_private.h:220
struct Mailbox * mailbox
Definition: imap_private.h:205
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:164
unsigned int max_msn
the largest MSN fetched so far
Definition: imap_private.h:237
unsigned int new_mail_count
Set when EXISTS notifies of new mail.
Definition: imap_private.h:222
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:251
Log at debug level 2.
Definition: logging.h:41
ImapOpenFlags check_status
Flags, e.g. IMAP_NEWMAIL_PENDING.
Definition: imap_private.h:221
void * mdata
Driver specific data.
Definition: mailbox.h:135
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: imap_private.h:173
#define IMAP_EXPUNGE_EXPECTED
Messages will be expunged from the server.
Definition: imap_private.h:65
IMAP-specific Mailbox data -.
Definition: imap_private.h:214
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:1274
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: imap_private.h:67
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Unrecoverable error occurred.
Definition: imap_private.h:94
#define IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition: imap_private.h:64
+ 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 1387 of file command.c.

1388 {
1389  int rc;
1390 
1391  if (cmd_start(adata, "IDLE", IMAP_CMD_POLL) < 0)
1392  {
1393  cmd_handle_fatal(adata);
1394  return -1;
1395  }
1396 
1397  if ((C_ImapPollTimeout > 0) && ((mutt_socket_poll(adata->conn, C_ImapPollTimeout)) == 0))
1398  {
1399  mutt_error(_("Connection to %s timed out"), adata->conn->account.host);
1400  cmd_handle_fatal(adata);
1401  return -1;
1402  }
1403 
1404  do
1405  {
1406  rc = imap_cmd_step(adata);
1407  } while (rc == IMAP_RES_CONTINUE);
1408 
1409  if (rc == IMAP_RES_RESPOND)
1410  {
1411  /* successfully entered IDLE state */
1412  adata->state = IMAP_IDLE;
1413  /* queue automatic exit when next command is issued */
1414  mutt_buffer_addstr(&adata->cmdbuf, "DONE\r\n");
1415  rc = IMAP_RES_OK;
1416  }
1417  if (rc != IMAP_RES_OK)
1418  {
1419  mutt_debug(LL_DEBUG1, "error starting IDLE\n");
1420  return -1;
1421  }
1422 
1423  return 0;
1424 }
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1100
struct ConnAccount account
Definition: connection.h:36
WHERE short C_ImapPollTimeout
Config: (imap) Maximum time to wait for a server response.
Definition: globals.h:156
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: imap_private.h:172
#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:164
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: imap_private.h:74
char host[128]
Definition: connaccount.h:63
Connection is idle.
Definition: imap_private.h:110
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:190
struct Buffer cmdbuf
Definition: imap_private.h:202
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define IMAP_RES_CONTINUE
* ...
Definition: imap_private.h:55
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:200
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct Connection * conn
Definition: imap_private.h:169
#define IMAP_RES_OK
<tag> OK ...
Definition: imap_private.h:54
#define IMAP_RES_RESPOND
+
Definition: imap_private.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ C_ImapServernoise

bool C_ImapServernoise

Config: (imap) Display server warnings as error messages.

Definition at line 55 of file command.c.

◆ 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 64 of file command.c.