NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
pop.c
Go to the documentation of this file.
1
24
32
33#include "config.h"
34#include <errno.h>
35#include <limits.h>
36#include <stdbool.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41#include "private.h"
42#include "mutt/lib.h"
43#include "config/lib.h"
44#include "email/lib.h"
45#include "core/lib.h"
46#include "conn/lib.h"
47#include "lib.h"
48#include "bcache/lib.h"
49#include "hooks/lib.h"
50#include "ncrypt/lib.h"
51#include "progress/lib.h"
52#include "question/lib.h"
53#include "store/lib.h"
54#include "adata.h"
55#include "edata.h"
56#include "mutt_logging.h"
57#include "mutt_socket.h"
58#include "mx.h"
59#ifdef ENABLE_NLS
60#include <libintl.h>
61#endif
62#ifdef USE_HCACHE
63#include "hcache/lib.h"
64#endif
65
66struct BodyCache;
67struct stat;
68
69#define HC_FNAME "neomutt" /* filename for hcache as POP lacks paths */
70#define HC_FEXT "hcache" /* extension for hcache as POP lacks paths */
71
74#define POP_MAX_MESSAGES 500000
75
85static const char *cache_id(const char *id)
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}
92
102static int fetch_message(const char *line, void *data)
103{
104 FILE *fp = data;
105
106 fputs(line, fp);
107 if (fputc('\n', fp) == EOF)
108 return -1;
109
110 return 0;
111}
112
122static int pop_read_header(struct PopAccountData *adata, struct Email *e)
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}
203
211static int fetch_uidl(const char *line, void *data)
212{
213 struct Mailbox *m = data;
215 char *endp = NULL;
216
217 errno = 0;
218 int index = strtol(line, &endp, 10);
219 if ((errno != 0) || (endp == line))
220 return -1;
221 while (*endp == ' ')
222 endp++;
223 line = endp;
224
225 /* uid must be at least be 1 byte */
226 if (strlen(line) == 0)
227 return -1;
228
229 int i;
230 for (i = 0; i < m->msg_count; i++)
231 {
232 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
233 if (mutt_str_equal(line, edata->uid))
234 break;
235 }
236
237 if (i == m->msg_count)
238 {
239 if (m->msg_count >= POP_MAX_MESSAGES)
240 {
241 mutt_debug(LL_DEBUG1, "UIDL response limit reached (%d)\n", POP_MAX_MESSAGES);
242 return -1;
243 }
244
245 mutt_debug(LL_DEBUG1, "new header %d %s\n", index, line);
246
247 mx_alloc_memory(m, i);
248
249 m->msg_count++;
250 m->emails[i] = email_new();
251
252 m->emails[i]->edata = pop_edata_new(line);
254 }
255 else if (m->emails[i]->index != index - 1)
256 {
257 adata->clear_cache = true;
258 }
259
260 m->emails[i]->index = index - 1;
261
262 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
263 edata->refno = index;
264
265 return 0;
266}
267
271static int pop_bcache_delete(const char *id, struct BodyCache *bcache, void *data)
272{
273 struct Mailbox *m = data;
274 if (!m)
275 return -1;
276
278 if (!adata)
279 return -1;
280
281#ifdef USE_HCACHE
282 /* keep hcache file if hcache == bcache */
283 if (mutt_str_equal(HC_FNAME "." HC_FEXT, id))
284 return 0;
285#endif
286
287 for (int i = 0; i < m->msg_count; i++)
288 {
289 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
290 /* if the id we get is known for a header: done (i.e. keep in cache) */
291 if (edata->uid && mutt_str_equal(edata->uid, id))
292 return 0;
293 }
294
295 /* message not found in context -> remove it from cache
296 * return the result of bcache, so we stop upon its first error */
297 return mutt_bcache_del(bcache, cache_id(id));
298}
299
300#ifdef USE_HCACHE
304static void pop_hcache_namer(const struct StoreOps *store_ops, const char *path,
305 struct Buffer *dest)
306{
307 buf_printf(dest, "%s.%s." HC_FEXT, path, store_ops->name);
308}
309
316static struct HeaderCache *pop_hcache_open(struct PopAccountData *adata, const char *path)
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}
330#endif
331
340static int pop_fetch_headers(struct Mailbox *m)
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}
504
509static void pop_clear_cache(struct PopAccountData *adata)
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}
525
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 *url = NULL;
544 if (url_check_scheme(c_pop_host) == U_UNKNOWN)
545 mutt_str_asprintf(&url, "pop://%s", c_pop_host);
546 else
547 url = mutt_str_dup(c_pop_host);
548
549 rc = pop_parse_path(url, &cac);
550 FREE(&url);
551 if (rc)
552 {
553 mutt_error(_("%s is an invalid POP path"), c_pop_host);
554 return;
555 }
556
557 struct Connection *conn = mutt_conn_find(&cac);
558 if (!conn)
559 return;
560
562 adata->conn = conn;
563
564 if (pop_open_connection(adata) < 0)
565 {
566 pop_adata_free((void **) &adata);
567 return;
568 }
569
570 mutt_message(_("Checking for new messages..."));
571
572 /* find out how many messages are in the mailbox. */
573 mutt_str_copy(buf, "STAT\r\n", sizeof(buf));
574 rc = pop_query(adata, buf, sizeof(buf));
575 if (rc == -1)
576 goto fail;
577 if (rc == -2)
578 {
579 mutt_error("%s", adata->err_msg);
580 goto finish;
581 }
582
583 sscanf(buf, "+OK %d %d", &msgs, &bytes);
584
585 /* only get unread messages */
586 const bool c_pop_last = cs_subset_bool(NeoMutt->sub, "pop_last");
587 if ((msgs > 0) && c_pop_last)
588 {
589 mutt_str_copy(buf, "LAST\r\n", sizeof(buf));
590 rc = pop_query(adata, buf, sizeof(buf));
591 if (rc == -1)
592 goto fail;
593 if (rc == 0)
594 sscanf(buf, "+OK %d", &last);
595 }
596
597 if (msgs <= last)
598 {
599 mutt_message(_("No new mail in POP mailbox"));
600 goto finish;
601 }
602
603 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
604 struct Mailbox *m_spool = mx_path_resolve(c_spool_file);
605
606 if (!mx_mbox_open(m_spool, MUTT_OPEN_NONE))
607 {
608 mailbox_free(&m_spool);
609 goto finish;
610 }
611 bool old_append = m_spool->append;
612 m_spool->append = true;
613
614 enum QuadOption delanswer = query_quadoption(_("Delete messages from server?"),
615 NeoMutt->sub, "pop_delete");
616
617 snprintf(msgbuf, sizeof(msgbuf),
618 ngettext("Reading new messages (%d byte)...",
619 "Reading new messages (%d bytes)...", bytes),
620 bytes);
621 mutt_message("%s", msgbuf);
622
623 for (int i = last + 1; i <= msgs; i++)
624 {
625 struct Message *msg = mx_msg_open_new(m_spool, NULL, MUTT_ADD_FROM);
626 if (msg)
627 {
628 snprintf(buf, sizeof(buf), "RETR %d\r\n", i);
629 rc = pop_fetch_data(adata, buf, NULL, fetch_message, msg->fp);
630 if (rc == -3)
631 rset = 1;
632
633 if ((rc == 0) && (mx_msg_commit(m_spool, msg) != 0))
634 {
635 rset = 1;
636 rc = -3;
637 }
638
639 mx_msg_close(m_spool, &msg);
640 }
641 else
642 {
643 rc = -3;
644 }
645
646 if ((rc == 0) && (delanswer == MUTT_YES))
647 {
648 /* delete the message on the server */
649 snprintf(buf, sizeof(buf), "DELE %d\r\n", i);
650 rc = pop_query(adata, buf, sizeof(buf));
651 }
652
653 if (rc == -1)
654 {
655 m_spool->append = old_append;
656 mx_mbox_close(m_spool);
657 goto fail;
658 }
659 if (rc == -2)
660 {
661 mutt_error("%s", adata->err_msg);
662 break;
663 }
664 if (rc == -3)
665 {
666 mutt_error(_("Error while writing mailbox"));
667 break;
668 }
669
670 /* L10N: The plural is picked by the second numerical argument, i.e.
671 the %d right before 'messages', i.e. the total number of messages. */
672 mutt_message(ngettext("%s [%d of %d message read]",
673 "%s [%d of %d messages read]", msgs - last),
674 msgbuf, i - last, msgs - last);
675 }
676
677 m_spool->append = old_append;
678 mx_mbox_close(m_spool);
679
680 if (rset)
681 {
682 /* make sure no messages get deleted */
683 mutt_str_copy(buf, "RSET\r\n", sizeof(buf));
684 if (pop_query(adata, buf, sizeof(buf)) == -1)
685 goto fail;
686 }
687
688finish:
689 /* exit gracefully */
690 mutt_str_copy(buf, "QUIT\r\n", sizeof(buf));
691 if (pop_query(adata, buf, sizeof(buf)) == -1)
692 goto fail;
693 mutt_socket_close(conn);
694 pop_adata_free((void **) &adata);
695 return;
696
697fail:
698 mutt_error(_("Server closed connection"));
699 mutt_socket_close(conn);
700 pop_adata_free((void **) &adata);
701}
702
706static bool pop_ac_owns_path(struct Account *a, const char *path)
707{
708 struct Url *url = url_parse(path);
709 if (!url)
710 return false;
711
712 struct PopAccountData *adata = a->adata;
713 struct ConnAccount *cac = &adata->conn->account;
714
715 const bool rc = mutt_istr_equal(url->host, cac->host) &&
716 mutt_istr_equal(url->user, cac->user);
717 url_free(&url);
718 return rc;
719}
720
724static bool pop_ac_add(struct Account *a, struct Mailbox *m)
725{
726 if (a->adata)
727 return true;
728
729 struct ConnAccount cac = { { 0 } };
730 if (pop_parse_path(mailbox_path(m), &cac) != 0)
731 {
732 mutt_error(_("%s is an invalid POP path"), mailbox_path(m));
733 return false;
734 }
735
737 adata->conn = mutt_conn_new(&cac);
738 if (!adata->conn)
739 {
740 pop_adata_free((void **) &adata);
741 return false;
742 }
743 a->adata = adata;
745
746 return true;
747}
748
754static enum MxOpenReturns pop_mbox_open(struct Mailbox *m)
755{
756 if (!m->account)
757 return MX_OPEN_ERROR;
758
759 char buf[PATH_MAX] = { 0 };
760 struct ConnAccount cac = { { 0 } };
761 struct Url url = { 0 };
762
763 if (pop_parse_path(mailbox_path(m), &cac) != 0)
764 {
765 mutt_error(_("%s is an invalid POP path"), mailbox_path(m));
766 return MX_OPEN_ERROR;
767 }
768
769 account_to_url(&cac, &url);
770 url.path = NULL;
771 url_tostring(&url, buf, sizeof(buf), U_NONE);
772
773 buf_strcpy(&m->pathbuf, buf);
775
776 struct PopAccountData *adata = m->account->adata;
777 if (!adata)
778 {
780 m->account->adata = adata;
782 }
783
784 struct Connection *conn = adata->conn;
785 if (!conn)
786 {
787 adata->conn = mutt_conn_new(&cac);
788 conn = adata->conn;
789 if (!conn)
790 return MX_OPEN_ERROR;
791 }
792
793 if (conn->fd < 0)
795
796 if (pop_open_connection(adata) < 0)
797 return MX_OPEN_ERROR;
798
799 adata->bcache = mutt_bcache_open(&cac, NULL);
800
801 /* init (hard-coded) ACL rights */
803#ifdef USE_HCACHE
804 /* flags are managed using header cache, so it only makes sense to
805 * enable them in that case */
807#endif
808
809 while (true)
810 {
811 if (pop_reconnect(m) < 0)
812 return MX_OPEN_ERROR;
813
814 m->size = adata->size;
815
816 mutt_message(_("Fetching list of messages..."));
817
818 const int rc = pop_fetch_headers(m);
819
820 if (rc >= 0)
821 return MX_OPEN_OK;
822
823 if (rc < -1)
824 return MX_OPEN_ERROR;
825 }
826}
827
831static enum MxStatus pop_mbox_check(struct Mailbox *m)
832{
833 if (!m || !m->account)
834 return MX_STATUS_ERROR;
835
837
838 const short c_pop_check_interval = cs_subset_number(NeoMutt->sub, "pop_check_interval");
839 if ((adata->check_time + c_pop_check_interval) > mutt_date_now())
840 return MX_STATUS_OK;
841
842 pop_logout(m);
843
845
846 if (pop_open_connection(adata) < 0)
847 return MX_STATUS_ERROR;
848
849 m->size = adata->size;
850
851 mutt_message(_("Checking for new messages..."));
852
853 int old_msg_count = m->msg_count;
854 int rc = pop_fetch_headers(m);
856 if (m->msg_count > old_msg_count)
858
859 if (rc < 0)
860 return MX_STATUS_ERROR;
861
862 if (rc > 0)
863 return MX_STATUS_NEW_MAIL;
864
865 return MX_STATUS_OK;
866}
867
873static enum MxStatus pop_mbox_sync(struct Mailbox *m)
874{
875 int i, j, rc = 0;
876 char buf[1024] = { 0 };
878#ifdef USE_HCACHE
879 struct HeaderCache *hc = NULL;
880#endif
881
882 adata->check_time = 0;
883
884 int num_deleted = 0;
885 for (i = 0; i < m->msg_count; i++)
886 {
887 if (m->emails[i]->deleted)
888 num_deleted++;
889 }
890
891 while (true)
892 {
893 if (pop_reconnect(m) < 0)
894 return MX_STATUS_ERROR;
895
896#ifdef USE_HCACHE
897 hc = pop_hcache_open(adata, mailbox_path(m));
898#endif
899
900 struct Progress *progress = NULL;
901 if (m->verbose)
902 {
903 progress = progress_new(MUTT_PROGRESS_WRITE, num_deleted);
904 progress_set_message(progress, _("Marking messages deleted..."));
905 }
906
907 for (i = 0, j = 0, rc = 0; (rc == 0) && (i < m->msg_count); i++)
908 {
909 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
910 if (m->emails[i]->deleted && (edata->refno != -1))
911 {
912 j++;
913 progress_update(progress, j, -1);
914 snprintf(buf, sizeof(buf), "DELE %d\r\n", edata->refno);
915 rc = pop_query(adata, buf, sizeof(buf));
916 if (rc == 0)
917 {
918 mutt_bcache_del(adata->bcache, cache_id(edata->uid));
919#ifdef USE_HCACHE
920 hcache_delete_email(hc, edata->uid, strlen(edata->uid));
921#endif
922 }
923 }
924
925#ifdef USE_HCACHE
926 if (m->emails[i]->changed)
927 {
928 hcache_store_email(hc, edata->uid, strlen(edata->uid), m->emails[i], 0);
929 }
930#endif
931 }
932 progress_free(&progress);
933
934#ifdef USE_HCACHE
935 hcache_close(&hc);
936#endif
937
938 if (rc == 0)
939 {
940 mutt_str_copy(buf, "QUIT\r\n", sizeof(buf));
941 rc = pop_query(adata, buf, sizeof(buf));
942 }
943
944 if (rc == 0)
945 {
946 adata->clear_cache = true;
947 pop_clear_cache(adata);
948 adata->status = POP_DISCONNECTED;
949 return MX_STATUS_OK;
950 }
951
952 if (rc == -2)
953 {
954 mutt_error("%s", adata->err_msg);
955 return MX_STATUS_ERROR;
956 }
957 }
958}
959
963static enum MxStatus pop_mbox_close(struct Mailbox *m)
964{
966 if (!adata)
967 return MX_STATUS_OK;
968
969 pop_logout(m);
970
971 if (adata->status != POP_NONE)
972 {
974 }
975
976 adata->status = POP_NONE;
977
978 adata->clear_cache = true;
980
981 mutt_bcache_close(&adata->bcache);
982
983 return MX_STATUS_OK;
984}
985
989static bool pop_msg_open(struct Mailbox *m, struct Message *msg, struct Email *e)
990{
991 char buf[1024] = { 0 };
993 struct PopEmailData *edata = pop_edata_get(e);
994 bool bcache = true;
995 bool success = false;
996 struct Buffer *path = NULL;
997
998 /* see if we already have the message in body cache */
999 msg->fp = mutt_bcache_get(adata->bcache, cache_id(edata->uid));
1000 if (msg->fp)
1001 return true;
1002
1003 /* see if we already have the message in our cache in
1004 * case $message_cache_dir is unset */
1005 struct PopCache *cache = &adata->cache[e->index % POP_CACHE_LEN];
1006
1007 if (cache->path)
1008 {
1009 if (cache->index == e->index)
1010 {
1011 /* yes, so just return a pointer to the message */
1012 msg->fp = mutt_file_fopen(cache->path, "r");
1013 if (msg->fp)
1014 return true;
1015
1016 mutt_perror("%s", cache->path);
1017 return false;
1018 }
1019 else
1020 {
1021 /* clear the previous entry */
1022 unlink(cache->path);
1023 FREE(&cache->path);
1024 }
1025 }
1026
1027 path = buf_pool_get();
1028
1029 while (true)
1030 {
1031 if (pop_reconnect(m) < 0)
1032 goto cleanup;
1033
1034 /* verify that massage index is correct */
1035 if (edata->refno < 0)
1036 {
1037 mutt_error(_("The message index is incorrect. Try reopening the mailbox."));
1038 goto cleanup;
1039 }
1040
1041 /* see if we can put in body cache; use our cache as fallback */
1042 msg->fp = mutt_bcache_put(adata->bcache, cache_id(edata->uid));
1043 if (!msg->fp)
1044 {
1045 /* no */
1046 bcache = false;
1048 msg->fp = mutt_file_fopen(buf_string(path), "w+");
1049 if (!msg->fp)
1050 {
1051 mutt_perror("%s", buf_string(path));
1052 goto cleanup;
1053 }
1054 }
1055
1056 snprintf(buf, sizeof(buf), "RETR %d\r\n", edata->refno);
1057
1058 struct Progress *progress = progress_new(MUTT_PROGRESS_NET,
1059 e->body->length + e->body->offset - 1);
1060 progress_set_message(progress, _("Fetching message..."));
1061 const int rc = pop_fetch_data(adata, buf, progress, fetch_message, msg->fp);
1062 progress_free(&progress);
1063
1064 if (rc == 0)
1065 break;
1066
1067 mutt_file_fclose(&msg->fp);
1068
1069 /* if RETR failed (e.g. connection closed), be sure to remove either
1070 * the file in bcache or from POP's own cache since the next iteration
1071 * of the loop will re-attempt to put() the message */
1072 if (!bcache)
1073 unlink(buf_string(path));
1074
1075 if (rc == -2)
1076 {
1077 mutt_error("%s", adata->err_msg);
1078 goto cleanup;
1079 }
1080
1081 if (rc == -3)
1082 {
1083 mutt_error(_("Can't write message to temporary file"));
1084 goto cleanup;
1085 }
1086 }
1087
1088 /* Update the header information. Previously, we only downloaded a
1089 * portion of the headers, those required for the main display. */
1090 if (bcache)
1091 {
1092 mutt_bcache_commit(adata->bcache, cache_id(edata->uid));
1093 }
1094 else
1095 {
1096 cache->index = e->index;
1097 cache->path = buf_strdup(path);
1098 }
1099 rewind(msg->fp);
1100
1101 /* Detach the private data */
1102 e->edata = NULL;
1103
1104 /* we replace envelope, key in subj_hash has to be updated as well */
1105 if (m->subj_hash && e->env->real_subj)
1108 mutt_env_free(&e->env);
1109 e->env = mutt_rfc822_read_header(msg->fp, e, false, false);
1110 if (m->subj_hash && e->env->real_subj)
1112 mutt_label_hash_add(m, e);
1113
1114 /* Reattach the private data */
1115 e->edata = edata;
1117
1118 e->lines = 0;
1119 while (fgets(buf, sizeof(buf), msg->fp) && !feof(msg->fp))
1120 {
1121 e->lines++;
1122 }
1123
1124 e->body->length = ftello(msg->fp) - e->body->offset;
1125
1126 /* This needs to be done in case this is a multipart message */
1127 if (!WithCrypto)
1128 e->security = crypt_query(e->body);
1129
1131 rewind(msg->fp);
1132
1133 success = true;
1134
1135cleanup:
1136 buf_pool_release(&path);
1137 return success;
1138}
1139
1145static int pop_msg_close(struct Mailbox *m, struct Message *msg)
1146{
1147 return mutt_file_fclose(&msg->fp);
1148}
1149
1153static int pop_msg_save_hcache(struct Mailbox *m, struct Email *e)
1154{
1155 int rc = 0;
1156#ifdef USE_HCACHE
1157 struct PopAccountData *adata = pop_adata_get(m);
1158 struct PopEmailData *edata = e->edata;
1159 struct HeaderCache *hc = pop_hcache_open(adata, mailbox_path(m));
1160 rc = hcache_store_email(hc, edata->uid, strlen(edata->uid), e, 0);
1161 hcache_close(&hc);
1162#endif
1163
1164 return rc;
1165}
1166
1170enum MailboxType pop_path_probe(const char *path, const struct stat *st)
1171{
1172 if (mutt_istr_startswith(path, "pop://"))
1173 return MUTT_POP;
1174
1175 if (mutt_istr_startswith(path, "pops://"))
1176 return MUTT_POP;
1177
1178 return MUTT_UNKNOWN;
1179}
1180
1184static int pop_path_canon(struct Buffer *path)
1185{
1186 return 0;
1187}
1188
1192const struct MxOps MxPopOps = {
1193 // clang-format off
1194 .type = MUTT_POP,
1195 .name = "pop",
1196 .is_local = false,
1197 .ac_owns_path = pop_ac_owns_path,
1198 .ac_add = pop_ac_add,
1199 .mbox_open = pop_mbox_open,
1200 .mbox_open_append = NULL,
1201 .mbox_check = pop_mbox_check,
1202 .mbox_check_stats = NULL,
1203 .mbox_sync = pop_mbox_sync,
1204 .mbox_close = pop_mbox_close,
1205 .msg_open = pop_msg_open,
1206 .msg_open_new = NULL,
1207 .msg_commit = NULL,
1208 .msg_close = pop_msg_close,
1209 .msg_padding_size = NULL,
1210 .msg_save_hcache = pop_msg_save_hcache,
1211 .tags_edit = NULL,
1212 .tags_commit = NULL,
1213 .path_probe = pop_path_probe,
1214 .path_canon = pop_path_canon,
1215 .path_is_empty = NULL,
1216 // clang-format on
1217};
Body Caching (local copies of email bodies)
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_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition bcache.c:254
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition bcache.c:146
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
FILE * mutt_bcache_get(struct BodyCache *bcache, const char *id)
Open a file in the Body Cache.
Definition bcache.c:185
void mutt_bcache_close(struct BodyCache **ptr)
Close an Email-Body Cache.
Definition bcache.c:167
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition bcache.c:274
FILE * mutt_bcache_put(struct BodyCache *bcache, const char *id)
Create a file in the Body Cache.
Definition bcache.c:212
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Connection Library.
Convenience wrapper for the core headers.
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition mailbox.c:90
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition mailbox.c:232
@ NT_MAILBOX_INVALID
Email list was changed.
Definition mailbox.h:182
@ MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition mailbox.h:71
@ MUTT_ACL_DELETE
Delete a message.
Definition mailbox.h:63
@ MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition mailbox.h:70
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:216
MailboxType
Supported mailbox formats.
Definition mailbox.h:40
@ MUTT_POP
'POP3' Mailbox type
Definition mailbox.h:51
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition mailbox.h:43
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition crypt.c:692
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
void mutt_label_hash_remove(struct Mailbox *m, struct Email *e)
Remove a message's labels from the Hash Table.
Definition header.c:430
void mutt_label_hash_add(struct Mailbox *m, struct Email *e)
Add a message's labels to the Hash Table.
Definition header.c:417
Structs that make up an email.
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition parse.c:1261
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition file.c:582
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
void pop_adata_free(void **ptr)
Free the private Account data - Implements Account::adata_free() -.
Definition adata.c:41
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 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
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
static bool pop_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Implements MxOps::ac_add() -.
Definition pop.c:724
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() -.
Definition pop.c:706
const struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition pop.c:1192
static enum MxStatus pop_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition pop.c:831
static enum MxStatus pop_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close() -.
Definition pop.c:963
static enum MxOpenReturns pop_mbox_open(struct Mailbox *m)
Open a Mailbox - Implements MxOps::mbox_open() -.
Definition pop.c:754
static enum MxStatus pop_mbox_sync(struct Mailbox *m)
Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
Definition pop.c:873
static int pop_msg_close(struct Mailbox *m, struct Message *msg)
Close an email - Implements MxOps::msg_close() -.
Definition pop.c:1145
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() -.
Definition pop.c:989
static int pop_msg_save_hcache(struct Mailbox *m, struct Email *e)
Save message to the header cache - Implements MxOps::msg_save_hcache() -.
Definition pop.c:1153
static int pop_path_canon(struct Buffer *path)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition pop.c:1184
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox?
Definition pop.c:1170
static int fetch_message(const char *line, void *data)
Parse a Message response - Implements pop_fetch_t -.
Definition pop.c:102
static int fetch_uidl(const char *line, void *data)
Parse UIDL response - Implements pop_fetch_t -.
Definition pop.c:211
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition hash.c:337
void mutt_hash_delete(struct HashTable *table, const char *strkey, const void *data)
Remove an element from a Hash Table.
Definition hash.c:429
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer, bool create)
Multiplexor for StoreOps::open.
Definition hcache.c:477
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition hcache.c:752
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
Header cache multiplexor.
void exec_account_hook(const char *url)
Perform an account hook.
Definition exec.c:328
Hook Commands.
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:808
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
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
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
#define PATH_MAX
Definition mutt.h:49
void account_to_url(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
NeoMutt Logging.
struct Connection * mutt_conn_new(const struct ConnAccount *cac)
Create a new Connection.
Definition mutt_socket.c:47
struct Connection * mutt_conn_find(const struct ConnAccount *cac)
Find a connection from a list.
Definition mutt_socket.c:88
NeoMutt connections.
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition mx.c:1208
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
API for mailboxes.
@ MUTT_ADD_FROM
add a From_ line
Definition mx.h:43
@ MUTT_OPEN_NONE
No flags are set.
Definition mxapi.h:42
MxOpenReturns
Return values for mbox_open()
Definition mxapi.h:83
@ MX_OPEN_ERROR
Open failed with an error.
Definition mxapi.h:85
@ MX_OPEN_OK
Open succeeded.
Definition mxapi.h:84
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h:70
@ MX_STATUS_ERROR
An error occurred.
Definition mxapi.h:71
@ MX_STATUS_OK
No changes.
Definition mxapi.h:72
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:73
API for encryption/signing of emails.
#define WithCrypto
Definition lib.h:132
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
struct PopAccountData * pop_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition adata.c:73
struct PopAccountData * pop_adata_new(void)
Create a new PopAccountData object.
Definition adata.c:63
Pop-specific Account data.
struct PopEmailData * pop_edata_new(const char *uid)
Create a new PopEmailData for an email.
Definition edata.c:56
struct PopEmailData * pop_edata_get(struct Email *e)
Get the private data for this Email.
Definition edata.c:68
Pop-specific Email data.
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
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
void pop_logout(struct Mailbox *m)
Logout from a POP server.
Definition lib.c:425
int pop_reconnect(struct Mailbox *m)
Reconnect and verify indexes if connection was lost.
Definition lib.c:609
POP network mailbox.
POP network mailbox.
#define pop_query(adata, buf, buflen)
Definition private.h:109
#define POP_CACHE_LEN
Number of entries in the POP cache hash table.
Definition private.h:38
@ POP_DISCONNECTED
Disconnected from server.
Definition private.h:49
@ POP_NONE
No connected to server.
Definition private.h:47
static void pop_clear_cache(struct PopAccountData *adata)
Delete all cached messages.
Definition pop.c:509
#define HC_FNAME
Definition pop.c:69
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
#define HC_FEXT
Definition pop.c:70
#define POP_MAX_MESSAGES
Hard limit on UIDL responses to prevent a malicious server from causing unbounded memory growth.
Definition pop.c:74
static int pop_read_header(struct PopAccountData *adata, struct Email *e)
Read header.
Definition pop.c:122
void pop_fetch_mail(void)
Fetch messages and save them in $spool_file.
Definition pop.c:529
static int pop_fetch_headers(struct Mailbox *m)
Read headers.
Definition pop.c:340
Progress Bar.
@ MUTT_PROGRESS_NET
Progress tracks bytes, according to $net_inc
Definition lib.h:83
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition lib.h:84
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition lib.h:85
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
QuadOption
Possible values for a quad-option.
Definition quad.h:36
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
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
Key value store.
A group of associated Mailboxes.
Definition account.h:36
void(* adata_free)(void **ptr)
Definition account.h:53
void * adata
Private data (for Mailbox backends)
Definition account.h:42
Local cache of email bodies.
Definition bcache.c:49
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
String manipulation buffer.
Definition buffer.h:36
Login details for a remote server.
Definition connaccount.h:59
char user[128]
Username.
Definition connaccount.h:62
char host[128]
Server to login to.
Definition connaccount.h:60
struct ConnAccount account
Account details: username, password, etc.
Definition connection.h:49
int fd
Socket file descriptor.
Definition connection.h:53
The envelope/body of an email.
Definition email.h:39
bool read
Email is read.
Definition email.h:50
struct Envelope * env
Envelope information.
Definition email.h:68
void * edata
Driver-specific data.
Definition email.h:74
int lines
How many lines in the body of this message?
Definition email.h:62
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
struct Body * body
List of MIME parts.
Definition email.h:69
bool old
Email is seen, but unread.
Definition email.h:49
void(* edata_free)(void **ptr)
Definition email.h:90
bool changed
Email has been edited.
Definition email.h:77
char * path
Path of Email (for local Mailboxes)
Definition email.h:70
bool deleted
Email is deleted.
Definition email.h:78
int index
The absolute (unsorted) message number.
Definition email.h:110
char *const real_subj
Offset of the real subject.
Definition envelope.h:71
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
A mailbox.
Definition mailbox.h:81
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition mailbox.h:83
bool append
Mailbox is opened in append mode.
Definition mailbox.h:111
int msg_count
Total number of messages.
Definition mailbox.h:90
AclFlags rights
ACL bits, see AclFlags.
Definition mailbox.h:121
struct HashTable * subj_hash
Hash Table: "Subject" -> Email.
Definition mailbox.h:126
struct Email ** emails
Array of Emails.
Definition mailbox.h:98
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:82
struct Account * account
Account that owns this Mailbox.
Definition mailbox.h:129
off_t size
Size of the Mailbox.
Definition mailbox.h:86
bool verbose
Display status messages?
Definition mailbox.h:119
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
char * path
path to temp file
Definition message.h:36
Definition mxapi.h:98
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
POP-specific Account data -.
Definition adata.h:37
size_t size
Mailbox size.
Definition adata.h:50
bool clear_cache
Clear the cache.
Definition adata.h:49
time_t check_time
Last check time.
Definition adata.h:51
unsigned int cmd_top
optional command TOP
Definition adata.h:46
char err_msg[POP_CMD_RESPONSE]
Last error message.
Definition adata.h:57
unsigned int status
Connection status.
Definition adata.h:39
struct Connection * conn
Connection to POP server.
Definition adata.h:38
struct PopCache cache[POP_CACHE_LEN]
Message cache.
Definition adata.h:58
struct BodyCache * bcache
body cache
Definition adata.h:56
unsigned int cmd_uidl
optional command UIDL
Definition adata.h:45
POP-specific email cache.
Definition private.h:67
unsigned int index
Message index.
Definition private.h:68
char * path
Filesystem path.
Definition private.h:69
POP-specific Email data -.
Definition edata.h:32
int refno
Message number on server.
Definition edata.h:34
const char * uid
UID of email.
Definition edata.h:33
Definition lib.h:66
const char * name
Store name.
Definition lib.h:67
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition url.h:69
char * user
Username.
Definition url.h:71
char * host
Host.
Definition url.h:73
char * path
Path.
Definition url.h:75
#define buf_mktemp(buf)
Definition tmp.h:33
#define mutt_file_mkstemp()
Definition tmp.h:36
struct Url * url_parse(const char *src)
Fill in Url.
Definition url.c:242
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition url.c:124
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition url.c:229
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
@ U_UNKNOWN
Url wasn't recognised.
Definition url.h:35
#define U_PATH
Path is included in URL.
Definition url.h:50
#define U_NONE
No flags are set for URL parsing.
Definition url.h:49