NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
pop.c File Reference

POP network mailbox. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.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 "lib.h"
#include "bcache/lib.h"
#include "ncrypt/lib.h"
#include "progress/lib.h"
#include "question/lib.h"
#include "adata.h"
#include "edata.h"
#include "hook.h"
#include "mutt_account.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_socket.h"
#include "muttlib.h"
#include "mx.h"
#include <libintl.h>
#include "hcache/lib.h"
+ Include dependency graph for pop.c:

Go to the source code of this file.

Macros

#define HC_FNAME   "neomutt" /* filename for hcache as POP lacks paths */
 
#define HC_FEXT   "hcache" /* extension for hcache as POP lacks paths */
 

Functions

static const char * cache_id (const char *id)
 Make a message-cache-compatible id. More...
 
static int fetch_message (const char *line, void *data)
 Write line to file - Implements pop_fetch_t -. More...
 
static int pop_read_header (struct PopAccountData *adata, struct Email *e)
 Read header. More...
 
static int fetch_uidl (const char *line, void *data)
 Parse UIDL - Implements pop_fetch_t -. More...
 
static int msg_cache_check (const char *id, struct BodyCache *bcache, void *data)
 Check the Body Cache for an ID - Implements bcache_list_t -. More...
 
static void pop_hcache_namer (const char *path, struct Buffer *dest)
 Create a header cache filename for a POP mailbox - Implements hcache_namer_t -. More...
 
static struct HeaderCachepop_hcache_open (struct PopAccountData *adata, const char *path)
 Open the header cache. More...
 
static int pop_fetch_headers (struct Mailbox *m)
 Read headers. More...
 
static void pop_clear_cache (struct PopAccountData *adata)
 Delete all cached messages. More...
 
void pop_fetch_mail (void)
 Fetch messages and save them in $spool_file. More...
 
static bool pop_ac_owns_path (struct Account *a, const char *path)
 Check whether an Account owns a Mailbox path - Implements MxOps::ac_owns_path() -. More...
 
static bool pop_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -. More...
 
static enum MxOpenReturns pop_mbox_open (struct Mailbox *m)
 Open a Mailbox - Implements MxOps::mbox_open() -. More...
 
static enum MxStatus pop_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -. More...
 
static enum MxStatus pop_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
static enum MxStatus pop_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -. More...
 
static bool pop_msg_open (struct Mailbox *m, struct Message *msg, int msgno)
 Open an email message in a Mailbox - Implements MxOps::msg_open() -. More...
 
static int pop_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -. More...
 
static int pop_msg_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Implements MxOps::msg_save_hcache() -. More...
 
enum MailboxType pop_path_probe (const char *path, const struct stat *st)
 Is this a POP Mailbox? - Implements MxOps::path_probe() -. More...
 
static int pop_path_canon (char *buf, size_t buflen)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -. More...
 
static int pop_path_pretty (char *buf, size_t buflen, const char *folder)
 Abbreviate a Mailbox path - Implements MxOps::path_pretty() -. More...
 
static int pop_path_parent (char *buf, size_t buflen)
 Find the parent of a Mailbox path - Implements MxOps::path_parent() -. More...
 

Variables

struct MxOps MxPopOps
 POP Mailbox - Implements MxOps -. More...
 

Detailed Description

POP network mailbox.

Authors
  • Vsevolod Volkov
  • Rocco Rutte
  • 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 pop.c.

Macro Definition Documentation

◆ HC_FNAME

#define HC_FNAME   "neomutt" /* filename for hcache as POP lacks paths */

Definition at line 71 of file pop.c.

◆ HC_FEXT

#define HC_FEXT   "hcache" /* extension for hcache as POP lacks paths */

Definition at line 72 of file pop.c.

Function Documentation

◆ cache_id()

static const char * cache_id ( const char *  id)
static

Make a message-cache-compatible id.

Parameters
idPOP message id
Return values
ptrSanitised string

The POP message id may contain '/' and other awkward characters.

Note
This function returns a pointer to a static buffer.

Definition at line 83 of file pop.c.

84{
85 static char clean[128];
86 mutt_str_copy(clean, id, sizeof(clean));
87 mutt_file_sanitize_filename(clean, true);
88 return clean;
89}
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:647
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:652
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pop_read_header()

static int pop_read_header ( struct PopAccountData adata,
struct Email e 
)
static

Read header.

Parameters
adataPOP Account data
eEmail
Return values
0Success
-1Connection lost
-2Invalid command or execution error
-3Error writing to tempfile

Definition at line 118 of file pop.c.

119{
120 FILE *fp = mutt_file_mkstemp();
121 if (!fp)
122 {
123 mutt_perror(_("Can't create temporary file"));
124 return -3;
125 }
126
127 int index = 0;
128 size_t length = 0;
129 char buf[1024] = { 0 };
130
131 struct PopEmailData *edata = pop_edata_get(e);
132
133 snprintf(buf, sizeof(buf), "LIST %d\r\n", edata->refno);
134 int rc = pop_query(adata, buf, sizeof(buf));
135 if (rc == 0)
136 {
137 sscanf(buf, "+OK %d %zu", &index, &length);
138
139 snprintf(buf, sizeof(buf), "TOP %d 0\r\n", edata->refno);
140 rc = pop_fetch_data(adata, buf, NULL, fetch_message, fp);
141
142 if (adata->cmd_top == 2)
143 {
144 if (rc == 0)
145 {
146 adata->cmd_top = 1;
147
148 mutt_debug(LL_DEBUG1, "set TOP capability\n");
149 }
150
151 if (rc == -2)
152 {
153 adata->cmd_top = 0;
154
155 mutt_debug(LL_DEBUG1, "unset TOP capability\n");
156 snprintf(adata->err_msg, sizeof(adata->err_msg), "%s",
157 _("Command TOP is not supported by server"));
158 }
159 }
160 }
161
162 switch (rc)
163 {
164 case 0:
165 {
166 rewind(fp);
167 e->env = mutt_rfc822_read_header(fp, e, false, false);
168 e->body->length = length - e->body->offset + 1;
169 rewind(fp);
170 while (!feof(fp))
171 {
172 e->body->length--;
173 fgets(buf, sizeof(buf), fp);
174 }
175 break;
176 }
177 case -2:
178 {
179 mutt_error("%s", adata->err_msg);
180 break;
181 }
182 case -3:
183 {
184 mutt_error(_("Can't write header to temporary file"));
185 break;
186 }
187 }
188
189 mutt_file_fclose(&fp);
190 return rc;
191}
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define mutt_file_mkstemp()
Definition: file.h:112
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
static int fetch_message(const char *line, void *data)
Write line to file - Implements pop_fetch_t -.
Definition: pop.c:98
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
#define _(a)
Definition: message.h:28
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1158
struct PopEmailData * pop_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:65
int pop_fetch_data(struct PopAccountData *adata, const char *query, struct Progress *progress, pop_fetch_t callback, void *data)
Read Headers with callback function.
Definition: lib.c:502
#define pop_query(adata, buf, buflen)
Definition: private.h:109
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct Envelope * env
Envelope information.
Definition: email.h:66
void * edata
Driver-specific data.
Definition: email.h:72
struct Body * body
List of MIME parts.
Definition: email.h:67
int index
The absolute (unsorted) message number.
Definition: email.h:110
unsigned int cmd_top
optional command TOP
Definition: adata.h:46
char err_msg[POP_CMD_RESPONSE]
Definition: adata.h:56
POP-specific Email data -.
Definition: edata.h:32
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pop_hcache_open()

static struct HeaderCache * pop_hcache_open ( struct PopAccountData adata,
const char *  path 
)
static

Open the header cache.

Parameters
adataPOP Account data
pathPath to the mailbox
Return values
ptrHeader cache

Definition at line 297 of file pop.c.

298{
299 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
300 if (!adata || !adata->conn)
301 return mutt_hcache_open(c_header_cache, path, NULL);
302
303 struct Url url = { 0 };
304 char p[1024] = { 0 };
305
306 mutt_account_tourl(&adata->conn->account, &url);
307 url.path = HC_FNAME;
308 url_tostring(&url, p, sizeof(p), U_PATH);
309 return mutt_hcache_open(c_header_cache, p, pop_hcache_namer);
310}
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
static void pop_hcache_namer(const char *path, struct Buffer *dest)
Create a header cache filename for a POP mailbox - Implements hcache_namer_t -.
Definition: pop.c:286
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:332
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:79
#define HC_FNAME
Definition: pop.c:71
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct Connection * conn
Connection to POP server.
Definition: adata.h:38
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * path
Path.
Definition: url.h:75
int url_tostring(struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition: url.c:418
#define U_PATH
Definition: url.h:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pop_fetch_headers()

static int pop_fetch_headers ( struct Mailbox m)
static

Read headers.

Parameters
mMailbox
Return values
0Success
-1Connection lost
-2Invalid command or execution error
-3Error writing to tempfile

Definition at line 321 of file pop.c.

322{
323 if (!m)
324 return -1;
325
327 struct Progress *progress = NULL;
328
329#ifdef USE_HCACHE
330 struct HeaderCache *hc = pop_hcache_open(adata, mailbox_path(m));
331#endif
332
333 adata->check_time = mutt_date_epoch();
334 adata->clear_cache = false;
335
336 for (int i = 0; i < m->msg_count; i++)
337 {
338 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
339 edata->refno = -1;
340 }
341
342 const int old_count = m->msg_count;
343 int rc = pop_fetch_data(adata, "UIDL\r\n", NULL, fetch_uidl, m);
344 const int new_count = m->msg_count;
345 m->msg_count = old_count;
346
347 if (adata->cmd_uidl == 2)
348 {
349 if (rc == 0)
350 {
351 adata->cmd_uidl = 1;
352
353 mutt_debug(LL_DEBUG1, "set UIDL capability\n");
354 }
355
356 if ((rc == -2) && (adata->cmd_uidl == 2))
357 {
358 adata->cmd_uidl = 0;
359
360 mutt_debug(LL_DEBUG1, "unset UIDL capability\n");
361 snprintf(adata->err_msg, sizeof(adata->err_msg), "%s",
362 _("Command UIDL is not supported by server"));
363 }
364 }
365
366 if (m->verbose)
367 {
368 progress = progress_new(_("Fetching message headers..."),
369 MUTT_PROGRESS_READ, new_count - old_count);
370 }
371
372 if (rc == 0)
373 {
374 int i, deleted;
375 for (i = 0, deleted = 0; i < old_count; i++)
376 {
377 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
378 if (edata->refno == -1)
379 {
380 m->emails[i]->deleted = true;
381 deleted++;
382 }
383 }
384 if (deleted > 0)
385 {
386 mutt_error(ngettext("%d message has been lost. Try reopening the mailbox.",
387 "%d messages have been lost. Try reopening the mailbox.", deleted),
388 deleted);
389 }
390
391 bool hcached = false;
392 for (i = old_count; i < new_count; i++)
393 {
394 if (m->verbose)
395 progress_update(progress, i + 1 - old_count, -1);
396 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
397#ifdef USE_HCACHE
398 struct HCacheEntry hce = mutt_hcache_fetch(hc, edata->uid, strlen(edata->uid), 0);
399 if (hce.email)
400 {
401 /* Detach the private data */
402 m->emails[i]->edata = NULL;
403
404 int index = m->emails[i]->index;
405 /* - POP dynamically numbers headers and relies on e->refno
406 * to map messages; so restore header and overwrite restored
407 * refno with current refno, same for index
408 * - e->data needs to a separate pointer as it's driver-specific
409 * data freed separately elsewhere
410 * (the old e->data should point inside a malloc'd block from
411 * hcache so there shouldn't be a memleak here) */
412 email_free(&m->emails[i]);
413 m->emails[i] = hce.email;
414 m->emails[i]->index = index;
415
416 /* Reattach the private data */
417 m->emails[i]->edata = edata;
419 rc = 0;
420 hcached = true;
421 }
422 else
423#endif
424 if ((rc = pop_read_header(adata, m->emails[i])) < 0)
425 break;
426#ifdef USE_HCACHE
427 else
428 {
429 mutt_hcache_store(hc, edata->uid, strlen(edata->uid), m->emails[i], 0);
430 }
431#endif
432
433 /* faked support for flags works like this:
434 * - if 'hcached' is true, we have the message in our hcache:
435 * - if we also have a body: read
436 * - if we don't have a body: old
437 * (if $mark_old is set which is maybe wrong as
438 * $mark_old should be considered for syncing the
439 * folder and not when opening it XXX)
440 * - if 'hcached' is false, we don't have the message in our hcache:
441 * - if we also have a body: read
442 * - if we don't have a body: new */
443 const bool bcached = (mutt_bcache_exists(adata->bcache, cache_id(edata->uid)) == 0);
444 m->emails[i]->old = false;
445 m->emails[i]->read = false;
446 if (hcached)
447 {
448 const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
449 if (bcached)
450 m->emails[i]->read = true;
451 else if (c_mark_old)
452 m->emails[i]->old = true;
453 }
454 else
455 {
456 if (bcached)
457 m->emails[i]->read = true;
458 }
459
460 m->msg_count++;
461 }
462 }
463 progress_free(&progress);
464
465#ifdef USE_HCACHE
467#endif
468
469 if (rc < 0)
470 {
471 for (int i = m->msg_count; i < new_count; i++)
472 email_free(&m->emails[i]);
473 return rc;
474 }
475
476 /* after putting the result into our structures,
477 * clean up cache, i.e. wipe messages deleted outside
478 * the availability of our cache */
479 const bool c_message_cache_clean = cs_subset_bool(NeoMutt->sub, "message_cache_clean");
480 if (c_message_cache_clean)
482
484 return new_count - old_count;
485}
int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
Check if a file exists in the Body Cache.
Definition: bcache.c:288
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition: bcache.c:330
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
static int msg_cache_check(const char *id, struct BodyCache *bcache, void *data)
Check the Body Cache for an ID - Implements bcache_list_t -.
Definition: pop.c:253
static int fetch_uidl(const char *line, void *data)
Parse UIDL - Implements pop_fetch_t -.
Definition: pop.c:200
int mutt_hcache_store(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:552
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:432
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:456
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
struct PopAccountData * pop_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: adata.c:64
void pop_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:41
static const char * cache_id(const char *id)
Make a message-cache-compatible id.
Definition: pop.c:83
static struct HeaderCache * pop_hcache_open(struct PopAccountData *adata, const char *path)
Open the header cache.
Definition: pop.c:297
static int pop_read_header(struct PopAccountData *adata, struct Email *e)
Read header.
Definition: pop.c:118
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:49
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:86
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:118
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
bool read
Email is read.
Definition: email.h:48
bool old
Email is seen, but unread.
Definition: email.h:47
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:87
bool deleted
Email is deleted.
Definition: email.h:76
Wrapper for Email retrieved from the header cache.
Definition: lib.h:98
struct Email * email
Retrieved email.
Definition: lib.h:101
Header cache structure.
Definition: lib.h:87
int msg_count
Total number of messages.
Definition: mailbox.h:88
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
bool verbose
Display status messages?
Definition: mailbox.h:114
POP-specific Account data -.
Definition: adata.h:37
bool clear_cache
Definition: adata.h:49
time_t check_time
Definition: adata.h:51
struct BodyCache * bcache
body cache
Definition: adata.h:55
unsigned int cmd_uidl
optional command UIDL
Definition: adata.h:45
const char * uid
UID of email.
Definition: edata.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pop_clear_cache()

static void pop_clear_cache ( struct PopAccountData adata)
static

Delete all cached messages.

Parameters
adataPOP Account data

Definition at line 491 of file pop.c.

492{
493 if (!adata->clear_cache)
494 return;
495
496 mutt_debug(LL_DEBUG1, "delete cached messages\n");
497
498 for (int i = 0; i < POP_CACHE_LEN; i++)
499 {
500 if (adata->cache[i].path)
501 {
502 unlink(adata->cache[i].path);
503 FREE(&adata->cache[i].path);
504 }
505 }
506}
#define FREE(x)
Definition: memory.h:43
#define POP_CACHE_LEN
Definition: private.h:39
struct PopCache cache[POP_CACHE_LEN]
Definition: adata.h:57
char * path
Definition: private.h:71
+ Here is the caller graph for this function:

◆ pop_fetch_mail()

void pop_fetch_mail ( void  )

Fetch messages and save them in $spool_file.

Definition at line 511 of file pop.c.

512{
513 const char *const c_pop_host = cs_subset_string(NeoMutt->sub, "pop_host");
514 if (!c_pop_host)
515 {
516 mutt_error(_("POP host is not defined"));
517 return;
518 }
519
520 char buf[1024] = { 0 };
521 char msgbuf[128] = { 0 };
522 int last = 0, msgs, bytes, rset = 0, rc;
523 struct ConnAccount cac = { { 0 } };
524
525 char *p = mutt_mem_calloc(strlen(c_pop_host) + 7, sizeof(char));
526 char *url = p;
527 if (url_check_scheme(c_pop_host) == U_UNKNOWN)
528 {
529 strcpy(url, "pop://");
530 p = strchr(url, '\0');
531 }
532 strcpy(p, c_pop_host);
533
534 rc = pop_parse_path(url, &cac);
535 FREE(&url);
536 if (rc)
537 {
538 mutt_error(_("%s is an invalid POP path"), c_pop_host);
539 return;
540 }
541
542 struct Connection *conn = mutt_conn_find(&cac);
543 if (!conn)
544 return;
545
547 adata->conn = conn;
548
549 if (pop_open_connection(adata) < 0)
550 {
551 //XXX mutt_socket_free(adata->conn);
552 pop_adata_free((void **) &adata);
553 return;
554 }
555
556 mutt_message(_("Checking for new messages..."));
557
558 /* find out how many messages are in the mailbox. */
559 mutt_str_copy(buf, "STAT\r\n", sizeof(buf));
560 rc = pop_query(adata, buf, sizeof(buf));
561 if (rc == -1)
562 goto fail;
563 if (rc == -2)
564 {
565 mutt_error("%s", adata->err_msg);
566 goto finish;
567 }
568
569 sscanf(buf, "+OK %d %d", &msgs, &bytes);
570
571 /* only get unread messages */
572 const bool c_pop_last = cs_subset_bool(NeoMutt->sub, "pop_last");
573 if ((msgs > 0) && c_pop_last)
574 {
575 mutt_str_copy(buf, "LAST\r\n", sizeof(buf));
576 rc = pop_query(adata, buf, sizeof(buf));
577 if (rc == -1)
578 goto fail;
579 if (rc == 0)
580 sscanf(buf, "+OK %d", &last);
581 }
582
583 if (msgs <= last)
584 {
585 mutt_message(_("No new mail in POP mailbox"));
586 goto finish;
587 }
588
589 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
590 struct Mailbox *m_spool = mx_path_resolve(c_spool_file);
591
592 if (!mx_mbox_open(m_spool, MUTT_OPEN_NO_FLAGS))
593 {
594 mailbox_free(&m_spool);
595 goto finish;
596 }
597 bool old_append = m_spool->append;
598 m_spool->append = true;
599
600 const enum QuadOption c_pop_delete = cs_subset_quad(NeoMutt->sub, "pop_delete");
601 enum QuadOption delanswer = query_quadoption(c_pop_delete, _("Delete messages from server?"));
602
603 snprintf(msgbuf, sizeof(msgbuf),
604 ngettext("Reading new messages (%d byte)...",
605 "Reading new messages (%d bytes)...", bytes),
606 bytes);
607 mutt_message("%s", msgbuf);
608
609 for (int i = last + 1; i <= msgs; i++)
610 {
611 struct Message *msg = mx_msg_open_new(m_spool, NULL, MUTT_ADD_FROM);
612 if (msg)
613 {
614 snprintf(buf, sizeof(buf), "RETR %d\r\n", i);
615 rc = pop_fetch_data(adata, buf, NULL, fetch_message, msg->fp);
616 if (rc == -3)
617 rset = 1;
618
619 if ((rc == 0) && (mx_msg_commit(m_spool, msg) != 0))
620 {
621 rset = 1;
622 rc = -3;
623 }
624
625 mx_msg_close(m_spool, &msg);
626 }
627 else
628 {
629 rc = -3;
630 }
631
632 if ((rc == 0) && (delanswer == MUTT_YES))
633 {
634 /* delete the message on the server */
635 snprintf(buf, sizeof(buf), "DELE %d\r\n", i);
636 rc = pop_query(adata, buf, sizeof(buf));
637 }
638
639 if (rc == -1)
640 {
641 m_spool->append = old_append;
642 mx_mbox_close(m_spool);
643 goto fail;
644 }
645 if (rc == -2)
646 {
647 mutt_error("%s", adata->err_msg);
648 break;
649 }
650 if (rc == -3)
651 {
652 mutt_error(_("Error while writing mailbox"));
653 break;
654 }
655
656 /* L10N: The plural is picked by the second numerical argument, i.e.
657 the %d right before 'messages', i.e. the total number of messages. */
658 mutt_message(ngettext("%s [%d of %d message read]",
659 "%s [%d of %d messages read]", msgs - last),
660 msgbuf, i - last, msgs - last);
661 }
662
663 m_spool->append = old_append;
664 mx_mbox_close(m_spool);
665
666 if (rset)
667 {
668 /* make sure no messages get deleted */
669 mutt_str_copy(buf, "RSET\r\n", sizeof(buf));
670 if (pop_query(adata, buf, sizeof(buf)) == -1)
671 goto fail;
672 }
673
674finish:
675 /* exit gracefully */
676 mutt_str_copy(buf, "QUIT\r\n", sizeof(buf));
677 if (pop_query(adata, buf, sizeof(buf)) == -1)
678 goto fail;
679 mutt_socket_close(conn);
680 FREE(&conn);
681 pop_adata_free((void **) &adata);
682 return;
683
684fail:
685 mutt_error(_("Server closed connection"));
686 mutt_socket_close(conn);
687 pop_adata_free((void **) &adata);
688}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
#define mutt_message(...)
Definition: logging.h:86
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
struct Connection * mutt_conn_find(const struct ConnAccount *cac)
Find a connection from a list.
Definition: mutt_socket.c:89
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1057
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1172
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:43
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mxapi.h:61
struct PopAccountData * pop_adata_new(void)
Create a new PopAccountData object.
Definition: adata.c:54
void pop_adata_free(void **ptr)
Free the private Account data - Implements Account::adata_free()
Definition: adata.c:40
int pop_open_connection(struct PopAccountData *adata)
Open connection and authenticate.
Definition: lib.c:308
int pop_parse_path(const char *path, struct ConnAccount *cac)
Parse a POP mailbox name.
Definition: lib.c:82
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:98
Login details for a remote server.
Definition: connaccount.h:53
A mailbox.
Definition: mailbox.h:79
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:109
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:221
@ U_UNKNOWN
Url wasn't recognised.
Definition: url.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function: