NeoMutt  2020-08-07-1-gab41a1
Teaching an old dog new tricks
DOXYGEN
message.c File Reference

Manage IMAP messages. More...

#include "config.h"
#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "conn/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "message.h"
#include "bcache/lib.h"
#include "imap/lib.h"
#include "mutt_globals.h"
#include "mutt_logging.h"
#include "mutt_socket.h"
#include "muttlib.h"
#include "mx.h"
#include "progress.h"
#include "protos.h"
#include <libintl.h>
#include "hcache/lib.h"
#include "autocrypt/lib.h"
+ Include dependency graph for message.c:

Go to the source code of this file.

Functions

void imap_edata_free (void **ptr)
 Free the private Email data - Implements Email::edata_free() More...
 
static struct ImapEmailDataimap_edata_new (void)
 Create a new ImapEmailData. More...
 
struct ImapEmailDataimap_edata_get (struct Email *e)
 Get the private data for this Email. More...
 
static struct BodyCachemsg_cache_open (struct Mailbox *m)
 Open a message cache. More...
 
static FILE * msg_cache_get (struct Mailbox *m, struct Email *e)
 Get the message cache entry for an email. More...
 
static FILE * msg_cache_put (struct Mailbox *m, struct Email *e)
 Put an email into the message cache. More...
 
static int msg_cache_commit (struct Mailbox *m, struct Email *e)
 Add to the message cache. More...
 
static int msg_cache_clean_cb (const char *id, struct BodyCache *bcache, void *data)
 Delete an entry from the message cache - Implements bcache_list_t. More...
 
static char * msg_parse_flags (struct ImapHeader *h, char *s)
 read a FLAGS token into an ImapHeader More...
 
static int msg_parse_fetch (struct ImapHeader *h, char *s)
 handle headers returned from header fetch More...
 
static int msg_fetch_header (struct Mailbox *m, struct ImapHeader *ih, char *buf, FILE *fp)
 import IMAP FETCH response into an ImapHeader More...
 
static int flush_buffer (char *buf, size_t *len, struct Connection *conn)
 Write data to a connection. More...
 
static bool query_abort_header_download (struct ImapAccountData *adata)
 Ask the user whether to abort the download. More...
 
static void alloc_msn_index (struct ImapAccountData *adata, size_t msn_count)
 Create lookup table of MSN to Header. More...
 
static void imap_alloc_uid_hash (struct ImapAccountData *adata, unsigned int msn_count)
 Create a Hash Table for the UIDs. More...
 
static unsigned int imap_fetch_msn_seqset (struct Buffer *buf, struct ImapAccountData *adata, bool evalhc, unsigned int msn_begin, unsigned int msn_end, unsigned int *fetch_msn_end)
 Generate a sequence set. More...
 
static void set_changed_flag (struct Mailbox *m, struct Email *e, int local_changes, bool *server_changes, int flag_name, bool old_hd_flag, bool new_hd_flag, bool h_flag)
 Have the flags of an email changed. More...
 
static int read_headers_normal_eval_cache (struct ImapAccountData *adata, unsigned int msn_end, unsigned int uid_next, bool store_flag_updates, bool eval_condstore)
 Retrieve data from the header cache. More...
 
static int read_headers_qresync_eval_cache (struct ImapAccountData *adata, char *uid_seqset)
 Retrieve data from the header cache. More...
 
static int read_headers_condstore_qresync_updates (struct ImapAccountData *adata, unsigned int msn_end, unsigned int uid_next, unsigned long long hc_modseq, bool eval_qresync)
 Retrieve updates from the server. More...
 
static int read_headers_fetch_new (struct Mailbox *m, unsigned int msn_begin, unsigned int msn_end, bool evalhc, unsigned int *maxuid, bool initial_download)
 Retrieve new messages from the server. More...
 
int imap_read_headers (struct Mailbox *m, unsigned int msn_begin, unsigned int msn_end, bool initial_download)
 Read headers from the server. More...
 
int imap_append_message (struct Mailbox *m, struct Message *msg)
 Write an email back to the server. More...
 
int imap_copy_messages (struct Mailbox *m, struct EmailList *el, const char *dest, bool delete_original)
 Server COPY messages to another folder. More...
 
int imap_cache_del (struct Mailbox *m, struct Email *e)
 Delete an email from the body cache. More...
 
int imap_cache_clean (struct Mailbox *m)
 Delete all the entries in the message cache. More...
 
char * imap_set_flags (struct Mailbox *m, struct Email *e, char *s, bool *server_changes)
 fill the message header according to the server flags More...
 
int imap_msg_open (struct Mailbox *m, struct Message *msg, int msgno)
 Open an email message in a Mailbox - Implements MxOps::msg_open() More...
 
int imap_msg_commit (struct Mailbox *m, struct Message *msg)
 Save changes to an email - Implements MxOps::msg_commit() More...
 
int imap_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() More...
 
int imap_msg_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Implements MxOps::msg_save_hcache() More...
 

Detailed Description

Manage IMAP messages.

Authors
  • 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 message.c.

Function Documentation

◆ imap_edata_free()

void imap_edata_free ( void **  ptr)

Free the private Email data - Implements Email::edata_free()

Definition at line 72 of file message.c.

73 {
74  if (!ptr || !*ptr)
75  return;
76 
77  struct ImapEmailData *edata = *ptr;
78  /* this should be safe even if the list wasn't used */
79  FREE(&edata->flags_system);
80  FREE(&edata->flags_remote);
81  FREE(ptr);
82 }
char * flags_remote
Definition: message.h:48
char * flags_system
Definition: message.h:47
void * edata
Driver-specific data.
Definition: email.h:109
#define FREE(x)
Definition: memory.h:40
IMAP-specific Email data -.
Definition: message.h:33
+ Here is the caller graph for this function:

◆ imap_edata_new()

static struct ImapEmailData* imap_edata_new ( void  )
static

Create a new ImapEmailData.

Return values
ptrNew ImapEmailData

Definition at line 88 of file message.c.

89 {
90  return mutt_mem_calloc(1, sizeof(struct ImapEmailData));
91 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
IMAP-specific Email data -.
Definition: message.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_edata_get()

struct ImapEmailData* imap_edata_get ( struct Email e)

Get the private data for this Email.

Parameters
eEmail
Return values
ptrPrivate Email data

Definition at line 98 of file message.c.

99 {
100  if (!e)
101  return NULL;
102  return e->edata;
103 }
void * edata
Driver-specific data.
Definition: email.h:109
+ Here is the caller graph for this function:

◆ msg_cache_open()

static struct BodyCache* msg_cache_open ( struct Mailbox m)
static

Open a message cache.

Parameters
mSelected Imap Mailbox
Return values
ptrSuccess, using existing cache (or opened new cache)
NULLFailure

Definition at line 111 of file message.c.

112 {
113  struct ImapAccountData *adata = imap_adata_get(m);
114  struct ImapMboxData *mdata = imap_mdata_get(m);
115 
116  if (!adata || (adata->mailbox != m))
117  return NULL;
118 
119  if (mdata->bcache)
120  return mdata->bcache;
121 
122  struct Buffer *mailbox = mutt_buffer_pool_get();
123  imap_cachepath(adata->delim, mdata->name, mailbox);
124 
125  struct BodyCache *bc = mutt_bcache_open(&adata->conn->account, mutt_b2s(mailbox));
126  mutt_buffer_pool_release(&mailbox);
127 
128  return bc;
129 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:136
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
struct BodyCache * bcache
Definition: private.h:240
void * mdata
Driver specific data.
Definition: mailbox.h:136
#define mutt_b2s(buf)
Definition: buffer.h:41
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
char * name
Mailbox name.
Definition: private.h:218
Local cache of email bodies.
Definition: bcache.c:53
IMAP-specific Account data -.
Definition: private.h:169
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
IMAP-specific Mailbox data -.
Definition: private.h:216
void imap_cachepath(char delim, const char *mailbox, struct Buffer *dest)
Generate a cache path for a mailbox.
Definition: util.c:850
struct Connection * conn
Definition: private.h:171
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ msg_cache_get()

static FILE* msg_cache_get ( struct Mailbox m,
struct Email e 
)
static

Get the message cache entry for an email.

Parameters
mSelected Imap Mailbox
eEmail
Return values
ptrSuccess, handle of cache entry
NULLFailure

Definition at line 138 of file message.c.

139 {
140  struct ImapAccountData *adata = imap_adata_get(m);
141  struct ImapMboxData *mdata = imap_mdata_get(m);
142 
143  if (!e || !adata || (adata->mailbox != m))
144  return NULL;
145 
146  mdata->bcache = msg_cache_open(m);
147  char id[64];
148  snprintf(id, sizeof(id), "%u-%u", mdata->uidvalidity, imap_edata_get(e)->uid);
149  return mutt_bcache_get(mdata->bcache, id);
150 }
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:98
uint32_t uidvalidity
Definition: private.h:228
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
struct BodyCache * bcache
Definition: private.h:240
FILE * mutt_bcache_get(struct BodyCache *bcache, const char *id)
Open a file in the Body Cache.
Definition: bcache.c:172
void * mdata
Driver specific data.
Definition: mailbox.h:136
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
static struct BodyCache * msg_cache_open(struct Mailbox *m)
Open a message cache.
Definition: message.c:111
IMAP-specific Account data -.
Definition: private.h:169
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
IMAP-specific Mailbox data -.
Definition: private.h:216
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ msg_cache_put()

static FILE* msg_cache_put ( struct Mailbox m,
struct Email e 
)
static

Put an email into the message cache.

Parameters
mSelected Imap Mailbox
eEmail
Return values
ptrSuccess, handle of cache entry
NULLFailure

Definition at line 159 of file message.c.

160 {
161  struct ImapAccountData *adata = imap_adata_get(m);
162  struct ImapMboxData *mdata = imap_mdata_get(m);
163 
164  if (!e || !adata || (adata->mailbox != m))
165  return NULL;
166 
167  mdata->bcache = msg_cache_open(m);
168  char id[64];
169  snprintf(id, sizeof(id), "%u-%u", mdata->uidvalidity, imap_edata_get(e)->uid);
170  return mutt_bcache_put(mdata->bcache, id);
171 }
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:98
uint32_t uidvalidity
Definition: private.h:228
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
struct BodyCache * bcache
Definition: private.h:240
void * mdata
Driver specific data.
Definition: mailbox.h:136
FILE * mutt_bcache_put(struct BodyCache *bcache, const char *id)
Create a file in the Body Cache.
Definition: bcache.c:199
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
static struct BodyCache * msg_cache_open(struct Mailbox *m)
Open a message cache.
Definition: message.c:111
IMAP-specific Account data -.
Definition: private.h:169
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
IMAP-specific Mailbox data -.
Definition: private.h:216
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ msg_cache_commit()

static int msg_cache_commit ( struct Mailbox m,
struct Email e 
)
static

Add to the message cache.

Parameters
mSelected Imap Mailbox
eEmail
Return values
0Success
-1Failure

Definition at line 180 of file message.c.

181 {
182  struct ImapAccountData *adata = imap_adata_get(m);
183  struct ImapMboxData *mdata = imap_mdata_get(m);
184 
185  if (!e || !adata || (adata->mailbox != m))
186  return -1;
187 
188  mdata->bcache = msg_cache_open(m);
189  char id[64];
190  snprintf(id, sizeof(id), "%u-%u", mdata->uidvalidity, imap_edata_get(e)->uid);
191 
192  return mutt_bcache_commit(mdata->bcache, id);
193 }
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:98
uint32_t uidvalidity
Definition: private.h:228
int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition: bcache.c:239
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
struct BodyCache * bcache
Definition: private.h:240
void * mdata
Driver specific data.
Definition: mailbox.h:136
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
static struct BodyCache * msg_cache_open(struct Mailbox *m)
Open a message cache.
Definition: message.c:111
IMAP-specific Account data -.
Definition: private.h:169
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
IMAP-specific Mailbox data -.
Definition: private.h:216
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ msg_cache_clean_cb()

static int msg_cache_clean_cb ( const char *  id,
struct BodyCache bcache,
void *  data 
)
static

Delete an entry from the message cache - Implements bcache_list_t.

Return values
0Always

Definition at line 199 of file message.c.

200 {
201  uint32_t uv;
202  unsigned int uid;
203  struct ImapMboxData *mdata = data;
204 
205  if (sscanf(id, "%u-%u", &uv, &uid) != 2)
206  return 0;
207 
208  /* bad UID */
209  if ((uv != mdata->uidvalidity) || !mutt_hash_int_find(mdata->uid_hash, uid))
210  mutt_bcache_del(bcache, id);
211 
212  return 0;
213 }
uint32_t uidvalidity
Definition: private.h:228
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
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct HashTable * uid_hash
Definition: private.h:236
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:256
IMAP-specific Mailbox data -.
Definition: private.h:216
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ msg_parse_flags()

static char* msg_parse_flags ( struct ImapHeader h,
char *  s 
)
static

read a FLAGS token into an ImapHeader

Parameters
hHeader to store flags
sCommand string containing flags
Return values
ptrThe end of flags string
NULLFailure

Definition at line 222 of file message.c.

223 {
224  struct ImapEmailData *edata = h->edata;
225 
226  /* sanity-check string */
227  size_t plen = mutt_istr_startswith(s, "FLAGS");
228  if (plen == 0)
229  {
230  mutt_debug(LL_DEBUG1, "not a FLAGS response: %s\n", s);
231  return NULL;
232  }
233  s += plen;
234  SKIPWS(s);
235  if (*s != '(')
236  {
237  mutt_debug(LL_DEBUG1, "bogus FLAGS response: %s\n", s);
238  return NULL;
239  }
240  s++;
241 
242  FREE(&edata->flags_system);
243  FREE(&edata->flags_remote);
244 
245  edata->deleted = false;
246  edata->flagged = false;
247  edata->replied = false;
248  edata->read = false;
249  edata->old = false;
250 
251  /* start parsing */
252  while (*s && (*s != ')'))
253  {
254  if ((plen = mutt_istr_startswith(s, "\\deleted")))
255  {
256  s += plen;
257  edata->deleted = true;
258  }
259  else if ((plen = mutt_istr_startswith(s, "\\flagged")))
260  {
261  s += plen;
262  edata->flagged = true;
263  }
264  else if ((plen = mutt_istr_startswith(s, "\\answered")))
265  {
266  s += plen;
267  edata->replied = true;
268  }
269  else if ((plen = mutt_istr_startswith(s, "\\seen")))
270  {
271  s += plen;
272  edata->read = true;
273  }
274  else if ((plen = mutt_istr_startswith(s, "\\recent")))
275  {
276  s += plen;
277  }
278  else if ((plen = mutt_istr_startswith(s, "old")))
279  {
280  s += plen;
281  edata->old = C_MarkOld ? true : false;
282  }
283  else
284  {
285  char ctmp;
286  char *flag_word = s;
287  bool is_system_keyword = mutt_istr_startswith(s, "\\");
288 
289  while (*s && !IS_SPACE(*s) && (*s != ')'))
290  s++;
291 
292  ctmp = *s;
293  *s = '\0';
294 
295  /* store other system flags as well (mainly \\Draft) */
296  if (is_system_keyword)
297  mutt_str_append_item(&edata->flags_system, flag_word, ' ');
298  /* store custom flags as well */
299  else
300  mutt_str_append_item(&edata->flags_remote, flag_word, ' ');
301 
302  *s = ctmp;
303  }
304  SKIPWS(s);
305  }
306 
307  /* wrap up, or note bad flags response */
308  if (*s == ')')
309  s++;
310  else
311  {
312  mutt_debug(LL_DEBUG1, "Unterminated FLAGS response: %s\n", s);
313  return NULL;
314  }
315 
316  return s;
317 }
bool C_MarkOld
Config: Mark new emails as old when leaving the mailbox.
Definition: globals.c:36
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
bool flagged
Definition: message.h:39
bool deleted
Definition: message.h:38
#define SKIPWS(ch)
Definition: string2.h:46
char * flags_remote
Definition: message.h:48
bool replied
Definition: message.h:40
bool old
Definition: message.h:37
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
#define IS_SPACE(ch)
Definition: string2.h:38
Log at debug level 1.
Definition: logging.h:40
char * flags_system
Definition: message.h:47
void * edata
Driver-specific data.
Definition: email.h:109
#define FREE(x)
Definition: memory.h:40
bool read
Definition: message.h:36
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
IMAP-specific Email data -.
Definition: message.h:33
void mutt_str_append_item(char **str, const char *item, char sep)
Add string to another separated by sep.
Definition: string.c:471
struct ImapEmailData * edata
Definition: message.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ msg_parse_fetch()

static int msg_parse_fetch ( struct ImapHeader h,
char *  s 
)
static

handle headers returned from header fetch

Parameters
hIMAP Header
sCommand string
Return values
0Success
-1String is corrupted
-2Fetch contains a body or header lines that still need to be parsed

Definition at line 327 of file message.c.

328 {
329  if (!s)
330  return -1;
331 
332  char tmp[128];
333  char *ptmp = NULL;
334  size_t plen = 0;
335 
336  while (*s)
337  {
338  SKIPWS(s);
339 
340  if (mutt_istr_startswith(s, "FLAGS"))
341  {
342  s = msg_parse_flags(h, s);
343  if (!s)
344  return -1;
345  }
346  else if ((plen = mutt_istr_startswith(s, "UID")))
347  {
348  s += plen;
349  SKIPWS(s);
350  if (mutt_str_atoui(s, &h->edata->uid) < 0)
351  return -1;
352 
353  s = imap_next_word(s);
354  }
355  else if ((plen = mutt_istr_startswith(s, "INTERNALDATE")))
356  {
357  s += plen;
358  SKIPWS(s);
359  if (*s != '\"')
360  {
361  mutt_debug(LL_DEBUG1, "bogus INTERNALDATE entry: %s\n", s);
362  return -1;
363  }
364  s++;
365  ptmp = tmp;
366  while (*s && (*s != '\"') && (ptmp != (tmp + sizeof(tmp) - 1)))
367  *ptmp++ = *s++;
368  if (*s != '\"')
369  return -1;
370  s++; /* skip past the trailing " */
371  *ptmp = '\0';
372  h->received = mutt_date_parse_imap(tmp);
373  }
374  else if ((plen = mutt_istr_startswith(s, "RFC822.SIZE")))
375  {
376  s += plen;
377  SKIPWS(s);
378  ptmp = tmp;
379  while (isdigit((unsigned char) *s) && (ptmp != (tmp + sizeof(tmp) - 1)))
380  *ptmp++ = *s++;
381  *ptmp = '\0';
382  if (mutt_str_atol(tmp, &h->content_length) < 0)
383  return -1;
384  }
385  else if (mutt_istr_startswith(s, "BODY") ||
386  mutt_istr_startswith(s, "RFC822.HEADER"))
387  {
388  /* handle above, in msg_fetch_header */
389  return -2;
390  }
391  else if ((plen = mutt_istr_startswith(s, "MODSEQ")))
392  {
393  s += plen;
394  SKIPWS(s);
395  if (*s != '(')
396  {
397  mutt_debug(LL_DEBUG1, "bogus MODSEQ response: %s\n", s);
398  return -1;
399  }
400  s++;
401  while (*s && (*s != ')'))
402  s++;
403  if (*s == ')')
404  s++;
405  else
406  {
407  mutt_debug(LL_DEBUG1, "Unterminated MODSEQ response: %s\n", s);
408  return -1;
409  }
410  }
411  else if (*s == ')')
412  s++; /* end of request */
413  else if (*s)
414  {
415  /* got something i don't understand */
416  imap_error("msg_parse_fetch", s);
417  return -1;
418  }
419  }
420 
421  return 0;
422 }
time_t received
Definition: message.h:58
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
long content_length
Definition: message.h:59
int mutt_str_atol(const char *str, long *dst)
Convert ASCII string to a long.
Definition: string.c:193
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_error(const char *where, const char *msg)
show an error and abort
Definition: util.c:798
unsigned int uid
32-bit Message UID
Definition: message.h:44
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:287
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
Log at debug level 1.
Definition: logging.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
time_t mutt_date_parse_imap(const char *s)
Parse date of the form: DD-MMM-YYYY HH:MM:SS +ZZzz.
Definition: date.c:589
static char * msg_parse_flags(struct ImapHeader *h, char *s)
read a FLAGS token into an ImapHeader
Definition: message.c:222
struct ImapEmailData * edata
Definition: message.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ msg_fetch_header()

static int msg_fetch_header ( struct Mailbox m,
struct ImapHeader ih,
char *  buf,
FILE *  fp 
)
static

import IMAP FETCH response into an ImapHeader

Parameters
mMailbox
ihImapHeader
bufServer string containing FETCH response
fpConnection to server
Return values
0Success
-1String is not a fetch response
-2String is a corrupt fetch response

Expects string beginning with * n FETCH.

Definition at line 436 of file message.c.

437 {
438  int rc = -1; /* default now is that string isn't FETCH response */
439 
440  struct ImapAccountData *adata = imap_adata_get(m);
441 
442  if (buf[0] != '*')
443  return rc;
444 
445  /* skip to message number */
447  if (mutt_str_atoui(buf, &ih->edata->msn) < 0)
448  return rc;
449 
450  /* find FETCH tag */
452  if (!mutt_istr_startswith(buf, "FETCH"))
453  return rc;
454 
455  rc = -2; /* we've got a FETCH response, for better or worse */
456  buf = strchr(buf, '(');
457  if (!buf)
458  return rc;
459  buf++;
460 
461  /* FIXME: current implementation - call msg_parse_fetch - if it returns -2,
462  * read header lines and call it again. Silly. */
463  int parse_rc = msg_parse_fetch(ih, buf);
464  if (parse_rc == 0)
465  return 0;
466  if ((parse_rc != -2) || !fp)
467  return rc;
468 
469  unsigned int bytes = 0;
470  if (imap_get_literal_count(buf, &bytes) == 0)
471  {
472  imap_read_literal(fp, adata, bytes, NULL);
473 
474  /* we may have other fields of the FETCH _after_ the literal
475  * (eg Domino puts FLAGS here). Nothing wrong with that, either.
476  * This all has to go - we should accept literals and nonliterals
477  * interchangeably at any time. */
478  if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
479  return rc;
480 
481  if (msg_parse_fetch(ih, adata->buf) == -1)
482  return rc;
483  }
484 
485  rc = 0; /* success */
486 
487  /* subtract headers from message size - unfortunately only the subset of
488  * headers we've requested. */
489  ih->content_length -= bytes;
490 
491  return rc;
492 }
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
static int msg_parse_fetch(struct ImapHeader *h, char *s)
handle headers returned from header fetch
Definition: message.c:327
long content_length
Definition: message.h:59
int imap_read_literal(FILE *fp, struct ImapAccountData *adata, unsigned long bytes, struct Progress *pbar)
Read bytes bytes from server into file.
Definition: imap.c:573
unsigned int msn
Message Sequence Number.
Definition: message.h:45
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:287
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
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
IMAP-specific Account data -.
Definition: private.h:169
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
char * buf
Definition: private.h:189
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
struct ImapEmailData * edata
Definition: message.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ flush_buffer()

static int flush_buffer ( char *  buf,
size_t *  len,
struct Connection conn 
)
static

Write data to a connection.

Parameters
bufBuffer containing data
lenLength of buffer
connNetwork connection

Definition at line 500 of file message.c.

501 {
502  buf[*len] = '\0';
503  int rc = mutt_socket_write_n(conn, buf, *len);
504  *len = 0;
505  return rc;
506 }
#define mutt_socket_write_n(conn, buf, len)
Definition: mutt_socket.h:39
char * buf
Definition: private.h:189
+ Here is the caller graph for this function:

◆ query_abort_header_download()

static bool query_abort_header_download ( struct ImapAccountData adata)
static

Ask the user whether to abort the download.

Parameters
adataImap Account data
Return values
trueAbort the download

If the user hits ctrl-c during an initial header download for a mailbox, prompt whether to completely abort the download and close the mailbox.

Definition at line 516 of file message.c.

517 {
518  bool abort = false;
519 
520  mutt_flushinp();
521  /* L10N: This prompt is made if the user hits Ctrl-C when opening an IMAP mailbox */
522  if (mutt_yesorno(_("Abort download and close mailbox?"), MUTT_YES) == MUTT_YES)
523  {
524  abort = true;
525  imap_close_connection(adata);
526  }
527  SigInt = 0;
528 
529  return abort;
530 }
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:74
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:919
#define _(a)
Definition: message.h:28
void imap_close_connection(struct ImapAccountData *adata)
Close an IMAP connection.
Definition: imap.c:833
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:379
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alloc_msn_index()

static void alloc_msn_index ( struct ImapAccountData adata,
size_t  msn_count 
)
static

Create lookup table of MSN to Header.

Parameters
adataImap Account data
msn_countNumber of MSNs in use

Mapping from Message Sequence Number to Header

Definition at line 539 of file message.c.

540 {
541  struct ImapMboxData *mdata = adata->mailbox->mdata;
542  size_t new_size;
543 
544  if (msn_count <= mdata->msn_index_size)
545  return;
546 
547  /* This is a conservative check to protect against a malicious imap
548  * server. Most likely size_t is bigger than an unsigned int, but
549  * if msn_count is this big, we have a serious problem. */
550  if (msn_count >= (UINT_MAX / sizeof(struct Email *)))
551  {
552  mutt_error(_("Out of memory"));
553  mutt_exit(1);
554  }
555 
556  /* Add a little padding, like mx_allloc_memory() */
557  new_size = msn_count + 25;
558 
559  if (!mdata->msn_index)
560  mdata->msn_index = mutt_mem_calloc(new_size, sizeof(struct Email *));
561  else
562  {
563  mutt_mem_realloc(&mdata->msn_index, sizeof(struct Email *) * new_size);
564  memset(mdata->msn_index + mdata->msn_index_size, 0,
565  sizeof(struct Email *) * (new_size - mdata->msn_index_size));
566  }
567 
568  mdata->msn_index_size = new_size;
569 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
The envelope/body of an email.
Definition: email.h:37
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
size_t msn_index_size
allocation size
Definition: private.h:238
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
void * mdata
Driver specific data.
Definition: mailbox.h:136
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:137
IMAP-specific Mailbox data -.
Definition: private.h:216
#define mutt_error(...)
Definition: logging.h:84
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_alloc_uid_hash()

static void imap_alloc_uid_hash ( struct ImapAccountData adata,
unsigned int  msn_count 
)
static

Create a Hash Table for the UIDs.

Parameters
adataImap Account data
msn_countNumber of MSNs in use

This function is run after imap_alloc_msn_index, so we skip the malicious msn_count size check.

Definition at line 579 of file message.c.

580 {
581  struct ImapMboxData *mdata = adata->mailbox->mdata;
582  if (!mdata->uid_hash)
583  mdata->uid_hash = mutt_hash_int_new(MAX(6 * msn_count / 5, 30), MUTT_HASH_NO_FLAGS);
584 }
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
struct HashTable * mutt_hash_int_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with integer keys)
Definition: hash.c:277
#define MAX(a, b)
Definition: memory.h:30
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct HashTable * uid_hash
Definition: private.h:236
IMAP-specific Mailbox data -.
Definition: private.h:216
#define MUTT_HASH_NO_FLAGS
No flags are set.
Definition: hash.h:97
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_fetch_msn_seqset()

static unsigned int imap_fetch_msn_seqset ( struct Buffer buf,
struct ImapAccountData adata,
bool  evalhc,
unsigned int  msn_begin,
unsigned int  msn_end,
unsigned int *  fetch_msn_end 
)
static

Generate a sequence set.

Parameters
[in]bufBuffer for the result
[in]adataImap Account data
[in]evalhcIf true, check the Header Cache
[in]msn_beginFirst Message Sequence Number
[in]msn_endLast Message Sequence Number
[out]fetch_msn_endHighest Message Sequence Number fetched

Generates a more complicated sequence set after using the header cache, in case there are missing MSNs in the middle.

Definition at line 598 of file message.c.

601 {
602  struct ImapMboxData *mdata = adata->mailbox->mdata;
603  unsigned int max_headers_per_fetch = UINT_MAX;
604  bool first_chunk = true;
605  int state = 0; /* 1: single msn, 2: range of msn */
606  unsigned int msn;
607  unsigned int range_begin = 0;
608  unsigned int range_end = 0;
609  unsigned int msn_count = 0;
610 
611  mutt_buffer_reset(buf);
612  if (msn_end < msn_begin)
613  return 0;
614 
615  if (C_ImapFetchChunkSize > 0)
616  max_headers_per_fetch = C_ImapFetchChunkSize;
617 
618  if (!evalhc)
619  {
620  if (msn_end - msn_begin + 1 <= max_headers_per_fetch)
621  *fetch_msn_end = msn_end;
622  else
623  *fetch_msn_end = msn_begin + max_headers_per_fetch - 1;
624  mutt_buffer_printf(buf, "%u:%u", msn_begin, *fetch_msn_end);
625  return (*fetch_msn_end - msn_begin + 1);
626  }
627 
628  for (msn = msn_begin; msn <= (msn_end + 1); msn++)
629  {
630  if (msn_count < max_headers_per_fetch && msn <= msn_end && !mdata->msn_index[msn - 1])
631  {
632  msn_count++;
633 
634  switch (state)
635  {
636  case 1: /* single: convert to a range */
637  state = 2;
638  /* fallthrough */
639  case 2: /* extend range ending */
640  range_end = msn;
641  break;
642  default:
643  state = 1;
644  range_begin = msn;
645  break;
646  }
647  }
648  else if (state)
649  {
650  if (first_chunk)
651  first_chunk = false;
652  else
653  mutt_buffer_addch(buf, ',');
654 
655  if (state == 1)
656  mutt_buffer_add_printf(buf, "%u", range_begin);
657  else if (state == 2)
658  mutt_buffer_add_printf(buf, "%u:%u", range_begin, range_end);
659  state = 0;
660 
661  if ((mutt_buffer_len(buf) > 500) || (msn_count >= max_headers_per_fetch))
662  break;
663  }
664  }
665 
666  /* The loop index goes one past to terminate the range if needed. */
667  *fetch_msn_end = msn - 1;
668 
669  return msn_count;
670 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
void * mdata
Driver specific data.
Definition: mailbox.h:136
long C_ImapFetchChunkSize
Config: (imap) Download headers in blocks of this size.
Definition: config.c:43
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
IMAP-specific Mailbox data -.
Definition: private.h:216
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_changed_flag()

static void set_changed_flag ( struct Mailbox m,
struct Email e,
int  local_changes,
bool *  server_changes,
int  flag_name,
bool  old_hd_flag,
bool  new_hd_flag,
bool  h_flag 
)
static

Have the flags of an email changed.

Parameters
[in]mMailbox
[in]eEmail
[in]local_changesHas the local mailbox been changed?
[out]server_changesSet to true if the flag has changed
[in]flag_nameFlag to check, e.g. MUTT_FLAG
[in]old_hd_flagOld header flags
[in]new_hd_flagNew header flags
[in]h_flagEmail's value for flag_name

Sets server_changes to 1 if a change to a flag is made, or in the case of local_changes, if a change to a flag would have been made.

Definition at line 687 of file message.c.

690 {
691  /* If there are local_changes, we only want to note if the server
692  * flags have changed, so we can set a reopen flag in
693  * cmd_parse_fetch(). We don't want to count a local modification
694  * to the header flag as a "change". */
695  if ((old_hd_flag == new_hd_flag) && (local_changes != 0))
696  return;
697 
698  if (new_hd_flag == h_flag)
699  return;
700 
701  if (server_changes)
702  *server_changes = true;
703 
704  /* Local changes have priority */
705  if (local_changes == 0)
706  mutt_set_flag(m, e, flag_name, new_hd_flag);
707 }
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:67
+ Here is the caller graph for this function:

◆ read_headers_normal_eval_cache()

static int read_headers_normal_eval_cache ( struct ImapAccountData adata,
unsigned int  msn_end,
unsigned int  uid_next,
bool  store_flag_updates,
bool  eval_condstore 
)
static

Retrieve data from the header cache.

Parameters
adataImap Account data
msn_endLast Message Sequence number
uid_nextUID of next email
store_flag_updatesif true, save flags to the header cache
eval_condstoreif true, use CONDSTORE to fetch flags
Return values
0Success
-1Error

Without CONDSTORE or QRESYNC, we need to query all the current UIDs and update their flag state and current MSN.

For CONDSTORE, we still need to grab the existing UIDs and their MSN. The current flag state will be queried in read_headers_condstore_qresync_updates().

Definition at line 727 of file message.c.

730 {
731  struct Progress progress;
732  char buf[1024];
733 
734  struct Mailbox *m = adata->mailbox;
735  struct ImapMboxData *mdata = imap_mdata_get(m);
736  int idx = m->msg_count;
737 
738  if (m->verbose)
739  {
740  /* L10N: Comparing the cached data with the IMAP server's data */
741  mutt_progress_init(&progress, _("Evaluating cache..."), MUTT_PROGRESS_READ, msn_end);
742  }
743 
744  /* If we are using CONDSTORE's "FETCH CHANGEDSINCE", then we keep
745  * the flags in the header cache, and update them further below.
746  * Otherwise, we fetch the current state of the flags here. */
747  snprintf(buf, sizeof(buf), "UID FETCH 1:%u (UID%s)", uid_next - 1,
748  eval_condstore ? "" : " FLAGS");
749 
750  imap_cmd_start(adata, buf);
751 
752  int rc = IMAP_RES_CONTINUE;
753  int mfhrc = 0;
754  struct ImapHeader h;
755  for (int msgno = 1; rc == IMAP_RES_CONTINUE; msgno++)
756  {
757  if (SigInt && query_abort_header_download(adata))
758  return -1;
759 
760  if (m->verbose)
761  mutt_progress_update(&progress, msgno, -1);
762 
763  memset(&h, 0, sizeof(h));
764  h.edata = imap_edata_new();
765  do
766  {
767  rc = imap_cmd_step(adata);
768  if (rc != IMAP_RES_CONTINUE)
769  break;
770 
771  mfhrc = msg_fetch_header(m, &h, adata->buf, NULL);
772  if (mfhrc < 0)
773  continue;
774 
775  if (!h.edata->uid)
776  {
777  mutt_debug(LL_DEBUG2, "skipping hcache FETCH response for message number %d missing a UID\n",
778  h.edata->msn);
779  continue;
780  }
781 
782  if ((h.edata->msn < 1) || (h.edata->msn > msn_end))
783  {
784  mutt_debug(LL_DEBUG1, "skipping hcache FETCH response for unknown message number %d\n",
785  h.edata->msn);
786  continue;
787  }
788 
789  if (mdata->msn_index[h.edata->msn - 1])
790  {
791  mutt_debug(LL_DEBUG2, "skipping hcache FETCH for duplicate message %d\n",
792  h.edata->msn);
793  continue;
794  }
795 
796  struct Email *e = imap_hcache_get(mdata, h.edata->uid);
797  m->emails[idx] = e;
798  if (e)
799  {
800  mdata->max_msn = MAX(mdata->max_msn, h.edata->msn);
801  mdata->msn_index[h.edata->msn - 1] = e;
802  mutt_hash_int_insert(mdata->uid_hash, h.edata->uid, e);
803 
804  e->index = idx;
805  /* messages which have not been expunged are ACTIVE (borrowed from mh
806  * folders) */
807  e->active = true;
808  e->changed = false;
809  if (eval_condstore)
810  {
811  h.edata->read = e->read;
812  h.edata->old = e->old;
813  h.edata->deleted = e->deleted;
814  h.edata->flagged = e->flagged;
815  h.edata->replied = e->replied;
816  }
817  else
818  {
819  e->read = h.edata->read;
820  e->old = h.edata->old;
821  e->deleted = h.edata->deleted;
822  e->flagged = h.edata->flagged;
823  e->replied = h.edata->replied;
824  }
825 
826  /* mailbox->emails[msgno]->received is restored from mutt_hcache_restore */
827  e->edata = h.edata;
829  STAILQ_INIT(&e->tags);
830 
831  /* We take a copy of the tags so we can split the string */
832  char *tags_copy = mutt_str_dup(h.edata->flags_remote);
833  driver_tags_replace(&e->tags, tags_copy);
834  FREE(&tags_copy);
835 
836  m->msg_count++;
837  mailbox_size_add(m, e);
838 
839  /* If this is the first time we are fetching, we need to
840  * store the current state of flags back into the header cache */
841  if (!eval_condstore && store_flag_updates)
842  imap_hcache_put(mdata, e);
843 
844  h.edata = NULL;
845  idx++;
846  }
847  } while (mfhrc == -1);
848 
849  imap_edata_free((void **) &h.edata);
850 
851  if ((mfhrc < -1) || ((rc != IMAP_RES_CONTINUE) && (rc != IMAP_RES_OK)))
852  return -1;
853  }
854 
855  return 0;
856 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
static bool query_abort_header_download(struct ImapAccountData *adata)
Ask the user whether to abort the download.
Definition: message.c:516
int msg_count
Total number of messages.
Definition: mailbox.h:91
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
The envelope/body of an email.
Definition: email.h:37
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
void mailbox_size_add(struct Mailbox *m, const struct Email *e)
Add an email&#39;s size to the total size of a Mailbox.
Definition: mailbox.c:188
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:74
int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
Add an entry to the header cache.
Definition: util.c:516
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
bool changed
Email has been edited.
Definition: email.h:48
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1062
A progress bar.
Definition: progress.h:50
unsigned int max_msn
the largest MSN fetched so far
Definition: private.h:239
struct HashElem * mutt_hash_int_insert(struct HashTable *table, unsigned int intkey, void *data)
Add a new element to the Hash Table (with integer keys)
Definition: hash.c:339
#define MAX(a, b)
Definition: memory.h:30
bool read
Email is read.
Definition: email.h:51
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
Log at debug level 2.
Definition: logging.h:41
void imap_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: message.c:72
bool old
Email is seen, but unread.
Definition: email.h:50
#define STAILQ_INIT(head)
Definition: queue.h:369
static int msg_fetch_header(struct Mailbox *m, struct ImapHeader *ih, char *buf, FILE *fp)
import IMAP FETCH response into an ImapHeader
Definition: message.c:436
Progress tracks elements, according to C_ReadInc.
Definition: progress.h:42
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct TagList tags
For drivers that support server tagging.
Definition: email.h:107
struct HashTable * uid_hash
Definition: private.h:236
bool active
Message is not to be removed.
Definition: email.h:59
A mailbox.
Definition: mailbox.h:81
IMAP-specific header.
Definition: message.h:54
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:115
bool verbose
Display status messages?
Definition: mailbox.h:118
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
unsigned int uid_next
Definition: private.h:229
struct Email * imap_hcache_get(struct ImapMboxData *mdata, unsigned int uid)
Get a header cache entry by its UID.
Definition: util.c:491
Log at debug level 1.
Definition: logging.h:40
bool flagged
Marked important?
Definition: email.h:43
IMAP-specific Mailbox data -.
Definition: private.h:216
char * buf
Definition: private.h:189
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:109
bool replied
Email has been replied to.
Definition: email.h:54
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
bool driver_tags_replace(struct TagList *head, char *tags)
Replace all tags.
Definition: tags.c:183
static struct ImapEmailData * imap_edata_new(void)
Create a new ImapEmailData.
Definition: message.c:88
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ read_headers_qresync_eval_cache()

static int read_headers_qresync_eval_cache ( struct ImapAccountData adata,
char *  uid_seqset 
)
static

Retrieve data from the header cache.

Parameters
adataImap Account data
uid_seqsetSequence Set of UIDs
Return values
>=0Success
-1Error

For QRESYNC, we grab the UIDs in order by MSN from the header cache.

In read_headers_condstore_qresync_updates(). We will update change flags using CHANGEDSINCE and find out what UIDs have been expunged using VANISHED.

Definition at line 870 of file message.c.

871 {
872  int rc;
873  unsigned int uid = 0;
874 
875  mutt_debug(LL_DEBUG2, "Reading uid seqset from header cache\n");
876  struct Mailbox *m = adata->mailbox;
877  struct ImapMboxData *mdata = adata->mailbox->mdata;
878  unsigned int msn = 1;
879 
880  struct SeqsetIterator *iter = mutt_seqset_iterator_new(uid_seqset);
881  if (!iter)
882  return -1;
883 
884  while ((rc = mutt_seqset_iterator_next(iter, &uid)) == 0)
885  {
886  /* The seqset may contain more headers than the fetch request, so
887  * we need to watch and reallocate the context and msn_index */
888  if (msn > mdata->msn_index_size)
889  alloc_msn_index(adata, msn);
890 
891  struct Email *e = imap_hcache_get(mdata, uid);
892  if (e)
893  {
894  mdata->max_msn = MAX(mdata->max_msn, msn);
895  mdata->msn_index[msn - 1] = e;
896 
897  if (m->msg_count >= m->email_max)
898  mx_alloc_memory(m);
899 
900  struct ImapEmailData *edata = imap_edata_new();
901  e->edata = edata;
903 
904  e->index = m->msg_count;
905  e->active = true;
906  e->changed = false;
907  edata->read = e->read;
908  edata->old = e->old;
909  edata->deleted = e->deleted;
910  edata->flagged = e->flagged;
911  edata->replied = e->replied;
912 
913  edata->msn = msn;
914  edata->uid = uid;
915  mutt_hash_int_insert(mdata->uid_hash, uid, e);
916 
917  mailbox_size_add(m, e);
918  m->emails[m->msg_count++] = e;
919 
920  msn++;
921  }
922  }
923 
925 
926  return rc;
927 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
void mailbox_size_add(struct Mailbox *m, const struct Email *e)
Add an email&#39;s size to the total size of a Mailbox.
Definition: mailbox.c:188
size_t msn_index_size
allocation size
Definition: private.h:238
struct SeqsetIterator * mutt_seqset_iterator_new(const char *seqset)
Create a new Sequence Set Iterator.
Definition: util.c:1209
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1232
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
bool changed
Email has been edited.
Definition: email.h:48
unsigned int msn
Message Sequence Number.
Definition: message.h:45
unsigned int max_msn
the largest MSN fetched so far
Definition: private.h:239
struct HashElem * mutt_hash_int_insert(struct HashTable *table, unsigned int intkey, void *data)
Add a new element to the Hash Table (with integer keys)
Definition: hash.c:339
bool flagged
Definition: message.h:39
#define MAX(a, b)
Definition: memory.h:30
bool deleted
Definition: message.h:38
bool read
Email is read.
Definition: email.h:51
Log at debug level 2.
Definition: logging.h:41
void imap_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: message.c:72
bool old
Email is seen, but unread.
Definition: email.h:50
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct HashTable * uid_hash
Definition: private.h:236
bool active
Message is not to be removed.
Definition: email.h:59
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
unsigned int uid
32-bit Message UID
Definition: message.h:44
A mailbox.
Definition: mailbox.h:81
void mutt_seqset_iterator_free(struct SeqsetIterator **ptr)
Free a Sequence Set Iterator.
Definition: util.c:1289
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:115
bool replied
Definition: message.h:40
bool old
Definition: message.h:37
struct Email * imap_hcache_get(struct ImapMboxData *mdata, unsigned int uid)
Get a header cache entry by its UID.
Definition: util.c:491
bool flagged
Marked important?
Definition: email.h:43
IMAP-specific Mailbox data -.
Definition: private.h:216
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:109
bool replied
Email has been replied to.
Definition: email.h:54
int index
The absolute (unsorted) message number.
Definition: email.h:86
bool read
Definition: message.h:36
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static void alloc_msn_index(struct ImapAccountData *adata, size_t msn_count)
Create lookup table of MSN to Header.
Definition: message.c:539
IMAP-specific Email data -.
Definition: message.h:33
static struct ImapEmailData * imap_edata_new(void)
Create a new ImapEmailData.
Definition: message.c:88
int mutt_seqset_iterator_next(struct SeqsetIterator *iter, unsigned int *next)
Get the next UID from a Sequence Set.
Definition: util.c:1230
UID Sequence Set Iterator.
Definition: private.h:248
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ read_headers_condstore_qresync_updates()

static int read_headers_condstore_qresync_updates ( struct ImapAccountData adata,
unsigned int  msn_end,
unsigned int  uid_next,
unsigned long long  hc_modseq,
bool  eval_qresync 
)
static

Retrieve updates from the server.

Parameters
adataImap Account data
msn_endLast Message Sequence number
uid_nextUID of next email
hc_modseqTimestamp of last Header Cache update
eval_qresyncIf true, use QRESYNC
Return values
0Success
-1Error

CONDSTORE and QRESYNC use FETCH extensions to grab updates.

Definition at line 941 of file message.c.

944 {
945  struct Progress progress;
946  char buf[1024];
947  unsigned int header_msn = 0;
948 
949  struct Mailbox *m = adata->mailbox;
950  struct ImapMboxData *mdata = imap_mdata_get(m);
951 
952  if (m->verbose)
953  {
954  /* L10N: Fetching IMAP flag changes, using the CONDSTORE extension */
955  mutt_progress_init(&progress, _("Fetching flag updates..."), MUTT_PROGRESS_READ, msn_end);
956  }
957 
958  snprintf(buf, sizeof(buf), "UID FETCH 1:%u (FLAGS) (CHANGEDSINCE %llu%s)",
959  uid_next - 1, hc_modseq, eval_qresync ? " VANISHED" : "");
960 
961  imap_cmd_start(adata, buf);
962 
963  int rc = IMAP_RES_CONTINUE;
964  for (int msgno = 1; rc == IMAP_RES_CONTINUE; msgno++)
965  {
966  if (SigInt && query_abort_header_download(adata))
967  return -1;
968 
969  if (m->verbose)
970  mutt_progress_update(&progress, msgno, -1);
971 
972  /* cmd_parse_fetch will update the flags */
973  rc = imap_cmd_step(adata);
974  if (rc != IMAP_RES_CONTINUE)
975  break;
976 
977  /* so we just need to grab the header and persist it back into
978  * the header cache */
979  char *fetch_buf = adata->buf;
980  if (fetch_buf[0] != '*')
981  continue;
982 
983  fetch_buf = imap_next_word(fetch_buf);
984  if (!isdigit((unsigned char) *fetch_buf) || (mutt_str_atoui(fetch_buf, &header_msn) < 0))
985  continue;
986 
987  if ((header_msn < 1) || (header_msn > msn_end) || !mdata->msn_index[header_msn - 1])
988  {
989  mutt_debug(LL_DEBUG1, "skipping CONDSTORE flag update for unknown message number %u\n",
990  header_msn);
991  continue;
992  }
993 
994  imap_hcache_put(mdata, mdata->msn_index[header_msn - 1]);
995  }
996 
997  /* The IMAP flag setting as part of cmd_parse_fetch() ends up
998  * flipping these on. */
999  mdata->check_status &= ~IMAP_FLAGS_PENDING;
1000  m->changed = false;
1001 
1002  /* VANISHED handling: we need to empty out the messages */
1003  if (mdata->reopen & IMAP_EXPUNGE_PENDING)
1004  {
1005  imap_hcache_close(mdata);
1007 
1008  imap_hcache_open(adata, mdata);
1009  mdata->reopen &= ~IMAP_EXPUNGE_PENDING;
1010  }
1011 
1012  /* undo expunge count updates.
1013  * ctx_update() will do this at the end of the header fetch. */
1014  m->vcount = 0;
1015  m->msg_tagged = 0;
1016  m->msg_deleted = 0;
1017  m->msg_new = 0;
1018  m->msg_unread = 0;
1019  m->msg_flagged = 0;
1020  m->changed = false;
1021 
1022  return 0;
1023 }
static bool query_abort_header_download(struct ImapAccountData *adata)
Ask the user whether to abort the download.
Definition: message.c:516
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:96
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:93
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:74
int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
Add an entry to the header cache.
Definition: util.c:516
void imap_expunge_mailbox(struct Mailbox *m)
Purge messages from the server.
Definition: imap.c:657
#define IMAP_FLAGS_PENDING
Flags have changed on the server.
Definition: private.h:69
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:222
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1062
A progress bar.
Definition: progress.h:50
int vcount
The number of virtual messages.
Definition: mailbox.h:102
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition: util.c:475
ImapOpenFlags check_status
Flags, e.g. IMAP_NEWMAIL_PENDING.
Definition: private.h:223
Progress tracks elements, according to C_ReadInc.
Definition: progress.h:42
void * mdata
Driver specific data.
Definition: mailbox.h:136
A mailbox.
Definition: mailbox.h:81
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:287
bool verbose
Display status messages?
Definition: mailbox.h:118
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:97
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
unsigned int uid_next
Definition: private.h:229
Log at debug level 1.
Definition: logging.h:40
IMAP-specific Mailbox data -.
Definition: private.h:216
char * buf
Definition: private.h:189
int msg_new
Number of new messages.
Definition: mailbox.h:95
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata)
Open a header cache.
Definition: util.c:435
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:67
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ read_headers_fetch_new()

static int read_headers_fetch_new ( struct Mailbox m,
unsigned int  msn_begin,
unsigned int  msn_end,
bool  evalhc,
unsigned int *  maxuid,
bool  initial_download 
)
static

Retrieve new messages from the server.

Parameters
[in]mImap Selected Mailbox
[in]msn_beginFirst Message Sequence number
[in]msn_endLast Message Sequence number
[in]evalhcIf true, check the Header Cache
[out]maxuidHighest UID seen
[in]initial_downloadtrue, if this is the first opening of the mailbox
Return values
0Success
-1Error

Definition at line 1037 of file message.c.

1040 {
1041  int rc, mfhrc = 0, retval = -1;
1042  unsigned int fetch_msn_end = 0;
1043  struct Progress progress;
1044  char *hdrreq = NULL;
1045  struct Buffer *tempfile = NULL;
1046  FILE *fp = NULL;
1047  struct ImapHeader h;
1048  struct Buffer *buf = NULL;
1049  static const char *const want_headers =
1050  "DATE FROM SENDER SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE "
1051  "CONTENT-DESCRIPTION IN-REPLY-TO REPLY-TO LINES LIST-POST X-LABEL "
1052  "X-ORIGINAL-TO";
1053 
1054  struct ImapAccountData *adata = imap_adata_get(m);
1055  struct ImapMboxData *mdata = imap_mdata_get(m);
1056  int idx = m->msg_count;
1057 
1058  if (!adata || (adata->mailbox != m))
1059  return -1;
1060 
1061  struct Buffer *hdr_list = mutt_buffer_pool_get();
1062  mutt_buffer_strcpy(hdr_list, want_headers);
1063  if (C_ImapHeaders)
1064  {
1065  mutt_buffer_addch(hdr_list, ' ');
1066  mutt_buffer_addstr(hdr_list, C_ImapHeaders);
1067  }
1068 #ifdef USE_AUTOCRYPT
1069  if (C_Autocrypt)
1070  {
1071  mutt_buffer_addch(hdr_list, ' ');
1072  mutt_buffer_addstr(hdr_list, "AUTOCRYPT");
1073  }
1074 #endif
1075 
1076  if (adata->capabilities & IMAP_CAP_IMAP4REV1)
1077  {
1078  mutt_str_asprintf(&hdrreq, "BODY.PEEK[HEADER.FIELDS (%s)]", mutt_b2s(hdr_list));
1079  }
1080  else if (adata->capabilities & IMAP_CAP_IMAP4)
1081  {
1082  mutt_str_asprintf(&hdrreq, "RFC822.HEADER.LINES (%s)", mutt_b2s(hdr_list));
1083  }
1084  else
1085  { /* Unable to fetch headers for lower versions */
1086  mutt_error(_("Unable to fetch headers from this IMAP server version"));
1087  goto bail;
1088  }
1089 
1090  mutt_buffer_pool_release(&hdr_list);
1091 
1092  /* instead of downloading all headers and then parsing them, we parse them
1093  * as they come in. */
1094  tempfile = mutt_buffer_pool_get();
1095  mutt_buffer_mktemp(tempfile);
1096  fp = mutt_file_fopen(mutt_b2s(tempfile), "w+");
1097  if (!fp)
1098  {
1099  mutt_error(_("Could not create temporary file %s"), mutt_b2s(tempfile));
1100  goto bail;
1101  }
1102  unlink(mutt_b2s(tempfile));
1103  mutt_buffer_pool_release(&tempfile);
1104 
1105  if (m->verbose)
1106  {
1107  mutt_progress_init(&progress, _("Fetching message headers..."),
1108  MUTT_PROGRESS_READ, msn_end);
1109  }
1110 
1111  buf = mutt_buffer_pool_get();
1112 
1113  /* NOTE:
1114  * The (fetch_msn_end < msn_end) used to be important to prevent
1115  * an infinite loop, in the event the server did not return all
1116  * the headers (due to a pending expunge, for example).
1117  *
1118  * I believe the new chunking imap_fetch_msn_seqset()
1119  * implementation and "msn_begin = fetch_msn_end + 1" assignment
1120  * at the end of the loop makes the comparison unneeded, but to be
1121  * cautious I'm keeping it.
1122  */
1123  while ((fetch_msn_end < msn_end) &&
1124  imap_fetch_msn_seqset(buf, adata, evalhc, msn_begin, msn_end, &fetch_msn_end))
1125  {
1126  char *cmd = NULL;
1127  mutt_str_asprintf(&cmd, "FETCH %s (UID FLAGS INTERNALDATE RFC822.SIZE %s)",
1128  mutt_b2s(buf), hdrreq);
1129  imap_cmd_start(adata, cmd);
1130  FREE(&cmd);
1131 
1132  rc = IMAP_RES_CONTINUE;
1133  for (int msgno = msn_begin; rc == IMAP_RES_CONTINUE; msgno++)
1134  {
1135  if (initial_download && SigInt && query_abort_header_download(adata))
1136  goto bail;
1137 
1138  if (m->verbose)
1139  mutt_progress_update(&progress, msgno, -1);
1140 
1141  rewind(fp);
1142  memset(&h, 0, sizeof(h));
1143  h.edata = imap_edata_new();
1144 
1145  /* this DO loop does two things:
1146  * 1. handles untagged messages, so we can try again on the same msg
1147  * 2. fetches the tagged response at the end of the last message. */
1148  do
1149  {
1150  rc = imap_cmd_step(adata);
1151  if (rc != IMAP_RES_CONTINUE)
1152  break;
1153 
1154  mfhrc = msg_fetch_header(m, &h, adata->buf, fp);
1155  if (mfhrc < 0)
1156  continue;
1157 
1158  if (!ftello(fp))
1159  {
1160  mutt_debug(LL_DEBUG2, "ignoring fetch response with no body\n");
1161  continue;
1162  }
1163 
1164  /* make sure we don't get remnants from older larger message headers */
1165  fputs("\n\n", fp);
1166 
1167  if ((h.edata->msn < 1) || (h.edata->msn > fetch_msn_end))
1168  {
1169  mutt_debug(LL_DEBUG1, "skipping FETCH response for unknown message number %d\n",
1170  h.edata->msn);
1171  continue;
1172  }
1173 
1174  /* May receive FLAGS updates in a separate untagged response */
1175  if (mdata->msn_index[h.edata->msn - 1])
1176  {
1177  mutt_debug(LL_DEBUG2, "skipping FETCH response for duplicate message %d\n",
1178  h.edata->msn);
1179  continue;
1180  }
1181 
1182  struct Email *e = email_new();
1183  m->emails[idx] = e;
1184 
1185  mdata->max_msn = MAX(mdata->max_msn, h.edata->msn);
1186  mdata->msn_index[h.edata->msn - 1] = e;
1187  mutt_hash_int_insert(mdata->uid_hash, h.edata->uid, e);
1188 
1189  e->index = idx;
1190  /* messages which have not been expunged are ACTIVE (borrowed from mh
1191  * folders) */
1192  e->active = true;
1193  e->changed = false;
1194  e->read = h.edata->read;
1195  e->old = h.edata->old;
1196  e->deleted = h.edata->deleted;
1197  e->flagged = h.edata->flagged;
1198  e->replied = h.edata->replied;
1199  e->received = h.received;
1200  e->edata = (void *) (h.edata);
1202  STAILQ_INIT(&e->tags);
1203 
1204  /* We take a copy of the tags so we can split the string */
1205  char *tags_copy = mutt_str_dup(h.edata->flags_remote);
1206  driver_tags_replace(&e->tags, tags_copy);
1207  FREE(&tags_copy);
1208 
1209  if (*maxuid < h.edata->uid)
1210  *maxuid = h.edata->uid;
1211 
1212  rewind(fp);
1213  /* NOTE: if Date: header is missing, mutt_rfc822_read_header depends
1214  * on h.received being set */
1215  e->env = mutt_rfc822_read_header(fp, e, false, false);
1216  /* body built as a side-effect of mutt_rfc822_read_header */
1217  e->body->length = h.content_length;
1218  mailbox_size_add(m, e);
1219 
1220 #ifdef USE_HCACHE
1221  imap_hcache_put(mdata, e);
1222 #endif /* USE_HCACHE */
1223 
1224  m->msg_count++;
1225 
1226  h.edata = NULL;
1227  idx++;
1228  } while (mfhrc == -1);
1229 
1230  imap_edata_free((void **) &h.edata);
1231 
1232  if ((mfhrc < -1) || ((rc != IMAP_RES_CONTINUE) && (rc != IMAP_RES_OK)))
1233  goto bail;
1234  }
1235 
1236  /* In case we get new mail while fetching the headers. */
1237  if (mdata->reopen & IMAP_NEWMAIL_PENDING)
1238  {
1239  msn_end = mdata->new_mail_count;
1240  while (msn_end > m->email_max)
1241  mx_alloc_memory(m);
1242  alloc_msn_index(adata, msn_end);
1243  mdata->reopen &= ~IMAP_NEWMAIL_PENDING;
1244  mdata->new_mail_count = 0;
1245  }
1246 
1247  /* Note: RFC3501 section 7.4.1 and RFC7162 section 3.2.10.2 say we
1248  * must not get any EXPUNGE/VANISHED responses in the middle of a
1249  * FETCH, nor when no command is in progress (e.g. between the
1250  * chunked FETCH commands). We previously tried to be robust by
1251  * setting:
1252  * msn_begin = mdata->max_msn + 1;
1253  * but with chunking (and the mythical header cache holes) this
1254  * may not be correct. So here we must assume the msn values have
1255  * not been altered during or after the fetch. */
1256  msn_begin = fetch_msn_end + 1;
1257  }
1258 
1259  retval = 0;
1260 
1261 bail:
1262  mutt_buffer_pool_release(&hdr_list);
1264  mutt_buffer_pool_release(&tempfile);
1265  mutt_file_fclose(&fp);
1266  FREE(&hdrreq);
1267 
1268  return retval;
1269 }
char * C_ImapHeaders
Config: (imap) Additional email headers to download when getting index.
Definition: config.c:44
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
#define IMAP_CAP_IMAP4
Server supports IMAP4.
Definition: private.h:122
static bool query_abort_header_download(struct ImapAccountData *adata)
Ask the user whether to abort the download.
Definition: message.c:516
int msg_count
Total number of messages.
Definition: mailbox.h:91
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
The envelope/body of an email.
Definition: email.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
struct Body * body
List of MIME parts.
Definition: email.h:91
void mailbox_size_add(struct Mailbox *m, const struct Email *e)
Add an email&#39;s size to the total size of a Mailbox.
Definition: mailbox.c:188
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:74
bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: config.c:37
int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
Add an entry to the header cache.
Definition: util.c:516
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:222
String manipulation buffer.
Definition: buffer.h:33
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1232
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
bool changed
Email has been edited.
Definition: email.h:48
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1062
A progress bar.
Definition: progress.h:50
static unsigned int imap_fetch_msn_seqset(struct Buffer *buf, struct ImapAccountData *adata, bool evalhc, unsigned int msn_begin, unsigned int msn_end, unsigned int *fetch_msn_end)
Generate a sequence set.
Definition: message.c:598
unsigned int max_msn
the largest MSN fetched so far
Definition: private.h:239
struct HashElem * mutt_hash_int_insert(struct HashTable *table, unsigned int intkey, void *data)
Add a new element to the Hash Table (with integer keys)
Definition: hash.c:339
unsigned int new_mail_count
Set when EXISTS notifies of new mail.
Definition: private.h:224
#define MAX(a, b)
Definition: memory.h:30
bool read
Email is read.
Definition: email.h:51
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
Log at debug level 2.
Definition: logging.h:41
void imap_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: message.c:72
bool old
Email is seen, but unread.
Definition: email.h:50
#define STAILQ_INIT(head)
Definition: queue.h:369
static int msg_fetch_header(struct Mailbox *m, struct ImapHeader *ih, char *buf, FILE *fp)
import IMAP FETCH response into an ImapHeader
Definition: message.c:436
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Envelope * env
Envelope information.
Definition: email.h:90
Progress tracks elements, according to C_ReadInc.
Definition: progress.h:42
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct TagList tags
For drivers that support server tagging.
Definition: email.h:107
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
struct HashTable * uid_hash
Definition: private.h:236
#define mutt_b2s(buf)
Definition: buffer.h:41
#define IMAP_CAP_IMAP4REV1
Server supports IMAP4rev1.
Definition: private.h:123
bool active
Message is not to be removed.
Definition: email.h:59
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
IMAP-specific header.
Definition: message.h:54
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:115
bool verbose
Display status messages?
Definition: mailbox.h:118
ImapCapFlags capabilities
Definition: private.h:185
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
IMAP-specific Account data -.
Definition: private.h:169
Log at debug level 1.
Definition: logging.h:40
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
bool flagged
Marked important?
Definition: email.h:43
IMAP-specific Mailbox data -.
Definition: private.h:216
char * buf
Definition: private.h:189
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:109
#define mutt_error(...)
Definition: logging.h:84
bool replied
Email has been replied to.
Definition: email.h:54
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: private.h:68
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define FREE(x)
Definition: memory.h:40
struct Email * email_new(void)
Create a new Email.
Definition: email.c:72
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static void alloc_msn_index(struct ImapAccountData *adata, size_t msn_count)
Create lookup table of MSN to Header.
Definition: message.c:539
bool driver_tags_replace(struct TagList *head, char *tags)
Replace all tags.
Definition: tags.c:183
static struct ImapEmailData * imap_edata_new(void)
Create a new ImapEmailData.
Definition: message.c:88
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1100
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1111
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_read_headers()

int imap_read_headers ( struct Mailbox m,
unsigned int  msn_begin,
unsigned int  msn_end,
bool  initial_download 
)

Read headers from the server.

Parameters
mImap Selected Mailbox
msn_beginFirst Message Sequence Number
msn_endLast Message Sequence Number
initial_downloadtrue, if this is the first opening of the mailbox
Return values
numLast MSN
-1Failure

Changed to read many headers instead of just one. It will return the msn of the last message read. It will return a value other than msn_end if mail comes in while downloading headers (in theory).

Definition at line 1284 of file message.c.

1286 {
1287  int oldmsgcount;
1288  unsigned int maxuid = 0;
1289  int retval = -1;
1290  bool evalhc = false;
1291 
1292 #ifdef USE_HCACHE
1293  void *uidvalidity = NULL;
1294  void *puid_next = NULL;
1295  unsigned int uid_next = 0;
1296  bool has_condstore = false;
1297  bool has_qresync = false;
1298  bool eval_condstore = false;
1299  bool eval_qresync = false;
1300  unsigned long long *pmodseq = NULL;
1301  unsigned long long hc_modseq = 0;
1302  char *uid_seqset = NULL;
1303 #endif /* USE_HCACHE */
1304 
1305  struct ImapAccountData *adata = imap_adata_get(m);
1306  struct ImapMboxData *mdata = imap_mdata_get(m);
1307  if (!adata || (adata->mailbox != m))
1308  return -1;
1309 
1310  /* make sure context has room to hold the mailbox */
1311  while (msn_end > m->email_max)
1312  mx_alloc_memory(m);
1313  alloc_msn_index(adata, msn_end);
1314  imap_alloc_uid_hash(adata, msn_end);
1315 
1316  oldmsgcount = m->msg_count;
1318  mdata->new_mail_count = 0;
1319 
1320 #ifdef USE_HCACHE
1321  imap_hcache_open(adata, mdata);
1322 
1323  if (mdata->hcache && initial_download)
1324  {
1325  size_t dlen = 0;
1326  uidvalidity = mutt_hcache_fetch_raw(mdata->hcache, "/UIDVALIDITY", 12, &dlen);
1327  puid_next = mutt_hcache_fetch_raw(mdata->hcache, "/UIDNEXT", 8, &dlen);
1328  if (puid_next)
1329  {
1330  uid_next = *(unsigned int *) puid_next;
1331  mutt_hcache_free_raw(mdata->hcache, &puid_next);
1332  }
1333 
1334  if (mdata->modseq)
1335  {
1337  has_condstore = true;
1338 
1339  /* If IMAP_CAP_QRESYNC and ImapQResync then NeoMutt sends ENABLE QRESYNC.
1340  * If we receive an ENABLED response back, then adata->qresync is set. */
1341  if (adata->qresync)
1342  has_qresync = true;
1343  }
1344 
1345  if (uidvalidity && uid_next && (*(uint32_t *) uidvalidity == mdata->uidvalidity))
1346  {
1347  size_t dlen2 = 0;
1348  evalhc = true;
1349  pmodseq = mutt_hcache_fetch_raw(mdata->hcache, "/MODSEQ", 7, &dlen2);
1350  if (pmodseq)
1351  {
1352  hc_modseq = *pmodseq;
1353  mutt_hcache_free_raw(mdata->hcache, (void **) &pmodseq);
1354  }
1355  if (hc_modseq)
1356  {
1357  if (has_qresync)
1358  {
1359  uid_seqset = imap_hcache_get_uid_seqset(mdata);
1360  if (uid_seqset)
1361  eval_qresync = true;
1362  }
1363 
1364  if (!eval_qresync && has_condstore)
1365  eval_condstore = true;
1366  }
1367  }
1368  mutt_hcache_free_raw(mdata->hcache, &uidvalidity);
1369  }
1370  if (evalhc)
1371  {
1372  if (eval_qresync)
1373  {
1374  if (read_headers_qresync_eval_cache(adata, uid_seqset) < 0)
1375  goto bail;
1376  }
1377  else
1378  {
1379  if (read_headers_normal_eval_cache(adata, msn_end, uid_next, has_condstore || has_qresync,
1380  eval_condstore) < 0)
1381  goto bail;
1382  }
1383 
1384  if ((eval_condstore || eval_qresync) && (hc_modseq != mdata->modseq))
1385  {
1386  if (read_headers_condstore_qresync_updates(adata, msn_end, uid_next,
1387  hc_modseq, eval_qresync) < 0)
1388  {
1389  goto bail;
1390  }
1391  }
1392 
1393  /* Look for the first empty MSN and start there */
1394  while (msn_begin <= msn_end)
1395  {
1396  if (!mdata->msn_index[msn_begin - 1])
1397  break;
1398  msn_begin++;
1399  }
1400  }
1401 #endif /* USE_HCACHE */
1402 
1403  if (read_headers_fetch_new(m, msn_begin, msn_end, evalhc, &maxuid, initial_download) < 0)
1404  goto bail;
1405 
1406  if (maxuid && (mdata->uid_next < maxuid + 1))
1407  mdata->uid_next = maxuid + 1;
1408 
1409 #ifdef USE_HCACHE
1410  mutt_hcache_store_raw(mdata->hcache, "/UIDVALIDITY", 12, &mdata->uidvalidity,
1411  sizeof(mdata->uidvalidity));
1412  if (maxuid && (mdata->uid_next < maxuid + 1))
1413  {
1414  mutt_debug(LL_DEBUG2, "Overriding UIDNEXT: %u -> %u\n", mdata->uid_next, maxuid + 1);
1415  mdata->uid_next = maxuid + 1;
1416  }
1417  if (mdata->uid_next > 1)
1418  {
1419  mutt_hcache_store_raw(mdata->hcache, "/UIDNEXT", 8, &mdata->uid_next,
1420  sizeof(mdata->uid_next));
1421  }
1422 
1423  /* We currently only sync CONDSTORE and QRESYNC on the initial download.
1424  * To do it more often, we'll need to deal with flag updates combined with
1425  * unsync'ed local flag changes. We'll also need to properly sync flags to
1426  * the header cache on close. I'm not sure it's worth the added complexity. */
1427  if (initial_download)
1428  {
1429  if (has_condstore || has_qresync)
1430  {
1431  mutt_hcache_store_raw(mdata->hcache, "/MODSEQ", 7, &mdata->modseq,
1432  sizeof(mdata->modseq));
1433  }
1434  else
1435  mutt_hcache_delete_record(mdata->hcache, "/MODSEQ", 7);
1436 
1437  if (has_qresync)
1439  else
1441  }
1442 #endif /* USE_HCACHE */
1443 
1444  if (m->msg_count > oldmsgcount)
1445  {
1446  /* TODO: it's not clear to me why we are calling mx_alloc_memory
1447  * yet again. */
1448  mx_alloc_memory(m);
1449  }
1450 
1451  mdata->reopen |= IMAP_REOPEN_ALLOW;
1452 
1453  retval = msn_end;
1454 
1455 bail:
1456 #ifdef USE_HCACHE
1457  imap_hcache_close(mdata);
1458  FREE(&uid_seqset);
1459 #endif /* USE_HCACHE */
1460 
1461  return retval;
1462 }
int msg_count
Total number of messages.
Definition: mailbox.h:91
static int read_headers_normal_eval_cache(struct ImapAccountData *adata, unsigned int msn_end, unsigned int uid_next, bool store_flag_updates, bool eval_condstore)
Retrieve data from the header cache.
Definition: message.c:727
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
uint32_t uidvalidity
Definition: private.h:228
#define IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition: private.h:65
int imap_hcache_store_uid_seqset(struct ImapMboxData *mdata)
Store a UID Sequence Set in the header cache.
Definition: util.c:551
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:222
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1232
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
struct HeaderCache * hcache
Definition: private.h:242
void mutt_hcache_free_raw(struct HeaderCache *hc, void **data)
Multiplexor for StoreOps::free.
Definition: hcache.c:508
char * imap_hcache_get_uid_seqset(struct ImapMboxData *mdata)
Get a UID Sequence Set from the header cache.
Definition: util.c:587
bool C_ImapCondstore
Config: (imap) Enable the CONDSTORE extension.
Definition: config.c:38
unsigned int new_mail_count
Set when EXISTS notifies of new mail.
Definition: private.h:224
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition: util.c:475
Log at debug level 2.
Definition: logging.h:41
static void imap_alloc_uid_hash(struct ImapAccountData *adata, unsigned int msn_count)
Create a Hash Table for the UIDs.
Definition: message.c:579
void * mdata
Driver specific data.
Definition: mailbox.h:136
unsigned long long modseq
Definition: private.h:230
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:598
bool qresync
true, if QRESYNC is successfully ENABLE&#39;d
Definition: private.h:193
ImapCapFlags capabilities
Definition: private.h:185
static int read_headers_fetch_new(struct Mailbox *m, unsigned int msn_begin, unsigned int msn_end, bool evalhc, unsigned int *maxuid, bool initial_download)
Retrieve new messages from the server.
Definition: message.c:1037
static int read_headers_qresync_eval_cache(struct ImapAccountData *adata, char *uid_seqset)
Retrieve data from the header cache.
Definition: message.c:870
IMAP-specific Account data -.
Definition: private.h:169
unsigned int uid_next
Definition: private.h:229
static int read_headers_condstore_qresync_updates(struct ImapAccountData *adata, unsigned int msn_end, unsigned int uid_next, unsigned long long hc_modseq, bool eval_qresync)
Retrieve updates from the server.
Definition: message.c:941
#define IMAP_CAP_CONDSTORE
RFC7162.
Definition: private.h:136
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
IMAP-specific Mailbox data -.
Definition: private.h:216
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: private.h:68
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static void alloc_msn_index(struct ImapAccountData *adata, size_t msn_count)
Create lookup table of MSN to Header.
Definition: message.c:539
int mutt_hcache_store_raw(struct HeaderCache *hc, const char *key, size_t keylen, void *data, size_t dlen)
store a key / data pair
Definition: hcache.c:578
int imap_hcache_clear_uid_seqset(struct ImapMboxData *mdata)
Delete a UID Sequence Set from the header cache.
Definition: util.c:573
void * mutt_hcache_fetch_raw(struct HeaderCache *hc, const char *key, size_t keylen, size_t *dlen)
Fetch a message&#39;s header from the cache.
Definition: hcache.c:490
void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata)
Open a header cache.
Definition: util.c:435
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_append_message()

int imap_append_message ( struct Mailbox m,
struct Message msg 
)

Write an email back to the server.

Parameters
mMailbox
msgMessage to save
Return values
0Success
-1Failure

Definition at line 1471 of file message.c.

1472 {
1473  if (!m || !msg)
1474  return -1;
1475 
1476  FILE *fp = NULL;
1477  char buf[1024 * 2];
1478  char internaldate[IMAP_DATELEN];
1479  char imap_flags[128];
1480  size_t len;
1481  struct Progress progress;
1482  size_t sent;
1483  int c, last;
1484  int rc;
1485 
1486  struct ImapAccountData *adata = imap_adata_get(m);
1487  struct ImapMboxData *mdata = imap_mdata_get(m);
1488 
1489  fp = fopen(msg->path, "r");
1490  if (!fp)
1491  {
1492  mutt_perror(msg->path);
1493  goto fail;
1494  }
1495 
1496  /* currently we set the \Seen flag on all messages, but probably we
1497  * should scan the message Status header for flag info. Since we're
1498  * already rereading the whole file for length it isn't any more
1499  * expensive (it'd be nice if we had the file size passed in already
1500  * by the code that writes the file, but that's a lot of changes.
1501  * Ideally we'd have an Email structure with flag info here... */
1502  for (last = EOF, len = 0; (c = fgetc(fp)) != EOF; last = c)
1503  {
1504  if ((c == '\n') && (last != '\r'))
1505  len++;
1506 
1507  len++;
1508  }
1509  rewind(fp);
1510 
1511  if (m->verbose)
1512  mutt_progress_init(&progress, _("Uploading message..."), MUTT_PROGRESS_NET, len);
1513 
1514  mutt_date_make_imap(internaldate, sizeof(internaldate), msg->received);
1515 
1516  imap_flags[0] = '\0';
1517  imap_flags[1] = '\0';
1518 
1519  if (msg->flags.read)
1520  mutt_str_cat(imap_flags, sizeof(imap_flags), " \\Seen");
1521  if (msg->flags.replied)
1522  mutt_str_cat(imap_flags, sizeof(imap_flags), " \\Answered");
1523  if (msg->flags.flagged)
1524  mutt_str_cat(imap_flags, sizeof(imap_flags), " \\Flagged");
1525  if (msg->flags.draft)
1526  mutt_str_cat(imap_flags, sizeof(imap_flags), " \\Draft");
1527 
1528  snprintf(buf, sizeof(buf), "APPEND %s (%s) \"%s\" {%lu}", mdata->munge_name,
1529  imap_flags + 1, internaldate, (unsigned long) len);
1530 
1531  imap_cmd_start(adata, buf);
1532 
1533  do
1534  {
1535  rc = imap_cmd_step(adata);
1536  } while (rc == IMAP_RES_CONTINUE);
1537 
1538  if (rc != IMAP_RES_RESPOND)
1539  goto cmd_step_fail;
1540 
1541  for (last = EOF, sent = len = 0; (c = fgetc(fp)) != EOF; last = c)
1542  {
1543  if ((c == '\n') && (last != '\r'))
1544  buf[len++] = '\r';
1545 
1546  buf[len++] = c;
1547 
1548  if (len > sizeof(buf) - 3)
1549  {
1550  sent += len;
1551  if (flush_buffer(buf, &len, adata->conn) < 0)
1552  goto fail;
1553  if (m->verbose)
1554  mutt_progress_update(&progress, sent, -1);
1555  }
1556  }
1557 
1558  if (len)
1559  if (flush_buffer(buf, &len, adata->conn) < 0)
1560  goto fail;
1561 
1562  if (mutt_socket_send(adata->conn, "\r\n") < 0)
1563  goto fail;
1564  mutt_file_fclose(&fp);
1565 
1566  do
1567  {
1568  rc = imap_cmd_step(adata);
1569  } while (rc == IMAP_RES_CONTINUE);
1570 
1571  if (rc != IMAP_RES_OK)
1572  goto cmd_step_fail;
1573 
1574  return 0;
1575 
1576 cmd_step_fail:
1577  mutt_debug(LL_DEBUG1, "command failed: %s\n", adata->buf);
1578  if (rc != IMAP_RES_BAD)
1579  {
1580  char *pc = imap_next_word(adata->buf); /* skip sequence number or token */
1581  pc = imap_next_word(pc); /* skip response code */
1582  if (*pc != '\0')
1583  mutt_error("%s", pc);
1584  }
1585 
1586 fail:
1587  mutt_file_fclose(&fp);
1588  return -1;
1589 }
Progress tracks bytes, according to C_NetInc.
Definition: progress.h:44
#define IMAP_RES_RESPOND
+
Definition: private.h:57
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
#define mutt_perror(...)
Definition: logging.h:85
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
bool replied
Definition: mx.h:93
#define _(a)
Definition: message.h:28
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1062
A progress bar.
Definition: progress.h:50
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
static int flush_buffer(char *buf, size_t *len, struct Connection *conn)
Write data to a connection.
Definition: message.c:500
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void * mdata
Driver specific data.
Definition: mailbox.h:136
bool flagged
Definition: mx.h:92
struct Message::@0 flags
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
bool verbose
Display status messages?
Definition: mailbox.h:118
bool draft
Definition: mx.h:94
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:390
IMAP-specific Account data -.
Definition: private.h:169
Log at debug level 1.
Definition: logging.h:40
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
IMAP-specific Mailbox data -.
Definition: private.h:216
char * buf
Definition: private.h:189
#define mutt_error(...)
Definition: logging.h:84
int mutt_date_make_imap(char *buf, size_t buflen, time_t timestamp)
Format date in IMAP style: DD-MMM-YYYY HH:MM:SS +ZZzz.
Definition: date.c:546
time_t received
the time at which this message was received
Definition: mx.h:96
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_DATELEN
Definition: private.h:89
bool read
Definition: mx.h:91
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
char * munge_name
Munged version of the mailbox name.
Definition: private.h:219
char * path
path to temp file
Definition: mx.h:86
struct Connection * conn
Definition: private.h:171
#define IMAP_RES_BAD
<tag> BAD ...
Definition: private.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_copy_messages()

int imap_copy_messages ( struct Mailbox m,
struct EmailList *  el,
const char *  dest,
bool  delete_original 
)

Server COPY messages to another folder.

Parameters
mMailbox
elList of Emails to copy
destDestination folder
delete_originalDelete the original?
Return values
-1Error
0Success
1Non-fatal error - try fetch/append

Definition at line 1601 of file message.c.

1602 {
1603  if (!m || !el || !dest)
1604  return -1;
1605 
1606  struct Buffer cmd, sync_cmd;
1607  char buf[PATH_MAX];
1608  char mbox[PATH_MAX];
1609  char mmbox[PATH_MAX];
1610  char prompt[PATH_MAX + 64];
1611  int rc;
1612  struct ConnAccount cac = { { 0 } };
1613  enum QuadOption err_continue = MUTT_NO;
1614  int triedcreate = 0;
1615  struct EmailNode *en = STAILQ_FIRST(el);
1616  bool single = !STAILQ_NEXT(en, entries);
1617  struct ImapAccountData *adata = imap_adata_get(m);
1618 
1619  if (single && en->email->attach_del)
1620  {
1621  mutt_debug(LL_DEBUG3, "#1 Message contains attachments to be deleted\n");
1622  return 1;
1623  }
1624 
1625  if (imap_parse_path(dest, &cac, buf, sizeof(buf)))
1626  {
1627  mutt_debug(LL_DEBUG1, "bad destination %s\n", dest);
1628  return -1;
1629  }
1630 
1631  /* check that the save-to folder is in the same account */
1632  if (!imap_account_match(&adata->conn->account, &cac))
1633  {
1634  mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1635  return 1;
1636  }
1637 
1638  imap_fix_path(adata->delim, buf, mbox, sizeof(mbox));
1639  if (*mbox == '\0')
1640  mutt_str_copy(mbox, "INBOX", sizeof(mbox));
1641  imap_munge_mbox_name(adata->unicode, mmbox, sizeof(mmbox), mbox);
1642 
1643  /* loop in case of TRYCREATE */
1644  do
1645  {
1646  mutt_buffer_init(&sync_cmd);
1647  mutt_buffer_init(&cmd);
1648 
1649  if (!single) /* copy tagged messages */
1650  {
1651  /* if any messages have attachments to delete, fall through to FETCH
1652  * and APPEND. TODO: Copy what we can with COPY, fall through for the
1653  * remainder. */
1654  STAILQ_FOREACH(en, el, entries)
1655  {
1656  if (en->email->attach_del)
1657  {
1659  "#2 Message contains attachments to be deleted\n");
1660  return 1;
1661  }
1662 
1663  if (en->email->active && en->email->changed)
1664  {
1665  rc = imap_sync_message_for_copy(m, en->email, &sync_cmd, &err_continue);
1666  if (rc < 0)
1667  {
1668  mutt_debug(LL_DEBUG1, "#1 could not sync\n");
1669  goto out;
1670  }
1671  }
1672  }
1673 
1674  rc = imap_exec_msgset(m, "UID COPY", mmbox, MUTT_TAG, false, false);
1675  if (rc == 0)
1676  {
1677  mutt_debug(LL_DEBUG1, "No messages tagged\n");
1678  rc = -1;
1679  goto out;
1680  }
1681  else if (rc < 0)
1682  {
1683  mutt_debug(LL_DEBUG1, "#1 could not queue copy\n");
1684  goto out;
1685  }
1686  else
1687  {
1688  mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1689  rc, mbox);
1690  }
1691  }
1692  else
1693  {
1694  mutt_message(_("Copying message %d to %s..."), en->email->index + 1, mbox);
1695  mutt_buffer_add_printf(&cmd, "UID COPY %u %s", imap_edata_get(en->email)->uid, mmbox);
1696 
1697  if (en->email->active && en->email->changed)
1698  {
1699  rc = imap_sync_message_for_copy(m, en->email, &sync_cmd, &err_continue);
1700  if (rc < 0)
1701  {
1702  mutt_debug(LL_DEBUG1, "#2 could not sync\n");
1703  goto out;
1704  }
1705  }
1706  rc = imap_exec(adata, cmd.data, IMAP_CMD_QUEUE);
1707  if (rc != IMAP_EXEC_SUCCESS)
1708  {
1709  mutt_debug(LL_DEBUG1, "#2 could not queue copy\n");
1710  goto out;
1711  }
1712  }
1713 
1714  /* let's get it on */
1715  rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1716  if (rc == IMAP_EXEC_ERROR)
1717  {
1718  if (triedcreate)
1719  {
1720  mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", mbox);
1721  break;
1722  }
1723  /* bail out if command failed for reasons other than nonexistent target */
1724  if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1725  break;
1726  mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1727  snprintf(prompt, sizeof(prompt), _("Create %s?"), mbox);
1728  if (C_Confirmcreate && (mutt_yesorno(prompt, MUTT_YES) != MUTT_YES))
1729  {
1730  mutt_clear_error();
1731  goto out;
1732  }
1733  if (imap_create_mailbox(adata, mbox) < 0)
1734  break;
1735  triedcreate = 1;
1736  }
1737  } while (rc == IMAP_EXEC_ERROR);
1738 
1739  if (rc != 0)
1740  {
1741  imap_error("imap_copy_messages", adata->buf);
1742  goto out;
1743  }
1744 
1745  /* cleanup */
1746  if (delete_original)
1747  {
1748  STAILQ_FOREACH(en, el, entries)
1749  {
1750  mutt_set_flag(m, en->email, MUTT_DELETE, true);
1751  mutt_set_flag(m, en->email, MUTT_PURGE, true);
1752  if (C_DeleteUntag)
1753  mutt_set_flag(m, en->email, MUTT_TAG, false);
1754  }
1755  }
1756 
1757  rc = 0;
1758 
1759 out:
1760  FREE(&cmd.data);
1761  FREE(&sync_cmd.data);
1762 
1763  return (rc < 0) ? -1 : rc;
1764 }
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:201
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:98
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:67
WHERE bool C_DeleteUntag
Config: Untag messages when they are marked for deletion.
Definition: mutt_globals.h:146
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
#define mutt_message(...)
Definition: logging.h:83
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
int imap_parse_path(const char *path, struct ConnAccount *cac, char *mailbox, size_t mailboxlen)
Parse an IMAP mailbox name into ConnAccount, name.
Definition: util.c:618
void imap_munge_mbox_name(bool unicode, char *dest, size_t dlen, const char *src)
Quote awkward characters in a mailbox name.
Definition: util.c:1045
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
bool changed
Email has been edited.
Definition: email.h:48
Messages to be purged (bypass trash)
Definition: mutt.h:100
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition: util.c:1178
Imap command executed or queued successfully.
Definition: private.h:83
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:379
int imap_exec_msgset(struct Mailbox *m, const char *pre, const char *post, int flag, bool changed, bool invert)
Prepare commands for all messages matching conditions.
Definition: imap.c:907
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
int imap_exec(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Execute a command and wait for the response from the server.
Definition: command.c:1247
int imap_sync_message_for_copy(struct Mailbox *m, struct Email *e, struct Buffer *cmd, enum QuadOption *err_continue)
Update server to reflect the flags of a single message.
Definition: imap.c:985
void imap_error(const char *where, const char *msg)
show an error and abort
Definition: util.c:798
bool active
Message is not to be removed.
Definition: email.h:59
unsigned int uid
32-bit Message UID
Definition: message.h:44
Messages to be deleted.
Definition: mutt.h:98
#define PATH_MAX
Definition: mutt.h:44
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
Tagged messages.
Definition: mutt.h:103
WHERE bool C_Confirmcreate
Config: Confirm before creating a new mailbox.
Definition: mutt_globals.h:144
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: private.h:72
int imap_create_mailbox(struct ImapAccountData *adata, char *mailbox)
Create a new mailbox.
Definition: imap.c:424
Login details for a remote server.
Definition: connaccount.h:51
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
Imap command failure.
Definition: private.h:84
IMAP-specific Account data -.
Definition: private.h:169
char * imap_get_qualifier(char *buf)
Get the qualifier from a tagged response.
Definition: util.c:906
Log at debug level 1.
Definition: logging.h:40
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
char * imap_fix_path(char delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition: util.c:820
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:721
char * buf
Definition: private.h:189
struct Email * email
Email in the list.
Definition: email.h:125
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define FREE(x)
Definition: memory.h:40
List of Emails.
Definition: email.h:123
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: private.h:74
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
#define STAILQ_FIRST(head)
Definition: queue.h:347
Log at debug level 3.
Definition: logging.h:42
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
bool unicode
If true, we can send UTF-8, and the server will use UTF8 rather than mUTF7.
Definition: private.h:192
struct Connection * conn
Definition: private.h:171
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cache_del()

int imap_cache_del ( struct Mailbox m,
struct Email e 
)

Delete an email from the body cache.

Parameters
mSelected Imap Mailbox
eEmail
Return values
0Success
-1Failure

Definition at line 1773 of file message.c.

1774 {
1775  struct ImapAccountData *adata = imap_adata_get(m);
1776  struct ImapMboxData *mdata = imap_mdata_get(m);
1777 
1778  if (!e || !adata || (adata->mailbox != m))
1779  return -1;
1780 
1781  mdata->bcache = msg_cache_open(m);
1782  char id[64];
1783  snprintf(id, sizeof(id), "%u-%u", mdata->uidvalidity, imap_edata_get(e)->uid);
1784  return mutt_bcache_del(mdata->bcache, id);
1785 }
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:98
uint32_t uidvalidity
Definition: private.h:228
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
struct BodyCache * bcache
Definition: private.h:240
void * mdata
Driver specific data.
Definition: mailbox.h:136
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
static struct BodyCache * msg_cache_open(struct Mailbox *m)
Open a message cache.
Definition: message.c:111
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:256
IMAP-specific Account data -.
Definition: private.h:169
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
IMAP-specific Mailbox data -.
Definition: private.h:216
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cache_clean()

int imap_cache_clean ( struct Mailbox m)

Delete all the entries in the message cache.

Parameters
mSelectedImap Mailbox
Return values
0Always

Definition at line 1792 of file message.c.

1793 {
1794  struct ImapAccountData *adata = imap_adata_get(m);
1795  struct ImapMboxData *mdata = imap_mdata_get(m);
1796 
1797  if (!adata || (adata->mailbox != m))
1798  return -1;
1799 
1800  mdata->bcache = msg_cache_open(m);
1801  mutt_bcache_list(mdata->bcache, msg_cache_clean_cb, mdata);
1802 
1803  return 0;
1804 }
static int msg_cache_clean_cb(const char *id, struct BodyCache *bcache, void *data)
Delete an entry from the message cache - Implements bcache_list_t.
Definition: message.c:199
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition: bcache.c:321
struct BodyCache * bcache
Definition: private.h:240
void * mdata
Driver specific data.
Definition: mailbox.h:136
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
static struct BodyCache * msg_cache_open(struct Mailbox *m)
Open a message cache.
Definition: message.c:111
IMAP-specific Account data -.
Definition: private.h:169
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
IMAP-specific Mailbox data -.
Definition: private.h:216
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_set_flags()

char* imap_set_flags ( struct Mailbox m,
struct Email e,
char *  s,
bool *  server_changes 
)

fill the message header according to the server flags

Parameters
[in]mImap Selected Mailbox
[in]eEmail
[in]sCommand string
[out]server_changesSet to true if the flags have changed
Return values
ptrThe end of flags string
NULLFailure

Expects a flags line of the form "FLAGS (flag flag ...)"

imap_set_flags: fill out the message header according to the flags from the server. Expects a flags line of the form "FLAGS (flag flag ...)"

Sets server_changes to 1 if a change to a flag is made, or in the case of e->changed, if a change to a flag would have been made.

Definition at line 1824 of file message.c.

1825 {
1826  struct ImapAccountData *adata = imap_adata_get(m);
1827  if (!adata || (adata->mailbox != m))
1828  return NULL;
1829 
1830  struct ImapHeader newh = { 0 };
1831  struct ImapEmailData old_edata = { 0 };
1832  int local_changes = e->changed;
1833 
1834  struct ImapEmailData *edata = e->edata;
1835  newh.edata = edata;
1836 
1837  mutt_debug(LL_DEBUG2, "parsing FLAGS\n");
1838  s = msg_parse_flags(&newh, s);
1839  if (!s)
1840  return NULL;
1841 
1842  /* Update tags system */
1843  /* We take a copy of the tags so we can split the string */
1844  char *tags_copy = mutt_str_dup(edata->flags_remote);
1845  driver_tags_replace(&e->tags, tags_copy);
1846  FREE(&tags_copy);
1847 
1848  /* YAUH (yet another ugly hack): temporarily set context to
1849  * read-write even if it's read-only, so *server* updates of
1850  * flags can be processed by mutt_set_flag. mailbox->changed must
1851  * be restored afterwards */
1852  bool readonly = m->readonly;
1853  m->readonly = false;
1854 
1855  /* This is redundant with the following two checks. Removing:
1856  * mutt_set_flag (m, e, MUTT_NEW, !(edata->read || edata->old)); */
1857  set_changed_flag(m, e, local_changes, server_changes, MUTT_OLD, old_edata.old,
1858  edata->old, e->old);
1859  set_changed_flag(m, e, local_changes, server_changes, MUTT_READ,
1860  old_edata.read, edata->read, e->read);
1861  set_changed_flag(m, e, local_changes, server_changes, MUTT_DELETE,
1862  old_edata.deleted, edata->deleted, e->deleted);
1863  set_changed_flag(m, e, local_changes, server_changes, MUTT_FLAG,
1864  old_edata.flagged, edata->flagged, e->flagged);
1865  set_changed_flag(m, e, local_changes, server_changes, MUTT_REPLIED,
1866  old_edata.replied, edata->replied, e->replied);
1867 
1868  /* this message is now definitively *not* changed (mutt_set_flag
1869  * marks things changed as a side-effect) */
1870  if (local_changes == 0)
1871  e->changed = false;
1872  m->changed &= !readonly;
1873  m->readonly = readonly;
1874 
1875  return s;
1876 }
static void set_changed_flag(struct Mailbox *m, struct Email *e, int local_changes, bool *server_changes, int flag_name, bool old_hd_flag, bool new_hd_flag, bool h_flag)
Have the flags of an email changed.
Definition: message.c:687
Flagged messages.
Definition: mutt.h:102
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
bool changed
Email has been edited.
Definition: email.h:48
Messages that have been replied to.
Definition: mutt.h:95
bool flagged
Definition: message.h:39
bool deleted
Definition: message.h:38
bool read
Email is read.
Definition: email.h:51
Log at debug level 2.
Definition: logging.h:41
bool old
Email is seen, but unread.
Definition: email.h:50
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
struct TagList tags
For drivers that support server tagging.
Definition: email.h:107
char * flags_remote
Definition: message.h:48
Old messages.
Definition: mutt.h:94
Messages to be deleted.
Definition: mutt.h:98
IMAP-specific header.
Definition: message.h:54
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
Messages that have been read.
Definition: mutt.h:96
bool replied
Definition: message.h:40
bool old
Definition: message.h:37
IMAP-specific Account data -.
Definition: private.h:169
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
bool flagged
Marked important?
Definition: email.h:43
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:109
bool replied
Email has been replied to.
Definition: email.h:54
#define FREE(x)
Definition: memory.h:40
bool read
Definition: message.h:36
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
IMAP-specific Email data -.
Definition: message.h:33
bool driver_tags_replace(struct TagList *head, char *tags)
Replace all tags.
Definition: tags.c:183
static char * msg_parse_flags(struct ImapHeader *h, char *s)
read a FLAGS token into an ImapHeader
Definition: message.c:222
struct ImapEmailData * edata
Definition: message.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_msg_open()

int imap_msg_open ( struct Mailbox m,
struct Message msg,
int  msgno 
)

Open an email message in a Mailbox - Implements MxOps::msg_open()

Definition at line 1881 of file message.c.

1882 {
1883  if (!m || !msg)
1884  return -1;
1885 
1886  struct Envelope *newenv = NULL;
1887  char buf[1024];
1888  char *pc = NULL;
1889  unsigned int bytes;
1890  struct Progress progress;
1891  unsigned int uid;
1892  bool retried = false;
1893  bool read;
1894  int rc;
1895 
1896  /* Sam's weird courier server returns an OK response even when FETCH
1897  * fails. Thanks Sam. */
1898  bool fetched = false;
1899 
1900  struct ImapAccountData *adata = imap_adata_get(m);
1901 
1902  if (!adata || (adata->mailbox != m))
1903  return -1;
1904 
1905  struct Email *e = m->emails[msgno];
1906  if (!e)
1907  return -1;
1908 
1909  msg->fp = msg_cache_get(m, e);
1910  if (msg->fp)
1911  {
1912  if (imap_edata_get(e)->parsed)
1913  return 0;
1914  goto parsemsg;
1915  }
1916 
1917  /* This function is called in a few places after endwin()
1918  * e.g. mutt_pipe_message(). */
1919  bool output_progress = !isendwin() && m->verbose;
1920  if (output_progress)
1921  mutt_message(_("Fetching message..."));
1922 
1923  msg->fp = msg_cache_put(m, e);
1924  if (!msg->fp)
1925  {
1926  struct Buffer *path = mutt_buffer_pool_get();
1927  mutt_buffer_mktemp(path);
1928  msg->fp = mutt_file_fopen(mutt_b2s(path), "w+");
1929  unlink(mutt_b2s(path));
1930  mutt_buffer_pool_release(&path);
1931 
1932  if (!msg->fp)
1933  return -1;
1934  }
1935 
1936  /* mark this header as currently inactive so the command handler won't
1937  * also try to update it. HACK until all this code can be moved into the
1938  * command handler */
1939  e->active = false;
1940 
1941  snprintf(buf, sizeof(buf), "UID FETCH %u %s", imap_edata_get(e)->uid,
1942  ((adata->capabilities & IMAP_CAP_IMAP4REV1) ?
1943  (C_ImapPeek ? "BODY.PEEK[]" : "BODY[]") :
1944  "RFC822"));
1945 
1946  imap_cmd_start(adata, buf);
1947  do
1948  {
1949  rc = imap_cmd_step(adata);
1950  if (rc != IMAP_RES_CONTINUE)
1951  break;
1952 
1953  pc = adata->buf;
1954  pc = imap_next_word(pc);
1955  pc = imap_next_word(pc);
1956 
1957  if (mutt_istr_startswith(pc, "FETCH"))
1958  {
1959  while (*pc)
1960  {
1961  pc = imap_next_word(pc);
1962  if (pc[0] == '(')
1963  pc++;
1964  if (mutt_istr_startswith(pc, "UID"))
1965  {
1966  pc = imap_next_word(pc);
1967  if (mutt_str_atoui(pc, &uid) < 0)
1968  goto bail;
1969  if (uid != imap_edata_get(e)->uid)
1970  {
1971  mutt_error(_(
1972  "The message index is incorrect. Try reopening the mailbox."));
1973  }
1974  }
1975  else if (mutt_istr_startswith(pc, "RFC822") || mutt_istr_startswith(pc, "BODY[]"))
1976  {
1977  pc = imap_next_word(pc);
1978  if (imap_get_literal_count(pc, &bytes) < 0)
1979  {
1980  imap_error("imap_msg_open()", buf);
1981  goto bail;
1982  }
1983  if (output_progress)
1984  {
1985  mutt_progress_init(&progress, _("Fetching message..."), MUTT_PROGRESS_NET, bytes);
1986  }
1987  if (imap_read_literal(msg->fp, adata, bytes, output_progress ? &progress : NULL) < 0)
1988  {
1989  goto bail;
1990  }
1991  /* pick up trailing line */
1992  rc = imap_cmd_step(adata);
1993  if (rc != IMAP_RES_CONTINUE)
1994  goto bail;
1995  pc = adata->buf;
1996 
1997  fetched = true;
1998  }
1999  /* UW-IMAP will provide a FLAGS update here if the FETCH causes a
2000  * change (eg from \Unseen to \Seen).
2001  * Uncommitted changes in neomutt take precedence. If we decide to
2002  * incrementally update flags later, this won't stop us syncing */
2003  else if (!e->changed && mutt_istr_startswith(pc, "FLAGS"))
2004  {
2005  pc = imap_set_flags(m, e, pc, NULL);
2006  if (!pc)
2007  goto bail;
2008  }
2009  }
2010  }
2011  } while (rc == IMAP_RES_CONTINUE);
2012 
2013  /* see comment before command start. */
2014  e->active = true;
2015 
2016  fflush(msg->fp);
2017  if (ferror(msg->fp))
2018  goto bail;
2019 
2020  if (rc != IMAP_RES_OK)
2021  goto bail;
2022 
2023  if (!fetched || !imap_code(adata->buf))
2024  goto bail;
2025 
2026  msg_cache_commit(m, e);
2027 
2028 parsemsg:
2029  /* Update the header information. Previously, we only downloaded a
2030  * portion of the headers, those required for the main display. */
2031  rewind(msg->fp);
2032  /* It may be that the Status header indicates a message is read, but the
2033  * IMAP server doesn't know the message has been \Seen. So we capture
2034  * the server's notion of 'read' and if it differs from the message info
2035  * picked up in mutt_rfc822_read_header, we mark the message (and context
2036  * changed). Another possibility: ignore Status on IMAP? */
2037  read = e->read;
2038  newenv = mutt_rfc822_read_header(msg->fp, e, false, false);
2039  mutt_env_merge(e->env, &newenv);
2040 
2041  /* see above. We want the new status in e->read, so we unset it manually
2042  * and let mutt_set_flag set it correctly, updating context. */
2043  if (read != e->read)
2044  {
2045  e->read = read;
2046  mutt_set_flag(m, e, MUTT_NEW, read);
2047  }
2048 
2049  e->lines = 0;
2050  fgets(buf, sizeof(buf), msg->fp);
2051  while (!feof(msg->fp))
2052  {
2053  e->lines++;
2054  fgets(buf, sizeof(buf), msg->fp);
2055  }
2056 
2057  e->body->length = ftell(msg->fp) - e->body->offset;
2058 
2059  mutt_clear_error();
2060  rewind(msg->fp);
2061  imap_edata_get(e)->parsed = true;
2062 
2063  /* retry message parse if cached message is empty */
2064  if (!retried && ((e->lines == 0) || (e->body->length == 0)))
2065  {
2066  imap_cache_del(m, e);
2067  retried = true;
2068  goto parsemsg;
2069  }
2070 
2071  return 0;
2072 
2073 bail:
2074  e->active = true;
2075  mutt_file_fclose(&msg->fp);
2076  imap_cache_del(m, e);
2077  return -1;
2078 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
Progress tracks bytes, according to C_NetInc.
Definition: progress.h:44
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:98
int lines
How many lines in the body of this message?
Definition: email.h:85
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:67
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
The envelope/body of an email.
Definition: email.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Body * body
List of MIME parts.
Definition: email.h:91
void mutt_env_merge(struct Envelope *base, struct Envelope **extra)
Merge the headers of two Envelopes.
Definition: envelope.c:151
#define mutt_message(...)
Definition: logging.h:83
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
static FILE * msg_cache_put(struct Mailbox *m, struct Email *e)
Put an email into the message cache.
Definition: message.c:159
int imap_cache_del(struct Mailbox *m, struct Email *e)
Delete an email from the body cache.
Definition: message.c:1773
String manipulation buffer.
Definition: buffer.h:33
static FILE * msg_cache_get(struct Mailbox *m, struct Email *e)
Get the message cache entry for an email.
Definition: message.c:138
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
bool changed
Email has been edited.
Definition: email.h:48
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1062
int imap_read_literal(FILE *fp, struct ImapAccountData *adata, unsigned long bytes, struct Progress *pbar)
Read bytes bytes from server into file.
Definition: imap.c:573
A progress bar.
Definition: progress.h:50
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
bool read
Email is read.
Definition: email.h:51
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Envelope * env
Envelope information.
Definition: email.h:90
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
#define mutt_b2s(buf)
Definition: buffer.h:41
void imap_error(const char *where, const char *msg)
show an error and abort
Definition: util.c:798
#define IMAP_CAP_IMAP4REV1
Server supports IMAP4rev1.
Definition: private.h:123
bool active
Message is not to be removed.
Definition: email.h:59
bool C_ImapPeek
Config: (imap) Don&#39;t mark messages as read when fetching them from the server.
Definition: config.c:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
New messages.
Definition: mutt.h:93
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:287
bool verbose
Display status messages?
Definition: mailbox.h:118
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
ImapCapFlags capabilities
Definition: private.h:185
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
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
IMAP-specific Account data -.
Definition: private.h:169
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
char * buf
Definition: private.h:189
#define mutt_error(...)
Definition: logging.h:84
FILE * fp
pointer to the message data
Definition: mx.h:85
char * imap_set_flags(struct Mailbox *m, struct Email *e, char *s, bool *server_changes)
fill the message header according to the server flags
Definition: message.c:1824
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1111
bool parsed
Definition: message.h:42
bool imap_code(const char *s)
Was the command successful.
Definition: command.c:1199
The header of an Email.
Definition: envelope.h:54
int msgno
Number displayed to the user.
Definition: email.h:87
static int msg_cache_commit(struct Mailbox *m, struct Email *e)
Add to the message cache.
Definition: message.c:180
+ Here is the call graph for this function:

◆ imap_msg_commit()

int imap_msg_commit ( struct Mailbox m,
struct Message msg 
)

Save changes to an email - Implements MxOps::msg_commit()

Note
May also return EOF Failure, see errno

Definition at line 2085 of file message.c.

2086 {
2087  int rc = mutt_file_fclose(&msg->fp);
2088  if (rc != 0)
2089  return rc;
2090 
2091  return imap_append_message(m, msg);
2092 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
int imap_append_message(struct Mailbox *m, struct Message *msg)
Write an email back to the server.
Definition: message.c:1471
FILE * fp
pointer to the message data
Definition: mx.h:85
+ Here is the call graph for this function:

◆ imap_msg_close()

int imap_msg_close ( struct Mailbox m,
struct Message msg 
)

Close an email - Implements MxOps::msg_close()

Note
May also return EOF Failure, see errno

Definition at line 2099 of file message.c.

2100 {
2101  return mutt_file_fclose(&msg->fp);
2102 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
FILE * fp
pointer to the message data
Definition: mx.h:85
+ Here is the call graph for this function:

◆ imap_msg_save_hcache()

int imap_msg_save_hcache ( struct Mailbox m,
struct Email e 
)

Save message to the header cache - Implements MxOps::msg_save_hcache()

Definition at line 2107 of file message.c.

2108 {
2109  int rc = 0;
2110 #ifdef USE_HCACHE
2111  bool close_hc = true;
2112  struct ImapAccountData *adata = imap_adata_get(m);
2113  struct ImapMboxData *mdata = imap_mdata_get(m);
2114  if (!mdata || !adata)
2115  return -1;
2116  if (mdata->hcache)
2117  close_hc = false;
2118  else
2119  imap_hcache_open(adata, mdata);
2120  rc = imap_hcache_put(mdata, e);
2121  if (close_hc)
2122  imap_hcache_close(mdata);
2123 #endif
2124  return rc;
2125 }
int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
Add an entry to the header cache.
Definition: util.c:516
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
struct HeaderCache * hcache
Definition: private.h:242
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition: util.c:475
void * mdata
Driver specific data.
Definition: mailbox.h:136
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
IMAP-specific Account data -.
Definition: private.h:169
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
IMAP-specific Mailbox data -.
Definition: private.h:216
void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata)
Open a header cache.
Definition: util.c:435
+ Here is the call graph for this function: