NeoMutt  2025-12-11-769-g906513
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 "hooks/lib.h"
#include "ncrypt/lib.h"
#include "progress/lib.h"
#include "question/lib.h"
#include "store/lib.h"
#include "adata.h"
#include "edata.h"
#include "mutt_logging.h"
#include "mutt_socket.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 */
 
#define POP_MAX_MESSAGES   500000
 Hard limit on UIDL responses to prevent a malicious server from causing unbounded memory growth.
 

Functions

static const char * cache_id (const char *id)
 Make a message-cache-compatible id.
 
static int fetch_message (const char *line, void *data)
 Parse a Message response - Implements pop_fetch_t -.
 
static int pop_read_header (struct PopAccountData *adata, struct Email *e)
 Read header.
 
static int fetch_uidl (const char *line, void *data)
 Parse UIDL response - Implements pop_fetch_t -.
 
static int pop_bcache_delete (const char *id, struct BodyCache *bcache, void *data)
 Delete an entry from the message cache - Implements bcache_list_t -.
 
static void pop_hcache_namer (const struct StoreOps *store_ops, const char *path, struct Buffer *dest)
 Create a header cache filename for a POP mailbox - Implements hcache_namer_t -.
 
static struct HeaderCachepop_hcache_open (struct PopAccountData *adata, const char *path)
 Open the header cache.
 
static int pop_fetch_headers (struct Mailbox *m)
 Read headers.
 
static void pop_clear_cache (struct PopAccountData *adata)
 Delete all cached messages.
 
void pop_fetch_mail (void)
 Fetch messages and save them in $spool_file.
 
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() -.
 
static bool pop_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -.
 
static enum MxOpenReturns pop_mbox_open (struct Mailbox *m)
 Open a Mailbox - Implements MxOps::mbox_open() -.
 
static enum MxStatus pop_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -.
 
static enum MxStatus pop_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 
static enum MxStatus pop_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -.
 
static bool pop_msg_open (struct Mailbox *m, struct Message *msg, struct Email *e)
 Open an email message in a Mailbox - Implements MxOps::msg_open() -.
 
static int pop_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -.
 
static int pop_msg_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Implements MxOps::msg_save_hcache() -.
 
enum MailboxType pop_path_probe (const char *path, const struct stat *st)
 Is this a POP Mailbox?
 
static int pop_path_canon (struct Buffer *path)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
 

Variables

const struct MxOps MxPopOps
 POP Mailbox - Implements MxOps -.
 

Detailed Description

POP network mailbox.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Ian Zimmerman

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 69 of file pop.c.

◆ HC_FEXT

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

Definition at line 70 of file pop.c.

◆ POP_MAX_MESSAGES

#define POP_MAX_MESSAGES   500000

Hard limit on UIDL responses to prevent a malicious server from causing unbounded memory growth.

Definition at line 74 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 85 of file pop.c.

86{
87 static char clean[128];
88 mutt_str_copy(clean, id, sizeof(clean));
89 mutt_file_sanitize_filename(clean, true);
90 return clean;
91}
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition file.c:582
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:586
+ 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 122 of file pop.c.

123{
124 FILE *fp = mutt_file_mkstemp();
125 if (!fp)
126 {
127 mutt_perror(_("Can't create temporary file"));
128 return -3;
129 }
130
131 int index = 0;
132 size_t length = 0;
133 char buf[1024] = { 0 };
134
135 struct PopEmailData *edata = pop_edata_get(e);
136
137 snprintf(buf, sizeof(buf), "LIST %d\r\n", edata->refno);
138 int rc = pop_query(adata, buf, sizeof(buf));
139 if (rc == 0)
140 {
141 if (sscanf(buf, "+OK %d %zu", &index, &length) == 2)
142 {
143 snprintf(buf, sizeof(buf), "TOP %d 0\r\n", edata->refno);
144 rc = pop_fetch_data(adata, buf, NULL, fetch_message, fp);
145
146 if (adata->cmd_top == 2)
147 {
148 if (rc == 0)
149 {
150 adata->cmd_top = 1;
151
152 mutt_debug(LL_DEBUG1, "set TOP capability\n");
153 }
154
155 if (rc == -2)
156 {
157 adata->cmd_top = 0;
158
159 mutt_debug(LL_DEBUG1, "unset TOP capability\n");
160 snprintf(adata->err_msg, sizeof(adata->err_msg), "%s",
161 _("Command TOP is not supported by server"));
162 }
163 }
164 else
165 {
166 mutt_debug(LL_DEBUG1, "Malformed LIST response: %s\n", buf);
167 rc = -1;
168 }
169 }
170 }
171
172 switch (rc)
173 {
174 case 0:
175 {
176 rewind(fp);
177 e->env = mutt_rfc822_read_header(fp, e, false, false);
178 e->body->length = length - e->body->offset + 1;
179 rewind(fp);
180 while (!feof(fp))
181 {
182 e->body->length--;
183 if (!fgets(buf, sizeof(buf), fp))
184 break;
185 }
186 break;
187 }
188 case -2:
189 {
190 mutt_error("%s", adata->err_msg);
191 break;
192 }
193 case -3:
194 {
195 mutt_error(_("Can't write header to temporary file"));
196 break;
197 }
198 }
199
200 mutt_file_fclose(&fp);
201 return rc;
202}
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition parse.c:1172
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
static int fetch_message(const char *line, void *data)
Parse a Message response - Implements pop_fetch_t -.
Definition pop.c:102
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define _(a)
Definition message.h:28
struct PopEmailData * pop_edata_get(struct Email *e)
Get the private data for this Email.
Definition edata.c:68
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:511
#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:68
void * edata
Driver-specific data.
Definition email.h:74
struct Body * body
List of MIME parts.
Definition email.h:69
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]
Last error message.
Definition adata.h:57
POP-specific Email data -.
Definition edata.h:32
#define mutt_file_mkstemp()
Definition tmp.h:36
+ 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 316 of file pop.c.

317{
318 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
319 if (!adata || !adata->conn)
320 return hcache_open(c_header_cache, path, NULL, true);
321
322 struct Url url = { 0 };
323 char p[1024] = { 0 };
324
325 account_to_url(&adata->conn->account, &url);
326 url.path = HC_FNAME;
327 url_tostring(&url, p, sizeof(p), U_PATH);
328 return hcache_open(c_header_cache, p, pop_hcache_namer, true);
329}
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
static void pop_hcache_namer(const struct StoreOps *store_ops, const char *path, struct Buffer *dest)
Create a header cache filename for a POP mailbox - Implements hcache_namer_t -.
Definition pop.c:304
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer, bool create)
Multiplexor for StoreOps::open.
Definition hcache.c:477
void account_to_url(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
#define HC_FNAME
Definition pop.c:69
struct ConnAccount account
Account details: username, password, etc.
Definition connection.h:49
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
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(const struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition url.c:426
#define U_PATH
Path is included in URL.
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 340 of file pop.c.

341{
342 if (!m)
343 return -1;
344
346 struct Progress *progress = NULL;
347
348#ifdef USE_HCACHE
349 struct HeaderCache *hc = pop_hcache_open(adata, mailbox_path(m));
350#endif
351
352 adata->check_time = mutt_date_now();
353 adata->clear_cache = false;
354
355 for (int i = 0; i < m->msg_count; i++)
356 {
357 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
358 edata->refno = -1;
359 }
360
361 const int old_count = m->msg_count;
362 int rc = pop_fetch_data(adata, "UIDL\r\n", NULL, fetch_uidl, m);
363 const int new_count = m->msg_count;
364 m->msg_count = old_count;
365
366 if (adata->cmd_uidl == 2)
367 {
368 if (rc == 0)
369 {
370 adata->cmd_uidl = 1;
371
372 mutt_debug(LL_DEBUG1, "set UIDL capability\n");
373 }
374
375 if ((rc == -2) && (adata->cmd_uidl == 2))
376 {
377 adata->cmd_uidl = 0;
378
379 mutt_debug(LL_DEBUG1, "unset UIDL capability\n");
380 snprintf(adata->err_msg, sizeof(adata->err_msg), "%s",
381 _("Command UIDL is not supported by server"));
382 }
383 }
384
385 if (m->verbose)
386 {
387 progress = progress_new(MUTT_PROGRESS_READ, new_count - old_count);
388 progress_set_message(progress, _("Fetching message headers..."));
389 }
390
391 if (rc == 0)
392 {
393 int i, deleted;
394 for (i = 0, deleted = 0; i < old_count; i++)
395 {
396 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
397 if (edata->refno == -1)
398 {
399 m->emails[i]->deleted = true;
400 deleted++;
401 }
402 }
403 if (deleted > 0)
404 {
405 mutt_error(ngettext("%d message has been lost. Try reopening the mailbox.",
406 "%d messages have been lost. Try reopening the mailbox.", deleted),
407 deleted);
408 }
409
410 bool hcached = false;
411 for (i = old_count; i < new_count; i++)
412 {
413 progress_update(progress, i + 1 - old_count, -1);
414 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
415#ifdef USE_HCACHE
416 struct HCacheEntry hce = hcache_fetch_email(hc, edata->uid, strlen(edata->uid), 0);
417 if (hce.email)
418 {
419 /* Detach the private data */
420 m->emails[i]->edata = NULL;
421
422 int index = m->emails[i]->index;
423 /* - POP dynamically numbers headers and relies on e->refno
424 * to map messages; so restore header and overwrite restored
425 * refno with current refno, same for index
426 * - e->data needs to a separate pointer as it's driver-specific
427 * data freed separately elsewhere
428 * (the old e->data should point inside a malloc'd block from
429 * hcache so there shouldn't be a memleak here) */
430 email_free(&m->emails[i]);
431 m->emails[i] = hce.email;
432 m->emails[i]->index = index;
433
434 /* Reattach the private data */
435 m->emails[i]->edata = edata;
437 rc = 0;
438 hcached = true;
439 }
440 else
441#endif
442 if ((rc = pop_read_header(adata, m->emails[i])) < 0)
443 break;
444#ifdef USE_HCACHE
445 else
446 {
447 hcache_store_email(hc, edata->uid, strlen(edata->uid), m->emails[i], 0);
448 }
449#endif
450
451 /* faked support for flags works like this:
452 * - if 'hcached' is true, we have the message in our hcache:
453 * - if we also have a body: read
454 * - if we don't have a body: old
455 * (if $mark_old is set which is maybe wrong as
456 * $mark_old should be considered for syncing the
457 * folder and not when opening it XXX)
458 * - if 'hcached' is false, we don't have the message in our hcache:
459 * - if we also have a body: read
460 * - if we don't have a body: new */
461 const bool bcached = (mutt_bcache_exists(adata->bcache, cache_id(edata->uid)) == 0);
462 m->emails[i]->old = false;
463 m->emails[i]->read = false;
464 if (hcached)
465 {
466 const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
467 if (bcached)
468 m->emails[i]->read = true;
469 else if (c_mark_old)
470 m->emails[i]->old = true;
471 }
472 else
473 {
474 if (bcached)
475 m->emails[i]->read = true;
476 }
477
478 m->msg_count++;
479 }
480 }
481 progress_free(&progress);
482
483#ifdef USE_HCACHE
484 hcache_close(&hc);
485#endif
486
487 if (rc < 0)
488 {
489 for (int i = m->msg_count; i < new_count; i++)
490 email_free(&m->emails[i]);
491 return rc;
492 }
493
494 /* after putting the result into our structures,
495 * clean up cache, i.e. wipe messages deleted outside
496 * the availability of our cache */
497 const bool c_message_cache_clean = cs_subset_bool(NeoMutt->sub, "message_cache_clean");
498 if (c_message_cache_clean)
500
502 return new_count - old_count;
503}
int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
Check if a file exists in the Body Cache.
Definition bcache.c:297
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition bcache.c:339
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:213
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
static int pop_bcache_delete(const char *id, struct BodyCache *bcache, void *data)
Delete an entry from the message cache - Implements bcache_list_t -.
Definition pop.c:271
void pop_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free() -.
Definition edata.c:41
static int fetch_uidl(const char *line, void *data)
Parse UIDL response - Implements pop_fetch_t -.
Definition pop.c:211
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition hcache.c:549
struct HCacheEntry hcache_fetch_email(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition hcache.c:569
int hcache_store_email(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition hcache.c:683
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
struct PopAccountData * pop_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition adata.c:73
static const char * cache_id(const char *id)
Make a message-cache-compatible id.
Definition pop.c:85
static struct HeaderCache * pop_hcache_open(struct PopAccountData *adata, const char *path)
Open the header cache.
Definition pop.c:316
static int pop_read_header(struct PopAccountData *adata, struct Email *e)
Read header.
Definition pop.c:122
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition lib.h:84
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition progress.c:80
void * adata
Private data (for Mailbox backends)
Definition account.h:42
bool read
Email is read.
Definition email.h:50
bool old
Email is seen, but unread.
Definition email.h:49
void(* edata_free)(void **ptr)
Definition email.h:90
bool deleted
Email is deleted.
Definition email.h:78
Wrapper for Email retrieved from the header cache.
Definition lib.h:100
struct Email * email
Retrieved email.
Definition lib.h:103
Header Cache.
Definition lib.h:87
int msg_count
Total number of messages.
Definition mailbox.h:87
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
bool verbose
Display status messages?
Definition mailbox.h:116
POP-specific Account data -.
Definition adata.h:37
bool clear_cache
Clear the cache.
Definition adata.h:49
time_t check_time
Last check time.
Definition adata.h:51
struct BodyCache * bcache
body cache
Definition adata.h:56
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 509 of file pop.c.

510{
511 if (!adata->clear_cache)
512 return;
513
514 mutt_debug(LL_DEBUG1, "delete cached messages\n");
515
516 for (int i = 0; i < POP_CACHE_LEN; i++)
517 {
518 if (adata->cache[i].path)
519 {
520 unlink(adata->cache[i].path);
521 FREE(&adata->cache[i].path);
522 }
523 }
524}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define POP_CACHE_LEN
Number of entries in the POP cache hash table.
Definition private.h:38
struct PopCache cache[POP_CACHE_LEN]
Message cache.
Definition adata.h:58
char * path
Filesystem path.
Definition private.h:69
+ 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 529 of file pop.c.

530{
531 const char *const c_pop_host = cs_subset_string(NeoMutt->sub, "pop_host");
532 if (!c_pop_host)
533 {
534 mutt_error(_("POP host is not defined"));
535 return;
536 }
537
538 char buf[1024] = { 0 };
539 char msgbuf[128] = { 0 };
540 int last = 0, msgs = 0, bytes = 0, rset = 0, rc;
541 struct ConnAccount cac = { { 0 } };
542
543 char *p = MUTT_MEM_CALLOC(strlen(c_pop_host) + 7, char);
544 char *url = p;
545 if (url_check_scheme(c_pop_host) == U_UNKNOWN)
546 {
547 strcpy(url, "pop://");
548 p = strchr(url, '\0');
549 }
550 strcpy(p, c_pop_host);
551
552 rc = pop_parse_path(url, &cac);
553 FREE(&url);
554 if (rc)
555 {
556 mutt_error(_("%s is an invalid POP path"), c_pop_host);
557 return;
558 }
559
560 struct Connection *conn = mutt_conn_find(&cac);
561 if (!conn)
562 return;
563
565 adata->conn = conn;
566
567 if (pop_open_connection(adata) < 0)
568 {
569 pop_adata_free((void **) &adata);
570 return;
571 }
572
573 mutt_message(_("Checking for new messages..."));
574
575 /* find out how many messages are in the mailbox. */
576 mutt_str_copy(buf, "STAT\r\n", sizeof(buf));
577 rc = pop_query(adata, buf, sizeof(buf));
578 if (rc == -1)
579 goto fail;
580 if (rc == -2)
581 {
582 mutt_error("%s", adata->err_msg);
583 goto finish;
584 }
585
586 sscanf(buf, "+OK %d %d", &msgs, &bytes);
587
588 /* only get unread messages */
589 const bool c_pop_last = cs_subset_bool(NeoMutt->sub, "pop_last");
590 if ((msgs > 0) && c_pop_last)
591 {
592 mutt_str_copy(buf, "LAST\r\n", sizeof(buf));
593 rc = pop_query(adata, buf, sizeof(buf));
594 if (rc == -1)
595 goto fail;
596 if (rc == 0)
597 sscanf(buf, "+OK %d", &last);
598 }
599
600 if (msgs <= last)
601 {
602 mutt_message(_("No new mail in POP mailbox"));
603 goto finish;
604 }
605
606 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
607 struct Mailbox *m_spool = mx_path_resolve(c_spool_file);
608
609 if (!mx_mbox_open(m_spool, MUTT_OPEN_NO_FLAGS))
610 {
611 mailbox_free(&m_spool);
612 goto finish;
613 }
614 bool old_append = m_spool->append;
615 m_spool->append = true;
616
617 enum QuadOption delanswer = query_quadoption(_("Delete messages from server?"),
618 NeoMutt->sub, "pop_delete");
619
620 snprintf(msgbuf, sizeof(msgbuf),
621 ngettext("Reading new messages (%d byte)...",
622 "Reading new messages (%d bytes)...", bytes),
623 bytes);
624 mutt_message("%s", msgbuf);
625
626 for (int i = last + 1; i <= msgs; i++)
627 {
628 struct Message *msg = mx_msg_open_new(m_spool, NULL, MUTT_ADD_FROM);
629 if (msg)
630 {
631 snprintf(buf, sizeof(buf), "RETR %d\r\n", i);
632 rc = pop_fetch_data(adata, buf, NULL, fetch_message, msg->fp);
633 if (rc == -3)
634 rset = 1;
635
636 if ((rc == 0) && (mx_msg_commit(m_spool, msg) != 0))
637 {
638 rset = 1;
639 rc = -3;
640 }
641
642 mx_msg_close(m_spool, &msg);
643 }
644 else
645 {
646 rc = -3;
647 }
648
649 if ((rc == 0) && (delanswer == MUTT_YES))
650 {
651 /* delete the message on the server */
652 snprintf(buf, sizeof(buf), "DELE %d\r\n", i);
653 rc = pop_query(adata, buf, sizeof(buf));
654 }
655
656 if (rc == -1)
657 {
658 m_spool->append = old_append;
659 mx_mbox_close(m_spool);
660 goto fail;
661 }
662 if (rc == -2)
663 {
664 mutt_error("%s", adata->err_msg);
665 break;
666 }
667 if (rc == -3)
668 {
669 mutt_error(_("Error while writing mailbox"));
670 break;
671 }
672
673 /* L10N: The plural is picked by the second numerical argument, i.e.
674 the %d right before 'messages', i.e. the total number of messages. */
675 mutt_message(ngettext("%s [%d of %d message read]",
676 "%s [%d of %d messages read]", msgs - last),
677 msgbuf, i - last, msgs - last);
678 }
679
680 m_spool->append = old_append;
681 mx_mbox_close(m_spool);
682
683 if (rset)
684 {
685 /* make sure no messages get deleted */
686 mutt_str_copy(buf, "RSET\r\n", sizeof(buf));
687 if (pop_query(adata, buf, sizeof(buf)) == -1)
688 goto fail;
689 }
690
691finish:
692 /* exit gracefully */
693 mutt_str_copy(buf, "QUIT\r\n", sizeof(buf));
694 if (pop_query(adata, buf, sizeof(buf)) == -1)
695 goto fail;
696 mutt_socket_close(conn);
697 pop_adata_free((void **) &adata);
698 return;
699
700fail:
701 mutt_error(_("Server closed connection"));
702 mutt_socket_close(conn);
703 pop_adata_free((void **) &adata);
704}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition mailbox.c:90
void pop_adata_free(void **ptr)
Free the private Account data - Implements Account::adata_free() -.
Definition adata.c:41
#define mutt_message(...)
Definition logging2.h:93
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
struct Connection * mutt_conn_find(const struct ConnAccount *cac)
Find a connection from a list.
Definition mutt_socket.c:88
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition mx.c:285
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition mx.c:1041
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition mx.c:1161
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1647
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
#define MUTT_ADD_FROM
add a From_ line
Definition mx.h:39
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition mxapi.h:39
struct PopAccountData * pop_adata_new(void)
Create a new PopAccountData object.
Definition adata.c:63
int pop_open_connection(struct PopAccountData *adata)
Open connection and authenticate.
Definition lib.c:316
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(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition socket.c:100
Login details for a remote server.
Definition connaccount.h:53
A mailbox.
Definition mailbox.h:78
bool append
Mailbox is opened in append mode.
Definition mailbox.h:108
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition url.c:229
@ 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: