NeoMutt  2020-11-20
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 "msn.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 56 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 91 of file command.c.

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

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

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

164 {
165  adata->status = IMAP_FATAL;
166 
167  if (!adata->mailbox)
168  return;
169 
170  struct ImapMboxData *mdata = adata->mailbox->mdata;
171 
172  if ((adata->state >= IMAP_SELECTED) && (mdata->reopen & IMAP_REOPEN_ALLOW))
173  {
175  mutt_socket_close(adata->conn);
176  mutt_error(_("Mailbox %s@%s closed"), adata->conn->account.user,
177  adata->conn->account.host);
178  adata->state = IMAP_DISCONNECTED;
179  }
180 
181  imap_close_connection(adata);
182  if (!adata->recovering)
183  {
184  adata->recovering = true;
185  if (imap_login(adata))
187  adata->recovering = false;
188  }
189 }
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
Unrecoverable error occurred.
Definition: private.h:97
int imap_login(struct ImapAccountData *adata)
Open an IMAP connection.
Definition: imap.c:1823
#define IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition: private.h:66
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: private.h:175
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:223
char user[128]
Username.
Definition: connaccount.h:55
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:207
void imap_close_connection(struct ImapAccountData *adata)
Close an IMAP connection.
Definition: imap.c:837
char host[128]
Server to login to.
Definition: connaccount.h:53
Disconnected from server.
Definition: private.h:107
void mx_fastclose_mailbox(struct Mailbox *m)
free up memory associated with the Mailbox
Definition: mx.c:445
Mailbox is selected.
Definition: private.h:110
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:176
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:96
IMAP-specific Mailbox data -.
Definition: private.h:217
#define mutt_error(...)
Definition: logging.h:84
bool recovering
Definition: private.h:173
struct Connection * conn
Definition: private.h:172
+ 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 199 of file command.c.

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

236 {
237  s = imap_next_word((char *) s);
238 
239  if (mutt_istr_startswith(s, "OK"))
240  return IMAP_RES_OK;
241  if (mutt_istr_startswith(s, "NO"))
242  return IMAP_RES_NO;
243 
244  return IMAP_RES_BAD;
245 }
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:56
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:172
#define IMAP_RES_NO
<tag> NO ...
Definition: private.h:54
#define IMAP_RES_BAD
<tag> BAD ...
Definition: private.h:55
+ 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 255 of file command.c.

256 {
257  unsigned int exp_msn;
258  struct Email *e = NULL;
259 
260  mutt_debug(LL_DEBUG2, "Handling EXPUNGE\n");
261 
262  struct ImapMboxData *mdata = adata->mailbox->mdata;
263 
264  if ((mutt_str_atoui(s, &exp_msn) < 0) || (exp_msn < 1) ||
265  (exp_msn > imap_msn_highest(&mdata->msn)))
266  {
267  return;
268  }
269 
270  e = imap_msn_get(&mdata->msn, exp_msn - 1);
271  if (e)
272  {
273  /* imap_expunge_mailbox() will rewrite e->index.
274  * It needs to resort using SORT_ORDER anyway, so setting to INT_MAX
275  * makes the code simpler and possibly more efficient. */
276  e->index = INT_MAX;
277  imap_edata_get(e)->msn = 0;
278  }
279 
280  /* decrement seqno of those above. */
281  const size_t max_msn = imap_msn_highest(&mdata->msn);
282  for (unsigned int cur = exp_msn; cur < max_msn; cur++)
283  {
284  e = imap_msn_get(&mdata->msn, cur);
285  if (e)
286  imap_edata_get(e)->msn--;
287  imap_msn_set(&mdata->msn, cur - 1, e);
288  }
289  imap_msn_shrink(&mdata->msn, 1);
290 
291  mdata->reopen |= IMAP_EXPUNGE_PENDING;
292 }
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
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:223
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:207
unsigned int msn
Message Sequence Number.
Definition: message.h:45
Log at debug level 2.
Definition: logging.h:41
struct Email * imap_msn_get(const struct MSN *msn, size_t idx)
Return the Email associated with an msn.
Definition: msn.c:80
void * mdata
Driver specific data.
Definition: mailbox.h:136
size_t imap_msn_shrink(struct MSN *msn, size_t num)
Remove a number of entries from the end of the cache.
Definition: msn.c:103
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:282
size_t imap_msn_highest(const struct MSN *msn)
Return the highest MSN in use.
Definition: msn.c:69
IMAP-specific Mailbox data -.
Definition: private.h:217
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
void imap_msn_set(struct MSN *msn, size_t idx, struct Email *e)
Cache an Email into a given position.
Definition: msn.c:92
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:68
+ 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 302 of file command.c.

303 {
304  bool earlier = false;
305  int rc;
306  unsigned int uid = 0;
307 
308  struct ImapMboxData *mdata = adata->mailbox->mdata;
309 
310  mutt_debug(LL_DEBUG2, "Handling VANISHED\n");
311 
312  if (mutt_istr_startswith(s, "(EARLIER)"))
313  {
314  /* The RFC says we should not decrement msns with the VANISHED EARLIER tag.
315  * My experimentation says that's crap. */
316  earlier = true;
317  s = imap_next_word(s);
318  }
319 
320  char *end_of_seqset = s;
321  while (*end_of_seqset)
322  {
323  if (!strchr("0123456789:,", *end_of_seqset))
324  *end_of_seqset = '\0';
325  else
326  end_of_seqset++;
327  }
328 
329  struct SeqsetIterator *iter = mutt_seqset_iterator_new(s);
330  if (!iter)
331  {
332  mutt_debug(LL_DEBUG2, "VANISHED: empty seqset [%s]?\n", s);
333  return;
334  }
335 
336  while ((rc = mutt_seqset_iterator_next(iter, &uid)) == 0)
337  {
338  struct Email *e = mutt_hash_int_find(mdata->uid_hash, uid);
339  if (!e)
340  continue;
341 
342  unsigned int exp_msn = imap_edata_get(e)->msn;
343 
344  /* imap_expunge_mailbox() will rewrite e->index.
345  * It needs to resort using SORT_ORDER anyway, so setting to INT_MAX
346  * makes the code simpler and possibly more efficient. */
347  e->index = INT_MAX;
348  imap_edata_get(e)->msn = 0;
349 
350  if ((exp_msn < 1) || (exp_msn > imap_msn_highest(&mdata->msn)))
351  {
352  mutt_debug(LL_DEBUG1, "VANISHED: msn for UID %u is incorrect\n", uid);
353  continue;
354  }
355  if (imap_msn_get(&mdata->msn, exp_msn - 1) != e)
356  {
357  mutt_debug(LL_DEBUG1, "VANISHED: msn_index for UID %u is incorrect\n", uid);
358  continue;
359  }
360 
361  imap_msn_remove(&mdata->msn, exp_msn - 1);
362 
363  if (!earlier)
364  {
365  /* decrement seqno of those above. */
366  const size_t max_msn = imap_msn_highest(&mdata->msn);
367  for (unsigned int cur = exp_msn; cur < max_msn; cur++)
368  {
369  e = imap_msn_get(&mdata->msn, cur);
370  if (e)
371  imap_edata_get(e)->msn--;
372  imap_msn_set(&mdata->msn, cur - 1, e);
373  }
374 
375  imap_msn_shrink(&mdata->msn, 1);
376  }
377  }
378 
379  if (rc < 0)
380  mutt_debug(LL_DEBUG1, "VANISHED: illegal seqset %s\n", s);
381 
382  mdata->reopen |= IMAP_EXPUNGE_PENDING;
383 
385 }
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
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:223
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:207
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
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
void imap_msn_remove(struct MSN *msn, size_t idx)
Remove an entry from the cache.
Definition: msn.c:113
Log at debug level 2.
Definition: logging.h:41
struct Email * imap_msn_get(const struct MSN *msn, size_t idx)
Return the Email associated with an msn.
Definition: msn.c:80
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct HashTable * uid_hash
Definition: private.h:237
size_t imap_msn_shrink(struct MSN *msn, size_t num)
Remove a number of entries from the end of the cache.
Definition: msn.c:103
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:172
size_t imap_msn_highest(const struct MSN *msn)
Return the highest MSN in use.
Definition: msn.c:69
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: private.h:217
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
void imap_msn_set(struct MSN *msn, size_t idx, struct Email *e)
Cache an Email into a given position.
Definition: msn.c:92
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:68
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:247
+ 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 396 of file command.c.

397 {
398  unsigned int msn, uid;
399  struct Email *e = NULL;
400  char *flags = NULL;
401  int uid_checked = 0;
402  bool server_changes = false;
403 
404  struct ImapMboxData *mdata = imap_mdata_get(adata->mailbox);
405 
406  mutt_debug(LL_DEBUG3, "Handling FETCH\n");
407 
408  if (mutt_str_atoui(s, &msn) < 0)
409  {
410  mutt_debug(LL_DEBUG3, "Skipping FETCH response - illegal MSN\n");
411  return;
412  }
413 
414  if ((msn < 1) || (msn > imap_msn_highest(&mdata->msn)))
415  {
416  mutt_debug(LL_DEBUG3, "Skipping FETCH response - MSN %u out of range\n", msn);
417  return;
418  }
419 
420  e = imap_msn_get(&mdata->msn, msn - 1);
421  if (!e || !e->active)
422  {
423  mutt_debug(LL_DEBUG3, "Skipping FETCH response - MSN %u not in msn_index\n", msn);
424  return;
425  }
426 
427  mutt_debug(LL_DEBUG2, "Message UID %u updated\n", imap_edata_get(e)->uid);
428  /* skip FETCH */
429  s = imap_next_word(s);
430  s = imap_next_word(s);
431 
432  if (*s != '(')
433  {
434  mutt_debug(LL_DEBUG1, "Malformed FETCH response\n");
435  return;
436  }
437  s++;
438 
439  while (*s)
440  {
441  SKIPWS(s);
442  size_t plen = mutt_istr_startswith(s, "FLAGS");
443  if (plen != 0)
444  {
445  flags = s;
446  if (uid_checked)
447  break;
448 
449  s += plen;
450  SKIPWS(s);
451  if (*s != '(')
452  {
453  mutt_debug(LL_DEBUG1, "bogus FLAGS response: %s\n", s);
454  return;
455  }
456  s++;
457  while (*s && (*s != ')'))
458  s++;
459  if (*s == ')')
460  s++;
461  else
462  {
463  mutt_debug(LL_DEBUG1, "Unterminated FLAGS response: %s\n", s);
464  return;
465  }
466  }
467  else if ((plen = mutt_istr_startswith(s, "UID")))
468  {
469  s += plen;
470  SKIPWS(s);
471  if (mutt_str_atoui(s, &uid) < 0)
472  {
473  mutt_debug(LL_DEBUG1, "Illegal UID. Skipping update\n");
474  return;
475  }
476  if (uid != imap_edata_get(e)->uid)
477  {
478  mutt_debug(LL_DEBUG1, "UID vs MSN mismatch. Skipping update\n");
479  return;
480  }
481  uid_checked = 1;
482  if (flags)
483  break;
484  s = imap_next_word(s);
485  }
486  else if ((plen = mutt_istr_startswith(s, "MODSEQ")))
487  {
488  s += plen;
489  SKIPWS(s);
490  if (*s != '(')
491  {
492  mutt_debug(LL_DEBUG1, "bogus MODSEQ response: %s\n", s);
493  return;
494  }
495  s++;
496  while (*s && (*s != ')'))
497  s++;
498  if (*s == ')')
499  s++;
500  else
501  {
502  mutt_debug(LL_DEBUG1, "Unterminated MODSEQ response: %s\n", s);
503  return;
504  }
505  }
506  else if (*s == ')')
507  break; /* end of request */
508  else if (*s)
509  {
510  mutt_debug(LL_DEBUG2, "Only handle FLAGS updates\n");
511  break;
512  }
513  }
514 
515  if (flags)
516  {
517  imap_set_flags(adata->mailbox, e, flags, &server_changes);
518  if (server_changes)
519  {
520  /* If server flags could conflict with NeoMutt's flags, reopen the mailbox. */
521  if (e->changed)
522  mdata->reopen |= IMAP_EXPUNGE_PENDING;
523  else
525  }
526  }
527 }
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
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:70
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:223
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:207
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:244
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
struct Email * imap_msn_get(const struct MSN *msn, size_t idx)
Return the Email associated with an msn.
Definition: msn.c:80
ImapOpenFlags check_status
Flags, e.g. IMAP_NEWMAIL_PENDING.
Definition: private.h:224
#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:282
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
size_t imap_msn_highest(const struct MSN *msn)
Return the highest MSN in use.
Definition: msn.c:69
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: private.h:217
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:1783
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:68
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 534 of file command.c.

535 {
536  mutt_debug(LL_DEBUG3, "Handling CAPABILITY\n");
537 
538  s = imap_next_word(s);
539  char *bracket = strchr(s, ']');
540  if (bracket)
541  *bracket = '\0';
542  FREE(&adata->capstr);
543  adata->capstr = mutt_str_dup(s);
544  adata->capabilities = 0;
545 
546  while (*s)
547  {
548  for (size_t i = 0; Capabilities[i]; i++)
549  {
550  size_t len = mutt_istr_startswith(s, Capabilities[i]);
551  if (len != 0 && ((s[len] == '\0') || IS_SPACE(s[len])))
552  {
553  adata->capabilities |= (1 << i);
554  mutt_debug(LL_DEBUG3, " Found capability \"%s\": %lu\n", Capabilities[i], i);
555  break;
556  }
557  }
558  s = imap_next_word(s);
559  }
560 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
char * capstr
Definition: private.h:185
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:172
ImapCapFlags capabilities
Definition: private.h:186
#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:63
+ 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 567 of file command.c.

568 {
569  struct ImapList *list = NULL;
570  struct ImapList lb = { 0 };
571  char delimbuf[5]; /* worst case: "\\"\0 */
572  unsigned int litlen;
573 
574  if (adata->cmdresult)
575  list = adata->cmdresult;
576  else
577  list = &lb;
578 
579  memset(list, 0, sizeof(struct ImapList));
580 
581  /* flags */
582  s = imap_next_word(s);
583  if (*s != '(')
584  {
585  mutt_debug(LL_DEBUG1, "Bad LIST response\n");
586  return;
587  }
588  s++;
589  while (*s)
590  {
591  if (mutt_istr_startswith(s, "\\NoSelect"))
592  list->noselect = true;
593  else if (mutt_istr_startswith(s, "\\NonExistent")) /* rfc5258 */
594  list->noselect = true;
595  else if (mutt_istr_startswith(s, "\\NoInferiors"))
596  list->noinferiors = true;
597  else if (mutt_istr_startswith(s, "\\HasNoChildren")) /* rfc5258*/
598  list->noinferiors = true;
599 
600  s = imap_next_word(s);
601  if (*(s - 2) == ')')
602  break;
603  }
604 
605  /* Delimiter */
606  if (!mutt_istr_startswith(s, "NIL"))
607  {
608  delimbuf[0] = '\0';
609  mutt_str_cat(delimbuf, 5, s);
610  imap_unquote_string(delimbuf);
611  list->delim = delimbuf[0];
612  }
613 
614  /* Name */
615  s = imap_next_word(s);
616  /* Notes often responds with literals here. We need a real tokenizer. */
617  if (imap_get_literal_count(s, &litlen) == 0)
618  {
619  if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
620  {
621  adata->status = IMAP_FATAL;
622  return;
623  }
624 
625  if (strlen(adata->buf) < litlen)
626  {
627  mutt_debug(LL_DEBUG1, "Error parsing LIST mailbox\n");
628  return;
629  }
630 
631  list->name = adata->buf;
632  s = list->name + litlen;
633  if (s[0] != '\0')
634  {
635  s[0] = '\0';
636  s++;
637  SKIPWS(s);
638  }
639  }
640  else
641  {
642  list->name = s;
643  /* Exclude rfc5258 RECURSIVEMATCH CHILDINFO suffix */
644  s = imap_next_word(s);
645  if (s[0] != '\0')
646  s[-1] = '\0';
647  imap_unmunge_mbox_name(adata->unicode, list->name);
648  }
649 
650  if (list->name[0] == '\0')
651  {
652  adata->delim = list->delim;
653  mutt_debug(LL_DEBUG3, "Root delimiter: %c\n", adata->delim);
654  }
655 }
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1071
Unrecoverable error occurred.
Definition: private.h:97
Items in an IMAP browser.
Definition: private.h:148
char delim
Definition: private.h:151
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:150
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:176
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
bool noinferiors
Definition: private.h:153
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:385
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:190
struct ImapList * cmdresult
Definition: private.h:197
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:57
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:152
bool unicode
If true, we can send UTF-8, and the server will use UTF8 rather than mUTF7.
Definition: private.h:193
+ 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 662 of file command.c.

663 {
664  char buf[256];
665  char quoted_name[256];
666  struct Buffer err;
667  struct Url url = { 0 };
668  struct ImapList list = { 0 };
669 
670  if (adata->cmdresult)
671  {
672  /* caller will handle response itself */
673  cmd_parse_list(adata, s);
674  return;
675  }
676 
678  return;
679 
680  adata->cmdresult = &list;
681  cmd_parse_list(adata, s);
682  adata->cmdresult = NULL;
683  /* noselect is for a gmail quirk */
684  if (!list.name || list.noselect)
685  return;
686 
687  mutt_debug(LL_DEBUG3, "Subscribing to %s\n", list.name);
688 
689  mutt_str_copy(buf, "mailboxes \"", sizeof(buf));
690  mutt_account_tourl(&adata->conn->account, &url);
691  /* escape \ and " */
692  imap_quote_string(quoted_name, sizeof(quoted_name), list.name, true);
693  url.path = quoted_name + 1;
694  url.path[strlen(url.path) - 1] = '\0';
695  if (mutt_str_equal(url.user, C_ImapUser))
696  url.user = NULL;
697  url_tostring(&url, buf + 11, sizeof(buf) - 11, 0);
698  mutt_str_cat(buf, sizeof(buf), "\"");
699  mutt_buffer_init(&err);
700  err.dsize = 256;
701  err.data = mutt_mem_malloc(err.dsize);
702  if (mutt_parse_rc_line(buf, &err))
703  mutt_debug(LL_DEBUG1, "Error adding subscribed mailbox: %s\n", err.data);
704  FREE(&err.data);
705 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
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:1039
Items in an IMAP browser.
Definition: private.h:148
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:61
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:150
bool C_ImapCheckSubscribed
Config: (imap) When opening a mailbox, ask the server for a list of subscribed folders.
Definition: config.c:40
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:385
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:716
#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:197
#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:567
Log at debug level 3.
Definition: logging.h:42
bool noselect
Definition: private.h:152
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:172
+ 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 712 of file command.c.

713 {
714  mutt_debug(LL_DEBUG2, "Handling MYRIGHTS\n");
715 
716  s = imap_next_word((char *) s);
717  s = imap_next_word((char *) s);
718 
719  /* zero out current rights set */
720  adata->mailbox->rights = 0;
721 
722  while (*s && !isspace((unsigned char) *s))
723  {
724  switch (*s)
725  {
726  case 'a':
727  adata->mailbox->rights |= MUTT_ACL_ADMIN;
728  break;
729  case 'e':
730  adata->mailbox->rights |= MUTT_ACL_EXPUNGE;
731  break;
732  case 'i':
733  adata->mailbox->rights |= MUTT_ACL_INSERT;
734  break;
735  case 'k':
736  adata->mailbox->rights |= MUTT_ACL_CREATE;
737  break;
738  case 'l':
739  adata->mailbox->rights |= MUTT_ACL_LOOKUP;
740  break;
741  case 'p':
742  adata->mailbox->rights |= MUTT_ACL_POST;
743  break;
744  case 'r':
745  adata->mailbox->rights |= MUTT_ACL_READ;
746  break;
747  case 's':
748  adata->mailbox->rights |= MUTT_ACL_SEEN;
749  break;
750  case 't':
751  adata->mailbox->rights |= MUTT_ACL_DELETE;
752  break;
753  case 'w':
754  adata->mailbox->rights |= MUTT_ACL_WRITE;
755  break;
756  case 'x':
757  adata->mailbox->rights |= MUTT_ACL_DELMX;
758  break;
759 
760  /* obsolete rights */
761  case 'c':
763  break;
764  case 'd':
766  break;
767  default:
768  mutt_debug(LL_DEBUG1, "Unknown right: %c\n", *s);
769  }
770  s++;
771  }
772 }
#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:207
#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 780 of file command.c.

781 {
782  if (!adata || !adata->account || !name)
783  return NULL;
784 
785  struct MailboxNode *np = NULL;
786  STAILQ_FOREACH(np, &adata->account->mailboxes, entries)
787  {
788  struct ImapMboxData *mdata = imap_mdata_get(np->mailbox);
789  if (mutt_str_equal(name, mdata->name))
790  return np->mailbox;
791  }
792 
793  return NULL;
794 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
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:244
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct Account * account
Parent Account.
Definition: private.h:209
char * name
Definition: private.h:150
char * name
Mailbox name.
Definition: private.h:219
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
IMAP-specific Mailbox data -.
Definition: private.h:217
List of Mailboxes.
Definition: mailbox.h:152
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:154
+ 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 804 of file command.c.

805 {
806  unsigned int litlen = 0;
807 
808  char *mailbox = imap_next_word(s);
809 
810  /* We need a real tokenizer. */
811  if (imap_get_literal_count(mailbox, &litlen) == 0)
812  {
813  if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
814  {
815  adata->status = IMAP_FATAL;
816  return;
817  }
818 
819  if (strlen(adata->buf) < litlen)
820  {
821  mutt_debug(LL_DEBUG1, "Error parsing STATUS mailbox\n");
822  return;
823  }
824 
825  mailbox = adata->buf;
826  s = mailbox + litlen;
827  s[0] = '\0';
828  s++;
829  SKIPWS(s);
830  }
831  else
832  {
833  s = imap_next_word(mailbox);
834  s[-1] = '\0';
835  imap_unmunge_mbox_name(adata->unicode, mailbox);
836  }
837 
838  struct Mailbox *m = find_mailbox(adata, mailbox);
839  struct ImapMboxData *mdata = imap_mdata_get(m);
840  if (!mdata)
841  {
842  mutt_debug(LL_DEBUG3, "Received status for an unexpected mailbox: %s\n", mailbox);
843  return;
844  }
845  uint32_t olduv = mdata->uidvalidity;
846  unsigned int oldun = mdata->uid_next;
847 
848  if (*s++ != '(')
849  {
850  mutt_debug(LL_DEBUG1, "Error parsing STATUS\n");
851  return;
852  }
853  while ((s[0] != '\0') && (s[0] != ')'))
854  {
855  char *value = imap_next_word(s);
856 
857  errno = 0;
858  const unsigned long ulcount = strtoul(value, &value, 10);
859  if (((errno == ERANGE) && (ulcount == ULONG_MAX)) || ((unsigned int) ulcount != ulcount))
860  {
861  mutt_debug(LL_DEBUG1, "Error parsing STATUS number\n");
862  return;
863  }
864  const unsigned int count = (unsigned int) ulcount;
865 
866  if (mutt_str_startswith(s, "MESSAGES"))
867  mdata->messages = count;
868  else if (mutt_str_startswith(s, "RECENT"))
869  mdata->recent = count;
870  else if (mutt_str_startswith(s, "UIDNEXT"))
871  mdata->uid_next = count;
872  else if (mutt_str_startswith(s, "UIDVALIDITY"))
873  mdata->uidvalidity = count;
874  else if (mutt_str_startswith(s, "UNSEEN"))
875  mdata->unseen = count;
876 
877  s = value;
878  if ((s[0] != '\0') && (*s != ')'))
879  s = imap_next_word(s);
880  }
881  mutt_debug(LL_DEBUG3, "%s (UIDVALIDITY: %u, UIDNEXT: %u) %d messages, %d recent, %d unseen\n",
882  mdata->name, mdata->uidvalidity, mdata->uid_next, mdata->messages,
883  mdata->recent, mdata->unseen);
884 
885  mutt_debug(LL_DEBUG3, "Running default STATUS handler\n");
886 
887  mutt_debug(LL_DEBUG3, "Found %s in mailbox list (OV: %u ON: %u U: %d)\n",
888  mailbox, olduv, oldun, mdata->unseen);
889 
890  bool new_mail = false;
891  if (C_MailCheckRecent)
892  {
893  if ((olduv != 0) && (olduv == mdata->uidvalidity))
894  {
895  if (oldun < mdata->uid_next)
896  new_mail = (mdata->unseen > 0);
897  }
898  else if ((olduv == 0) && (oldun == 0))
899  {
900  /* first check per session, use recent. might need a flag for this. */
901  new_mail = (mdata->recent > 0);
902  }
903  else
904  new_mail = (mdata->unseen > 0);
905  }
906  else
907  new_mail = (mdata->unseen > 0);
908 
909  m->has_new = new_mail;
910  m->msg_count = mdata->messages;
911  m->msg_unread = mdata->unseen;
912 
913  // force back to keep detecting new mail until the mailbox is opened
914  if (m->has_new)
915  mdata->uid_next = oldun;
916 }
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:1071
uint32_t uidvalidity
Definition: private.h:229
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
Unrecoverable error occurred.
Definition: private.h:97
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:244
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:780
#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:160
A mailbox.
Definition: mailbox.h:81
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:176
char * name
Mailbox name.
Definition: private.h:219
WHERE bool C_MailCheckRecent
Config: Notify the user about new mail since the last time the mailbox was opened.
Definition: mutt_globals.h:150
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:230
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: private.h:217
char * buf
Definition: private.h:190
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
unsigned int unseen
Definition: private.h:234
unsigned int recent
Definition: private.h:233
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:57
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:232
bool unicode
If true, we can send UTF-8, and the server will use UTF8 rather than mUTF7.
Definition: private.h:193
+ 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 923 of file command.c.

924 {
925  mutt_debug(LL_DEBUG2, "Handling ENABLED\n");
926 
927  while ((s = imap_next_word((char *) s)) && (*s != '\0'))
928  {
929  if (mutt_istr_startswith(s, "UTF8=ACCEPT") ||
930  mutt_istr_startswith(s, "UTF8=ONLY"))
931  {
932  adata->unicode = true;
933  }
934  if (mutt_istr_startswith(s, "QRESYNC"))
935  adata->qresync = true;
936  }
937 }
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:194
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
#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:193
+ 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 943 of file command.c.

944 {
945  unsigned int count = 0;
946  mutt_debug(LL_DEBUG2, "Handling EXISTS\n");
947 
948  if (mutt_str_atoui(pn, &count) < 0)
949  {
950  mutt_debug(LL_DEBUG1, "Malformed EXISTS: '%s'\n", pn);
951  return;
952  }
953 
954  struct ImapMboxData *mdata = adata->mailbox->mdata;
955 
956  /* new mail arrived */
957  if (count < imap_msn_highest(&mdata->msn))
958  {
959  /* Notes 6.0.3 has a tendency to report fewer messages exist than
960  * it should. */
961  mutt_debug(LL_DEBUG1, "Message count is out of sync\n");
962  }
963  /* at least the InterChange server sends EXISTS messages freely,
964  * even when there is no new mail */
965  else if (count == imap_msn_highest(&mdata->msn))
966  mutt_debug(LL_DEBUG3, "superfluous EXISTS message\n");
967  else
968  {
969  mutt_debug(LL_DEBUG2, "New mail in %s - %d messages total\n", mdata->name, count);
970  mdata->reopen |= IMAP_NEWMAIL_PENDING;
971  mdata->new_mail_count = count;
972  }
973 }
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:223
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:207
unsigned int new_mail_count
Set when EXISTS notifies of new mail.
Definition: private.h:225
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:219
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:282
size_t imap_msn_highest(const struct MSN *msn)
Return the highest MSN in use.
Definition: msn.c:69
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: private.h:217
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: private.h:69
#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 981 of file command.c.

982 {
983  char *s = imap_next_word(adata->buf);
984  char *pn = imap_next_word(s);
985 
986  if ((adata->state >= IMAP_SELECTED) && isdigit((unsigned char) *s))
987  {
988  /* pn vs. s: need initial seqno */
989  pn = s;
990  s = imap_next_word(s);
991 
992  /* EXISTS, EXPUNGE, FETCH are always related to the SELECTED mailbox */
993  if (mutt_istr_startswith(s, "EXISTS"))
994  cmd_parse_exists(adata, pn);
995  else if (mutt_istr_startswith(s, "EXPUNGE"))
996  cmd_parse_expunge(adata, pn);
997  else if (mutt_istr_startswith(s, "FETCH"))
998  cmd_parse_fetch(adata, pn);
999  }
1000  else if ((adata->state >= IMAP_SELECTED) &&
1001  mutt_istr_startswith(s, "VANISHED"))
1002  cmd_parse_vanished(adata, pn);
1003  else if (mutt_istr_startswith(s, "CAPABILITY"))
1004  cmd_parse_capability(adata, s);
1005  else if (mutt_istr_startswith(s, "OK [CAPABILITY"))
1006  cmd_parse_capability(adata, pn);
1007  else if (mutt_istr_startswith(pn, "OK [CAPABILITY"))
1009  else if (mutt_istr_startswith(s, "LIST"))
1010  cmd_parse_list(adata, s);
1011  else if (mutt_istr_startswith(s, "LSUB"))
1012  cmd_parse_lsub(adata, s);
1013  else if (mutt_istr_startswith(s, "MYRIGHTS"))
1014  cmd_parse_myrights(adata, s);
1015  else if (mutt_istr_startswith(s, "SEARCH"))
1016  cmd_parse_search(adata, s);
1017  else if (mutt_istr_startswith(s, "STATUS"))
1018  cmd_parse_status(adata, s);
1019  else if (mutt_istr_startswith(s, "ENABLED"))
1020  cmd_parse_enabled(adata, s);
1021  else if (mutt_istr_startswith(s, "BYE"))
1022  {
1023  mutt_debug(LL_DEBUG2, "Handling BYE\n");
1024 
1025  /* check if we're logging out */
1026  if (adata->status == IMAP_BYE)
1027  return 0;
1028 
1029  /* server shut down our connection */
1030  s += 3;
1031  SKIPWS(s);
1032  mutt_error("%s", s);
1033  cmd_handle_fatal(adata);
1034 
1035  return -1;
1036  }
1037  else if (C_ImapServernoise && mutt_istr_startswith(s, "NO"))
1038  {
1039  mutt_debug(LL_DEBUG2, "Handling untagged NO\n");
1040 
1041  /* Display the warning message from the server */
1042  mutt_error("%s", s + 2);
1043  }
1044 
1045  return 0;
1046 }
Logged out from server.
Definition: private.h:98
static void cmd_parse_capability(struct ImapAccountData *adata, char *s)
set capability bits according to CAPABILITY response
Definition: command.c:534
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: private.h:175
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:163
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:110
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:176
static void cmd_parse_enabled(struct ImapAccountData *adata, const char *s)
Record what the server has enabled.
Definition: command.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:172
bool C_ImapServernoise
Config: (imap) Display server warnings as error messages.
Definition: config.c:60
static void cmd_parse_myrights(struct ImapAccountData *adata, const char *s)
Set rights bits according to MYRIGHTS response.
Definition: command.c:712
static void cmd_parse_lsub(struct ImapAccountData *adata, char *s)
Parse a server LSUB (list subscribed mailboxes)
Definition: command.c:662
char * buf
Definition: private.h:190
static void cmd_parse_fetch(struct ImapAccountData *adata, char *s)
Load fetch response into ImapAccountData.
Definition: command.c:396
#define mutt_error(...)
Definition: logging.h:84
static void cmd_parse_expunge(struct ImapAccountData *adata, const char *s)
Parse expunge command.
Definition: command.c:255
static void cmd_parse_vanished(struct ImapAccountData *adata, char *s)
Parse vanished command.
Definition: command.c:302
#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:567
static void cmd_parse_exists(struct ImapAccountData *adata, const char *pn)
Parse EXISTS message from serer.
Definition: command.c:943
static void cmd_parse_status(struct ImapAccountData *adata, char *s)
Parse status from server.
Definition: command.c:804
+ 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 1057 of file command.c.

1058 {
1059  return cmd_start(adata, cmdstr, IMAP_CMD_NO_FLAGS);
1060 }
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: private.h:73
static int cmd_start(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Start a new IMAP command.
Definition: command.c:199
+ 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 1071 of file command.c.

1072 {
1073  if (!adata)
1074  return -1;
1075 
1076  size_t len = 0;
1077  int c;
1078  int rc;
1079  int stillrunning = 0;
1080  struct ImapCommand *cmd = NULL;
1081 
1082  if (adata->status == IMAP_FATAL)
1083  {
1084  cmd_handle_fatal(adata);
1085  return IMAP_RES_BAD;
1086  }
1087 
1088  /* read into buffer, expanding buffer as necessary until we have a full
1089  * line */
1090  do
1091  {
1092  if (len == adata->blen)
1093  {
1094  mutt_mem_realloc(&adata->buf, adata->blen + IMAP_CMD_BUFSIZE);
1095  adata->blen = adata->blen + IMAP_CMD_BUFSIZE;
1096  mutt_debug(LL_DEBUG3, "grew buffer to %lu bytes\n", adata->blen);
1097  }
1098 
1099  /* back up over '\0' */
1100  if (len)
1101  len--;
1102  c = mutt_socket_readln_d(adata->buf + len, adata->blen - len, adata->conn, MUTT_SOCK_LOG_FULL);
1103  if (c <= 0)
1104  {
1105  mutt_debug(LL_DEBUG1, "Error reading server response\n");
1106  cmd_handle_fatal(adata);
1107  return IMAP_RES_BAD;
1108  }
1109 
1110  len += c;
1111  }
1112  /* if we've read all the way to the end of the buffer, we haven't read a
1113  * full line (mutt_socket_readln strips the \r, so we always have at least
1114  * one character free when we've read a full line) */
1115  while (len == adata->blen);
1116 
1117  /* don't let one large string make cmd->buf hog memory forever */
1118  if ((adata->blen > IMAP_CMD_BUFSIZE) && (len <= IMAP_CMD_BUFSIZE))
1119  {
1121  adata->blen = IMAP_CMD_BUFSIZE;
1122  mutt_debug(LL_DEBUG3, "shrank buffer to %lu bytes\n", adata->blen);
1123  }
1124 
1125  adata->lastread = mutt_date_epoch();
1126 
1127  /* handle untagged messages. The caller still gets its shot afterwards. */
1128  if ((mutt_str_startswith(adata->buf, "* ") ||
1129  mutt_str_startswith(imap_next_word(adata->buf), "OK [")) &&
1130  cmd_handle_untagged(adata))
1131  {
1132  return IMAP_RES_BAD;
1133  }
1134 
1135  /* server demands a continuation response from us */
1136  if (adata->buf[0] == '+')
1137  return IMAP_RES_RESPOND;
1138 
1139  /* Look for tagged command completions.
1140  *
1141  * Some response handlers can end up recursively calling
1142  * imap_cmd_step() and end up handling all tagged command
1143  * completions.
1144  * (e.g. FETCH->set_flag->set_header_color->~h pattern match.)
1145  *
1146  * Other callers don't even create an adata->cmds entry.
1147  *
1148  * For both these cases, we default to returning OK */
1149  rc = IMAP_RES_OK;
1150  c = adata->lastcmd;
1151  do
1152  {
1153  cmd = &adata->cmds[c];
1154  if (cmd->state == IMAP_RES_NEW)
1155  {
1156  if (mutt_str_startswith(adata->buf, cmd->seq))
1157  {
1158  if (!stillrunning)
1159  {
1160  /* first command in queue has finished - move queue pointer up */
1161  adata->lastcmd = (adata->lastcmd + 1) % adata->cmdslots;
1162  }
1163  cmd->state = cmd_status(adata->buf);
1164  rc = cmd->state;
1165  if (cmd->state == IMAP_RES_NO || cmd->state == IMAP_RES_BAD)
1166  {
1167  mutt_message(_("IMAP command failed: %s"), adata->buf);
1168  }
1169  }
1170  else
1171  stillrunning++;
1172  }
1173 
1174  c = (c + 1) % adata->cmdslots;
1175  } while (c != adata->nextcmd);
1176 
1177  if (stillrunning)
1178  rc = IMAP_RES_CONTINUE;
1179  else
1180  {
1181  mutt_debug(LL_DEBUG3, "IMAP queue drained\n");
1182  imap_cmd_finish(adata);
1183  }
1184 
1185  return rc;
1186 }
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:200
#define IMAP_RES_RESPOND
+
Definition: private.h:58
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:56
#define mutt_message(...)
Definition: logging.h:83
#define IMAP_RES_NEW
ImapCommand.state additions.
Definition: private.h:59
Unrecoverable error occurred.
Definition: private.h:97
#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:163
size_t blen
Definition: private.h:191
#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:159
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:160
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:176
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition: command.c:1306
#define IMAP_CMD_BUFSIZE
Definition: command.c:56
char seq[SEQ_LEN+1]
Command tag, e.g. &#39;a0001&#39;.
Definition: private.h:161
#define IMAP_RES_NO
<tag> NO ...
Definition: private.h:54
time_t lastread
last time we read a command for the server
Definition: private.h:189
Log at debug level 1.
Definition: logging.h:40
int state
Command state, e.g. IMAP_RES_NEW.
Definition: private.h:162
char * buf
Definition: private.h:190
static int cmd_handle_untagged(struct ImapAccountData *adata)
fallback parser for otherwise unhandled messages
Definition: command.c:981
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:57
Log at debug level 3.
Definition: logging.h:42
struct Connection * conn
Definition: private.h:172
#define IMAP_RES_BAD
<tag> BAD ...
Definition: private.h:55
static int cmd_status(const char *s)
parse response line for tagged OK/NO/BAD
Definition: command.c:235
+ 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 1194 of file command.c.

1195 {
1196  return cmd_status(s) == IMAP_RES_OK;
1197 }
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:56
static int cmd_status(const char *s)
parse response line for tagged OK/NO/BAD
Definition: command.c:235
+ 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 1205 of file command.c.

1206 {
1207  static const char *notrailer = "";
1208  const char *s = adata->buf;
1209 
1210  if (!s)
1211  {
1212  mutt_debug(LL_DEBUG2, "not a tagged response\n");
1213  return notrailer;
1214  }
1215 
1216  s = imap_next_word((char *) s);
1217  if (!s || (!mutt_istr_startswith(s, "OK") && !mutt_istr_startswith(s, "NO") &&
1218  !mutt_istr_startswith(s, "BAD")))
1219  {
1220  mutt_debug(LL_DEBUG2, "not a command completion: %s\n", adata->buf);
1221  return notrailer;
1222  }
1223 
1224  s = imap_next_word((char *) s);
1225  if (!s)
1226  return notrailer;
1227 
1228  return s;
1229 }
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:172
char * buf
Definition: private.h:190
#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 1242 of file command.c.

1243 {
1244  int rc;
1245 
1246  if (flags & IMAP_CMD_SINGLE)
1247  {
1248  // Process any existing commands
1249  if (adata->nextcmd != adata->lastcmd)
1250  imap_exec(adata, NULL, IMAP_CMD_POLL);
1251  }
1252 
1253  rc = cmd_start(adata, cmdstr, flags);
1254  if (rc < 0)
1255  {
1256  cmd_handle_fatal(adata);
1257  return IMAP_EXEC_FATAL;
1258  }
1259 
1260  if (flags & IMAP_CMD_QUEUE)
1261  return IMAP_EXEC_SUCCESS;
1262 
1263  if ((flags & IMAP_CMD_POLL) && (C_ImapPollTimeout > 0) &&
1264  ((mutt_socket_poll(adata->conn, C_ImapPollTimeout)) == 0))
1265  {
1266  mutt_error(_("Connection to %s timed out"), adata->conn->account.host);
1267  cmd_handle_fatal(adata);
1268  return IMAP_EXEC_FATAL;
1269  }
1270 
1271  /* Allow interruptions, particularly useful if there are network problems. */
1273  do
1274  {
1275  rc = imap_cmd_step(adata);
1276  // The queue is empty, so the single command has been processed
1277  if ((flags & IMAP_CMD_SINGLE) && (adata->nextcmd == adata->lastcmd))
1278  break;
1279  } while (rc == IMAP_RES_CONTINUE);
1280  mutt_sig_allow_interrupt(false);
1281 
1282  if (rc == IMAP_RES_NO)
1283  return IMAP_EXEC_ERROR;
1284  if (rc != IMAP_RES_OK)
1285  {
1286  if (adata->status != IMAP_FATAL)
1287  return IMAP_EXEC_ERROR;
1288 
1289  mutt_debug(LL_DEBUG1, "command failed: %s\n", adata->buf);
1290  return IMAP_EXEC_FATAL;
1291  }
1292 
1293  return IMAP_EXEC_SUCCESS;
1294 }
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:56
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1071
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
Imap connection failure.
Definition: private.h:86
Unrecoverable error occurred.
Definition: private.h:97
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: private.h:76
#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:163
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:84
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:57
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:1242
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:176
#define IMAP_RES_NO
<tag> NO ...
Definition: private.h:54
Imap command failure.
Definition: private.h:85
Log at debug level 1.
Definition: logging.h:40
char * buf
Definition: private.h:190
#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:199
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: private.h:75
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:57
#define IMAP_CMD_SINGLE
Run a single command.
Definition: private.h:77
struct Connection * conn
Definition: private.h:172
+ 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 1306 of file command.c.

1307 {
1308  if (!adata)
1309  return;
1310 
1311  if (adata->status == IMAP_FATAL)
1312  {
1313  adata->closing = false;
1314  cmd_handle_fatal(adata);
1315  return;
1316  }
1317 
1318  if (!(adata->state >= IMAP_SELECTED) || (adata->mailbox && adata->closing))
1319  {
1320  adata->closing = false;
1321  return;
1322  }
1323 
1324  adata->closing = false;
1325 
1326  struct ImapMboxData *mdata = imap_mdata_get(adata->mailbox);
1327 
1328  if (mdata && mdata->reopen & IMAP_REOPEN_ALLOW)
1329  {
1330  // First remove expunged emails from the msn_index
1331  if (mdata->reopen & IMAP_EXPUNGE_PENDING)
1332  {
1333  mutt_debug(LL_DEBUG2, "Expunging mailbox\n");
1334  imap_expunge_mailbox(adata->mailbox);
1335  /* Detect whether we've gotten unexpected EXPUNGE messages */
1336  if (!(mdata->reopen & IMAP_EXPUNGE_EXPECTED))
1339  }
1340 
1341  // Then add new emails to it
1342  if (mdata->reopen & IMAP_NEWMAIL_PENDING)
1343  {
1344  const size_t max_msn = imap_msn_highest(&mdata->msn);
1345  if (mdata->new_mail_count > max_msn)
1346  {
1347  if (!(mdata->reopen & IMAP_EXPUNGE_PENDING))
1349 
1350  mutt_debug(LL_DEBUG2, "Fetching new mails from %d to %d\n", max_msn + 1,
1351  mdata->new_mail_count);
1352  imap_read_headers(adata->mailbox, max_msn + 1, mdata->new_mail_count, false);
1353  }
1354  }
1355 
1356  // And to finish inform about MUTT_REOPEN if needed
1357  if (mdata->reopen & IMAP_EXPUNGE_PENDING && !(mdata->reopen & IMAP_EXPUNGE_EXPECTED))
1359 
1360  if (mdata->reopen & IMAP_EXPUNGE_PENDING)
1362  }
1363 
1364  adata->status = 0;
1365 }
Unrecoverable error occurred.
Definition: private.h:97
void imap_expunge_mailbox(struct Mailbox *m)
Purge messages from the server.
Definition: imap.c:665
#define IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition: private.h:66
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: private.h:175
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:223
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:207
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:244
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition: command.c:163
unsigned int new_mail_count
Set when EXISTS notifies of new mail.
Definition: private.h:225
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:1243
ImapOpenFlags check_status
Flags, e.g. IMAP_NEWMAIL_PENDING.
Definition: private.h:224
Mailbox is selected.
Definition: private.h:110
void * mdata
Driver specific data.
Definition: mailbox.h:136
bool closing
If true, we are waiting for CLOSE completion.
Definition: private.h:174
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:176
#define IMAP_EXPUNGE_EXPECTED
Messages will be expunged from the server.
Definition: private.h:67
size_t imap_msn_highest(const struct MSN *msn)
Return the highest MSN in use.
Definition: msn.c:69
IMAP-specific Mailbox data -.
Definition: private.h:217
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: private.h:69
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:68
+ 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 1373 of file command.c.

1374 {
1375  int rc;
1376 
1377  if (cmd_start(adata, "IDLE", IMAP_CMD_POLL) < 0)
1378  {
1379  cmd_handle_fatal(adata);
1380  return -1;
1381  }
1382 
1383  if ((C_ImapPollTimeout > 0) && ((mutt_socket_poll(adata->conn, C_ImapPollTimeout)) == 0))
1384  {
1385  mutt_error(_("Connection to %s timed out"), adata->conn->account.host);
1386  cmd_handle_fatal(adata);
1387  return -1;
1388  }
1389 
1390  do
1391  {
1392  rc = imap_cmd_step(adata);
1393  } while (rc == IMAP_RES_CONTINUE);
1394 
1395  if (rc == IMAP_RES_RESPOND)
1396  {
1397  /* successfully entered IDLE state */
1398  adata->state = IMAP_IDLE;
1399  /* queue automatic exit when next command is issued */
1400  mutt_buffer_addstr(&adata->cmdbuf, "DONE\r\n");
1401  rc = IMAP_RES_OK;
1402  }
1403  if (rc != IMAP_RES_OK)
1404  {
1405  mutt_debug(LL_DEBUG1, "error starting IDLE\n");
1406  return -1;
1407  }
1408 
1409  return 0;
1410 }
#define IMAP_RES_RESPOND
+
Definition: private.h:58
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:56
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1071
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: private.h:175
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: private.h:76
#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:163
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:204
short C_ImapPollTimeout
Config: (imap) Maximum time to wait for a server response.
Definition: config.c:57
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:113
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:199
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:57
struct Connection * conn
Definition: private.h:172
+ 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 63 of file command.c.