NeoMutt  2023-05-17-56-ga67199
Teaching an old dog new tricks
DOXYGEN
pop.c
Go to the documentation of this file.
1
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 "ncrypt/lib.h"
50#include "progress/lib.h"
51#include "question/lib.h"
52#include "adata.h"
53#include "edata.h"
54#include "hook.h"
55#include "mutt_account.h"
56#include "mutt_header.h"
57#include "mutt_logging.h"
58#include "mutt_socket.h"
59#include "mx.h"
60#ifdef ENABLE_NLS
61#include <libintl.h>
62#endif
63#ifdef USE_HCACHE
64#include "hcache/lib.h"
65#endif
66
67struct BodyCache;
68struct stat;
69
70#define HC_FNAME "neomutt" /* filename for hcache as POP lacks paths */
71#define HC_FEXT "hcache" /* extension for hcache as POP lacks paths */
72
82static const char *cache_id(const char *id)
83{
84 static char clean[128];
85 mutt_str_copy(clean, id, sizeof(clean));
86 mutt_file_sanitize_filename(clean, true);
87 return clean;
88}
89
97static int fetch_message(const char *line, void *data)
98{
99 FILE *fp = data;
100
101 fputs(line, fp);
102 if (fputc('\n', fp) == EOF)
103 return -1;
104
105 return 0;
106}
107
117static int pop_read_header(struct PopAccountData *adata, struct Email *e)
118{
119 FILE *fp = mutt_file_mkstemp();
120 if (!fp)
121 {
122 mutt_perror(_("Can't create temporary file"));
123 return -3;
124 }
125
126 int index = 0;
127 size_t length = 0;
128 char buf[1024] = { 0 };
129
130 struct PopEmailData *edata = pop_edata_get(e);
131
132 snprintf(buf, sizeof(buf), "LIST %d\r\n", edata->refno);
133 int rc = pop_query(adata, buf, sizeof(buf));
134 if (rc == 0)
135 {
136 sscanf(buf, "+OK %d %zu", &index, &length);
137
138 snprintf(buf, sizeof(buf), "TOP %d 0\r\n", edata->refno);
139 rc = pop_fetch_data(adata, buf, NULL, fetch_message, fp);
140
141 if (adata->cmd_top == 2)
142 {
143 if (rc == 0)
144 {
145 adata->cmd_top = 1;
146
147 mutt_debug(LL_DEBUG1, "set TOP capability\n");
148 }
149
150 if (rc == -2)
151 {
152 adata->cmd_top = 0;
153
154 mutt_debug(LL_DEBUG1, "unset TOP capability\n");
155 snprintf(adata->err_msg, sizeof(adata->err_msg), "%s",
156 _("Command TOP is not supported by server"));
157 }
158 }
159 }
160
161 switch (rc)
162 {
163 case 0:
164 {
165 rewind(fp);
166 e->env = mutt_rfc822_read_header(fp, e, false, false);
167 e->body->length = length - e->body->offset + 1;
168 rewind(fp);
169 while (!feof(fp))
170 {
171 e->body->length--;
172 if (!fgets(buf, sizeof(buf), fp))
173 break;
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}
192
200static int fetch_uidl(const char *line, void *data)
201{
202 struct Mailbox *m = data;
204 char *endp = NULL;
205
206 errno = 0;
207 int index = strtol(line, &endp, 10);
208 if (errno)
209 return -1;
210 while (*endp == ' ')
211 endp++;
212 line = endp;
213
214 /* uid must be at least be 1 byte */
215 if (strlen(line) == 0)
216 return -1;
217
218 int i;
219 for (i = 0; i < m->msg_count; i++)
220 {
221 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
222 if (mutt_str_equal(line, edata->uid))
223 break;
224 }
225
226 if (i == m->msg_count)
227 {
228 mutt_debug(LL_DEBUG1, "new header %d %s\n", index, line);
229
230 mx_alloc_memory(m, i);
231
232 m->msg_count++;
233 m->emails[i] = email_new();
234
235 m->emails[i]->edata = pop_edata_new(line);
237 }
238 else if (m->emails[i]->index != index - 1)
239 {
240 adata->clear_cache = true;
241 }
242
243 m->emails[i]->index = index - 1;
244
245 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
246 edata->refno = index;
247
248 return 0;
249}
250
254static int msg_cache_check(const char *id, struct BodyCache *bcache, void *data)
255{
256 struct Mailbox *m = data;
257 if (!m)
258 return -1;
259
261 if (!adata)
262 return -1;
263
264#ifdef USE_HCACHE
265 /* keep hcache file if hcache == bcache */
266 if (mutt_str_equal(HC_FNAME "." HC_FEXT, id))
267 return 0;
268#endif
269
270 for (int i = 0; i < m->msg_count; i++)
271 {
272 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
273 /* if the id we get is known for a header: done (i.e. keep in cache) */
274 if (edata->uid && mutt_str_equal(edata->uid, id))
275 return 0;
276 }
277
278 /* message not found in context -> remove it from cache
279 * return the result of bcache, so we stop upon its first error */
280 return mutt_bcache_del(bcache, cache_id(id));
281}
282
283#ifdef USE_HCACHE
287static void pop_hcache_namer(const char *path, struct Buffer *dest)
288{
289 buf_printf(dest, "%s." HC_FEXT, path);
290}
291
298static struct HeaderCache *pop_hcache_open(struct PopAccountData *adata, const char *path)
299{
300 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
301 if (!adata || !adata->conn)
302 return mutt_hcache_open(c_header_cache, path, NULL);
303
304 struct Url url = { 0 };
305 char p[1024] = { 0 };
306
307 mutt_account_tourl(&adata->conn->account, &url);
308 url.path = HC_FNAME;
309 url_tostring(&url, p, sizeof(p), U_PATH);
310 return mutt_hcache_open(c_header_cache, p, pop_hcache_namer);
311}
312#endif
313
322static int pop_fetch_headers(struct Mailbox *m)
323{
324 if (!m)
325 return -1;
326
328 struct Progress *progress = NULL;
329
330#ifdef USE_HCACHE
331 struct HeaderCache *hc = pop_hcache_open(adata, mailbox_path(m));
332#endif
333
334 adata->check_time = mutt_date_now();
335 adata->clear_cache = false;
336
337 for (int i = 0; i < m->msg_count; i++)
338 {
339 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
340 edata->refno = -1;
341 }
342
343 const int old_count = m->msg_count;
344 int rc = pop_fetch_data(adata, "UIDL\r\n", NULL, fetch_uidl, m);
345 const int new_count = m->msg_count;
346 m->msg_count = old_count;
347
348 if (adata->cmd_uidl == 2)
349 {
350 if (rc == 0)
351 {
352 adata->cmd_uidl = 1;
353
354 mutt_debug(LL_DEBUG1, "set UIDL capability\n");
355 }
356
357 if ((rc == -2) && (adata->cmd_uidl == 2))
358 {
359 adata->cmd_uidl = 0;
360
361 mutt_debug(LL_DEBUG1, "unset UIDL capability\n");
362 snprintf(adata->err_msg, sizeof(adata->err_msg), "%s",
363 _("Command UIDL is not supported by server"));
364 }
365 }
366
367 if (m->verbose)
368 {
369 progress = progress_new(_("Fetching message headers..."),
370 MUTT_PROGRESS_READ, new_count - old_count);
371 }
372
373 if (rc == 0)
374 {
375 int i, deleted;
376 for (i = 0, deleted = 0; i < old_count; i++)
377 {
378 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
379 if (edata->refno == -1)
380 {
381 m->emails[i]->deleted = true;
382 deleted++;
383 }
384 }
385 if (deleted > 0)
386 {
387 mutt_error(ngettext("%d message has been lost. Try reopening the mailbox.",
388 "%d messages have been lost. Try reopening the mailbox.", deleted),
389 deleted);
390 }
391
392 bool hcached = false;
393 for (i = old_count; i < new_count; i++)
394 {
395 if (m->verbose)
396 progress_update(progress, i + 1 - old_count, -1);
397 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
398#ifdef USE_HCACHE
399 struct HCacheEntry hce = mutt_hcache_fetch(hc, edata->uid, strlen(edata->uid), 0);
400 if (hce.email)
401 {
402 /* Detach the private data */
403 m->emails[i]->edata = NULL;
404
405 int index = m->emails[i]->index;
406 /* - POP dynamically numbers headers and relies on e->refno
407 * to map messages; so restore header and overwrite restored
408 * refno with current refno, same for index
409 * - e->data needs to a separate pointer as it's driver-specific
410 * data freed separately elsewhere
411 * (the old e->data should point inside a malloc'd block from
412 * hcache so there shouldn't be a memleak here) */
413 email_free(&m->emails[i]);
414 m->emails[i] = hce.email;
415 m->emails[i]->index = index;
416
417 /* Reattach the private data */
418 m->emails[i]->edata = edata;
420 rc = 0;
421 hcached = true;
422 }
423 else
424#endif
425 if ((rc = pop_read_header(adata, m->emails[i])) < 0)
426 break;
427#ifdef USE_HCACHE
428 else
429 {
430 mutt_hcache_store(hc, edata->uid, strlen(edata->uid), m->emails[i], 0);
431 }
432#endif
433
434 /* faked support for flags works like this:
435 * - if 'hcached' is true, we have the message in our hcache:
436 * - if we also have a body: read
437 * - if we don't have a body: old
438 * (if $mark_old is set which is maybe wrong as
439 * $mark_old should be considered for syncing the
440 * folder and not when opening it XXX)
441 * - if 'hcached' is false, we don't have the message in our hcache:
442 * - if we also have a body: read
443 * - if we don't have a body: new */
444 const bool bcached = (mutt_bcache_exists(adata->bcache, cache_id(edata->uid)) == 0);
445 m->emails[i]->old = false;
446 m->emails[i]->read = false;
447 if (hcached)
448 {
449 const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
450 if (bcached)
451 m->emails[i]->read = true;
452 else if (c_mark_old)
453 m->emails[i]->old = true;
454 }
455 else
456 {
457 if (bcached)
458 m->emails[i]->read = true;
459 }
460
461 m->msg_count++;
462 }
463 }
464 progress_free(&progress);
465
466#ifdef USE_HCACHE
468#endif
469
470 if (rc < 0)
471 {
472 for (int i = m->msg_count; i < new_count; i++)
473 email_free(&m->emails[i]);
474 return rc;
475 }
476
477 /* after putting the result into our structures,
478 * clean up cache, i.e. wipe messages deleted outside
479 * the availability of our cache */
480 const bool c_message_cache_clean = cs_subset_bool(NeoMutt->sub, "message_cache_clean");
481 if (c_message_cache_clean)
483
485 return new_count - old_count;
486}
487
492static void pop_clear_cache(struct PopAccountData *adata)
493{
494 if (!adata->clear_cache)
495 return;
496
497 mutt_debug(LL_DEBUG1, "delete cached messages\n");
498
499 for (int i = 0; i < POP_CACHE_LEN; i++)
500 {
501 if (adata->cache[i].path)
502 {
503 unlink(adata->cache[i].path);
504 FREE(&adata->cache[i].path);
505 }
506 }
507}
508
513{
514 const char *const c_pop_host = cs_subset_string(NeoMutt->sub, "pop_host");
515 if (!c_pop_host)
516 {
517 mutt_error(_("POP host is not defined"));
518 return;
519 }
520
521 char buf[1024] = { 0 };
522 char msgbuf[128] = { 0 };
523 int last = 0, msgs, bytes, rset = 0, rc;
524 struct ConnAccount cac = { { 0 } };
525
526 char *p = mutt_mem_calloc(strlen(c_pop_host) + 7, sizeof(char));
527 char *url = p;
528 if (url_check_scheme(c_pop_host) == U_UNKNOWN)
529 {
530 strcpy(url, "pop://");
531 p = strchr(url, '\0');
532 }
533 strcpy(p, c_pop_host);
534
535 rc = pop_parse_path(url, &cac);
536 FREE(&url);
537 if (rc)
538 {
539 mutt_error(_("%s is an invalid POP path"), c_pop_host);
540 return;
541 }
542
543 struct Connection *conn = mutt_conn_find(&cac);
544 if (!conn)
545 return;
546
548 adata->conn = conn;
549
550 if (pop_open_connection(adata) < 0)
551 {
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 pop_adata_free((void **) &adata);
681 return;
682
683fail:
684 mutt_error(_("Server closed connection"));
685 mutt_socket_close(conn);
686 pop_adata_free((void **) &adata);
687}
688
692static bool pop_ac_owns_path(struct Account *a, const char *path)
693{
694 struct Url *url = url_parse(path);
695 if (!url)
696 return false;
697
698 struct PopAccountData *adata = a->adata;
699 struct ConnAccount *cac = &adata->conn->account;
700
701 const bool rc = mutt_istr_equal(url->host, cac->host) &&
702 mutt_istr_equal(url->user, cac->user);
703 url_free(&url);
704 return rc;
705}
706
710static bool pop_ac_add(struct Account *a, struct Mailbox *m)
711{
712 if (a->adata)
713 return true;
714
715 struct ConnAccount cac = { { 0 } };
716 if (pop_parse_path(mailbox_path(m), &cac))
717 {
718 mutt_error(_("%s is an invalid POP path"), mailbox_path(m));
719 return false;
720 }
721
723 adata->conn = mutt_conn_new(&cac);
724 if (!adata->conn)
725 {
726 pop_adata_free((void **) &adata);
727 return false;
728 }
729 a->adata = adata;
731
732 return true;
733}
734
740static enum MxOpenReturns pop_mbox_open(struct Mailbox *m)
741{
742 if (!m->account)
743 return MX_OPEN_ERROR;
744
745 char buf[PATH_MAX] = { 0 };
746 struct ConnAccount cac = { { 0 } };
747 struct Url url = { 0 };
748
749 if (pop_parse_path(mailbox_path(m), &cac))
750 {
751 mutt_error(_("%s is an invalid POP path"), mailbox_path(m));
752 return MX_OPEN_ERROR;
753 }
754
755 mutt_account_tourl(&cac, &url);
756 url.path = NULL;
757 url_tostring(&url, buf, sizeof(buf), U_NO_FLAGS);
758
759 buf_strcpy(&m->pathbuf, buf);
761
762 struct PopAccountData *adata = m->account->adata;
763 if (!adata)
764 {
766 m->account->adata = adata;
768 }
769
770 struct Connection *conn = adata->conn;
771 if (!conn)
772 {
773 adata->conn = mutt_conn_new(&cac);
774 conn = adata->conn;
775 if (!conn)
776 return MX_OPEN_ERROR;
777 }
778
779 if (conn->fd < 0)
781
782 if (pop_open_connection(adata) < 0)
783 return MX_OPEN_ERROR;
784
785 adata->bcache = mutt_bcache_open(&cac, NULL);
786
787 /* init (hard-coded) ACL rights */
789#ifdef USE_HCACHE
790 /* flags are managed using header cache, so it only makes sense to
791 * enable them in that case */
793#endif
794
795 while (true)
796 {
797 if (pop_reconnect(m) < 0)
798 return MX_OPEN_ERROR;
799
800 m->size = adata->size;
801
802 mutt_message(_("Fetching list of messages..."));
803
804 const int rc = pop_fetch_headers(m);
805
806 if (rc >= 0)
807 return MX_OPEN_OK;
808
809 if (rc < -1)
810 return MX_OPEN_ERROR;
811 }
812}
813
817static enum MxStatus pop_mbox_check(struct Mailbox *m)
818{
819 if (!m || !m->account)
820 return MX_STATUS_ERROR;
821
823
824 const short c_pop_check_interval = cs_subset_number(NeoMutt->sub, "pop_check_interval");
825 if ((adata->check_time + c_pop_check_interval) > mutt_date_now())
826 return MX_STATUS_OK;
827
828 pop_logout(m);
829
831
832 if (pop_open_connection(adata) < 0)
833 return MX_STATUS_ERROR;
834
835 m->size = adata->size;
836
837 mutt_message(_("Checking for new messages..."));
838
839 int old_msg_count = m->msg_count;
840 int rc = pop_fetch_headers(m);
842 if (m->msg_count > old_msg_count)
844
845 if (rc < 0)
846 return MX_STATUS_ERROR;
847
848 if (rc > 0)
849 return MX_STATUS_NEW_MAIL;
850
851 return MX_STATUS_OK;
852}
853
859static enum MxStatus pop_mbox_sync(struct Mailbox *m)
860{
861 int i, j, rc = 0;
862 char buf[1024] = { 0 };
864#ifdef USE_HCACHE
865 struct HeaderCache *hc = NULL;
866#endif
867
868 adata->check_time = 0;
869
870 int num_deleted = 0;
871 for (i = 0; i < m->msg_count; i++)
872 {
873 if (m->emails[i]->deleted)
874 num_deleted++;
875 }
876
877 while (true)
878 {
879 if (pop_reconnect(m) < 0)
880 return MX_STATUS_ERROR;
881
882#ifdef USE_HCACHE
883 hc = pop_hcache_open(adata, mailbox_path(m));
884#endif
885
886 struct Progress *progress = NULL;
887 if (m->verbose)
888 {
889 progress = progress_new(_("Marking messages deleted..."),
890 MUTT_PROGRESS_WRITE, num_deleted);
891 }
892
893 for (i = 0, j = 0, rc = 0; (rc == 0) && (i < m->msg_count); i++)
894 {
895 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
896 if (m->emails[i]->deleted && (edata->refno != -1))
897 {
898 j++;
899 if (m->verbose)
900 progress_update(progress, j, -1);
901 snprintf(buf, sizeof(buf), "DELE %d\r\n", edata->refno);
902 rc = pop_query(adata, buf, sizeof(buf));
903 if (rc == 0)
904 {
905 mutt_bcache_del(adata->bcache, cache_id(edata->uid));
906#ifdef USE_HCACHE
907 mutt_hcache_delete_record(hc, edata->uid, strlen(edata->uid));
908#endif
909 }
910 }
911
912#ifdef USE_HCACHE
913 if (m->emails[i]->changed)
914 {
915 mutt_hcache_store(hc, edata->uid, strlen(edata->uid), m->emails[i], 0);
916 }
917#endif
918 }
919 progress_free(&progress);
920
921#ifdef USE_HCACHE
923#endif
924
925 if (rc == 0)
926 {
927 mutt_str_copy(buf, "QUIT\r\n", sizeof(buf));
928 rc = pop_query(adata, buf, sizeof(buf));
929 }
930
931 if (rc == 0)
932 {
933 adata->clear_cache = true;
934 pop_clear_cache(adata);
935 adata->status = POP_DISCONNECTED;
936 return MX_STATUS_OK;
937 }
938
939 if (rc == -2)
940 {
941 mutt_error("%s", adata->err_msg);
942 return MX_STATUS_ERROR;
943 }
944 }
945}
946
950static enum MxStatus pop_mbox_close(struct Mailbox *m)
951{
953 if (!adata)
954 return MX_STATUS_OK;
955
956 pop_logout(m);
957
958 if (adata->status != POP_NONE)
959 {
961 }
962
963 adata->status = POP_NONE;
964
965 adata->clear_cache = true;
967
968 mutt_bcache_close(&adata->bcache);
969
970 return MX_STATUS_OK;
971}
972
976static bool pop_msg_open(struct Mailbox *m, struct Message *msg, struct Email *e)
977{
978 char buf[1024] = { 0 };
980 struct PopEmailData *edata = pop_edata_get(e);
981 bool bcache = true;
982 bool success = false;
983 struct Buffer *path = NULL;
984
985 /* see if we already have the message in body cache */
986 msg->fp = mutt_bcache_get(adata->bcache, cache_id(edata->uid));
987 if (msg->fp)
988 return true;
989
990 /* see if we already have the message in our cache in
991 * case $message_cache_dir is unset */
992 struct PopCache *cache = &adata->cache[e->index % POP_CACHE_LEN];
993
994 if (cache->path)
995 {
996 if (cache->index == e->index)
997 {
998 /* yes, so just return a pointer to the message */
999 msg->fp = fopen(cache->path, "r");
1000 if (msg->fp)
1001 return true;
1002
1003 mutt_perror(cache->path);
1004 return false;
1005 }
1006 else
1007 {
1008 /* clear the previous entry */
1009 unlink(cache->path);
1010 FREE(&cache->path);
1011 }
1012 }
1013
1014 path = buf_pool_get();
1015
1016 while (true)
1017 {
1018 if (pop_reconnect(m) < 0)
1019 goto cleanup;
1020
1021 /* verify that massage index is correct */
1022 if (edata->refno < 0)
1023 {
1024 mutt_error(_("The message index is incorrect. Try reopening the mailbox."));
1025 goto cleanup;
1026 }
1027
1028 /* see if we can put in body cache; use our cache as fallback */
1029 msg->fp = mutt_bcache_put(adata->bcache, cache_id(edata->uid));
1030 if (!msg->fp)
1031 {
1032 /* no */
1033 bcache = false;
1035 msg->fp = mutt_file_fopen(buf_string(path), "w+");
1036 if (!msg->fp)
1037 {
1039 goto cleanup;
1040 }
1041 }
1042
1043 snprintf(buf, sizeof(buf), "RETR %d\r\n", edata->refno);
1044
1045 struct Progress *progress = progress_new(_("Fetching message..."), MUTT_PROGRESS_NET,
1046 e->body->length + e->body->offset - 1);
1047 const int rc = pop_fetch_data(adata, buf, progress, fetch_message, msg->fp);
1048 progress_free(&progress);
1049
1050 if (rc == 0)
1051 break;
1052
1053 mutt_file_fclose(&msg->fp);
1054
1055 /* if RETR failed (e.g. connection closed), be sure to remove either
1056 * the file in bcache or from POP's own cache since the next iteration
1057 * of the loop will re-attempt to put() the message */
1058 if (!bcache)
1059 unlink(buf_string(path));
1060
1061 if (rc == -2)
1062 {
1063 mutt_error("%s", adata->err_msg);
1064 goto cleanup;
1065 }
1066
1067 if (rc == -3)
1068 {
1069 mutt_error(_("Can't write message to temporary file"));
1070 goto cleanup;
1071 }
1072 }
1073
1074 /* Update the header information. Previously, we only downloaded a
1075 * portion of the headers, those required for the main display. */
1076 if (bcache)
1077 {
1078 mutt_bcache_commit(adata->bcache, cache_id(edata->uid));
1079 }
1080 else
1081 {
1082 cache->index = e->index;
1083 cache->path = buf_strdup(path);
1084 }
1085 rewind(msg->fp);
1086
1087 /* Detach the private data */
1088 e->edata = NULL;
1089
1090 /* we replace envelope, key in subj_hash has to be updated as well */
1091 if (m->subj_hash && e->env->real_subj)
1094 mutt_env_free(&e->env);
1095 e->env = mutt_rfc822_read_header(msg->fp, e, false, false);
1096 if (m->subj_hash && e->env->real_subj)
1098 mutt_label_hash_add(m, e);
1099
1100 /* Reattach the private data */
1101 e->edata = edata;
1103
1104 e->lines = 0;
1105 while (fgets(buf, sizeof(buf), msg->fp) && !feof(msg->fp))
1106 {
1107 e->lines++;
1108 }
1109
1110 e->body->length = ftello(msg->fp) - e->body->offset;
1111
1112 /* This needs to be done in case this is a multipart message */
1113 if (!WithCrypto)
1114 e->security = crypt_query(e->body);
1115
1117 rewind(msg->fp);
1118
1119 success = true;
1120
1121cleanup:
1122 buf_pool_release(&path);
1123 return success;
1124}
1125
1131static int pop_msg_close(struct Mailbox *m, struct Message *msg)
1132{
1133 return mutt_file_fclose(&msg->fp);
1134}
1135
1139static int pop_msg_save_hcache(struct Mailbox *m, struct Email *e)
1140{
1141 int rc = 0;
1142#ifdef USE_HCACHE
1143 struct PopAccountData *adata = pop_adata_get(m);
1144 struct PopEmailData *edata = e->edata;
1145 struct HeaderCache *hc = pop_hcache_open(adata, mailbox_path(m));
1146 rc = mutt_hcache_store(hc, edata->uid, strlen(edata->uid), e, 0);
1148#endif
1149
1150 return rc;
1151}
1152
1156enum MailboxType pop_path_probe(const char *path, const struct stat *st)
1157{
1158 if (mutt_istr_startswith(path, "pop://"))
1159 return MUTT_POP;
1160
1161 if (mutt_istr_startswith(path, "pops://"))
1162 return MUTT_POP;
1163
1164 return MUTT_UNKNOWN;
1165}
1166
1170static int pop_path_canon(char *buf, size_t buflen)
1171{
1172 return 0;
1173}
1174
1178static int pop_path_pretty(char *buf, size_t buflen, const char *folder)
1179{
1180 /* Succeed, but don't do anything, for now */
1181 return 0;
1182}
1183
1187static int pop_path_parent(char *buf, size_t buflen)
1188{
1189 /* Succeed, but don't do anything, for now */
1190 return 0;
1191}
1192
1196const struct MxOps MxPopOps = {
1197 // clang-format off
1198 .type = MUTT_POP,
1199 .name = "pop",
1200 .is_local = false,
1201 .ac_owns_path = pop_ac_owns_path,
1202 .ac_add = pop_ac_add,
1203 .mbox_open = pop_mbox_open,
1204 .mbox_open_append = NULL,
1205 .mbox_check = pop_mbox_check,
1206 .mbox_check_stats = NULL,
1207 .mbox_sync = pop_mbox_sync,
1208 .mbox_close = pop_mbox_close,
1209 .msg_open = pop_msg_open,
1210 .msg_open_new = NULL,
1211 .msg_commit = NULL,
1212 .msg_close = pop_msg_close,
1213 .msg_padding_size = NULL,
1214 .msg_save_hcache = pop_msg_save_hcache,
1215 .tags_edit = NULL,
1216 .tags_commit = NULL,
1217 .path_probe = pop_path_probe,
1218 .path_canon = pop_path_canon,
1219 .path_pretty = pop_path_pretty,
1220 .path_parent = pop_path_parent,
1221 .path_is_empty = NULL,
1222 // clang-format on
1223};
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:286
int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition: bcache.c:246
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:143
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition: bcache.c:328
FILE * mutt_bcache_get(struct BodyCache *bcache, const char *id)
Open a file in the Body Cache.
Definition: bcache.c:179
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:263
FILE * mutt_bcache_put(struct BodyCache *bcache, const char *id)
Create a file in the Body Cache.
Definition: bcache.c:206
void mutt_bcache_close(struct BodyCache **bcache)
Close an Email-Body Cache.
Definition: bcache.c:164
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:401
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:536
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:90
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
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
Connection Library.
Convenience wrapper for the core headers.
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition: crypt.c:677
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
Structs that make up an email.
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:150
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:665
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:254
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:287
#define mutt_error(...)
Definition: logging2.h:90
#define mutt_message(...)
Definition: logging2.h:89
#define mutt_debug(LEVEL,...)
Definition: logging2.h:87
#define mutt_perror(...)
Definition: logging2.h:91
static bool pop_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Implements MxOps::ac_add() -.
Definition: pop.c:710
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:692
const struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition: pop.c:1196
static enum MxStatus pop_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition: pop.c:817
static enum MxStatus pop_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close() -.
Definition: pop.c:950
static enum MxOpenReturns pop_mbox_open(struct Mailbox *m)
Open a Mailbox - Implements MxOps::mbox_open() -.
Definition: pop.c:740
static enum MxStatus pop_mbox_sync(struct Mailbox *m)
Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
Definition: pop.c:859
static int pop_msg_close(struct Mailbox *m, struct Message *msg)
Close an email - Implements MxOps::msg_close() -.
Definition: pop.c:1131
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:976
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:1139
static int pop_path_canon(char *buf, size_t buflen)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition: pop.c:1170
static int pop_path_parent(char *buf, size_t buflen)
Find the parent of a Mailbox path - Implements MxOps::path_parent() -.
Definition: pop.c:1187
static int pop_path_pretty(char *buf, size_t buflen, const char *folder)
Abbreviate a Mailbox path - Implements MxOps::path_pretty() -.
Definition: pop.c:1178
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox? - Implements MxOps::path_probe() -.
Definition: pop.c:1156
static int fetch_message(const char *line, void *data)
Write line to file - Implements pop_fetch_t -.
Definition: pop.c:97
static int fetch_uidl(const char *line, void *data)
Parse UIDL - Implements pop_fetch_t -.
Definition: pop.c:200
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:335
void mutt_hash_delete(struct HashTable *table, const char *strkey, const void *data)
Remove an element from a Hash Table.
Definition: hash.c:427
Header cache multiplexor.
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:616
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:489
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:379
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:695
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:513
void mutt_account_hook(const char *url)
Perform an account hook.
Definition: hook.c:847
Parse and execute user-defined hooks.
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:88
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:223
@ NT_MAILBOX_INVALID
Email list was changed.
Definition: mailbox.h:175
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:63
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:209
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:71
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
@ MUTT_POP
'POP3' Mailbox type
Definition: mailbox.h:52
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
#define MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition: mailbox.h:70
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:43
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:446
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:810
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
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:653
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:240
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
#define PATH_MAX
Definition: mutt.h:41
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:79
ConnAccount object used by POP and IMAP.
void mutt_label_hash_remove(struct Mailbox *m, struct Email *e)
Remove a message's labels from the Hash Table.
Definition: mutt_header.c:442
void mutt_label_hash_add(struct Mailbox *m, struct Email *e)
Add a message's labels to the Hash Table.
Definition: mutt_header.c:429
Representation of the email's header.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
NeoMutt Logging.
struct Connection * mutt_conn_new(const struct ConnAccount *cac)
Create a new Connection.
Definition: mutt_socket.c:48
struct Connection * mutt_conn_find(const struct ConnAccount *cac)
Find a connection from a list.
Definition: mutt_socket.c:89
NeoMutt connections.
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition: mx.c:1237
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1210
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:307
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1072
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1189
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1698
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:618
API for mailboxes.
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:41
MxOpenReturns
Return values for mbox_open()
Definition: mxapi.h:97
@ MX_OPEN_ERROR
Open failed with an error.
Definition: mxapi.h:99
@ MX_OPEN_OK
Open succeeded.
Definition: mxapi.h:98
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mxapi.h:61
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:84
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:85
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:86
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:87
API for encryption/signing of emails.
#define WithCrypto
Definition: lib.h:116
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1169
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
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
void pop_adata_free(void **ptr)
Free the private Account data - Implements Account::adata_free()
Definition: adata.c:41
Pop-specific Account data.
struct PopEmailData * pop_edata_new(const char *uid)
Create a new PopEmailData for an email.
Definition: edata.c:53
void pop_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:41
struct PopEmailData * pop_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:65
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:510
void pop_logout(struct Mailbox *m)
Logout from a POP server.
Definition: lib.c:424
int pop_reconnect(struct Mailbox *m)
Reconnect and verify indexes if connection was lost.
Definition: lib.c:607
#define pop_query(adata, buf, buflen)
Definition: private.h:109
#define POP_CACHE_LEN
Definition: private.h:39
@ POP_DISCONNECTED
Disconnected from server.
Definition: private.h:51
@ POP_NONE
No connected to server.
Definition: private.h:49
static void pop_clear_cache(struct PopAccountData *adata)
Delete all cached messages.
Definition: pop.c:492
#define HC_FNAME
Definition: pop.c:70
static const char * cache_id(const char *id)
Make a message-cache-compatible id.
Definition: pop.c:82
static struct HeaderCache * pop_hcache_open(struct PopAccountData *adata, const char *path)
Open the header cache.
Definition: pop.c:298
#define HC_FEXT
Definition: pop.c:71
static int pop_read_header(struct PopAccountData *adata, struct Email *e)
Read header.
Definition: pop.c:117
void pop_fetch_mail(void)
Fetch messages and save them in $spool_file.
Definition: pop.c:512
static int pop_fetch_headers(struct Mailbox *m)
Read headers.
Definition: pop.c:322
Progress bar.
@ MUTT_PROGRESS_NET
Progress tracks bytes, according to $net_inc
Definition: lib.h:51
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:49
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:50
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:89
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:121
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(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
GUI display the mailboxes in a side panel.
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:101
Key value store.
A group of associated Mailboxes.
Definition: account.h:37
void(* adata_free)(void **ptr)
Free the private data attached to the Account.
Definition: account.h:52
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
Local cache of email bodies.
Definition: bcache.c:51
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:34
Login details for a remote server.
Definition: connaccount.h:53
char user[128]
Username.
Definition: connaccount.h:56
char host[128]
Server to login to.
Definition: connaccount.h:54
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
int fd
Socket file descriptor.
Definition: connection.h:54
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
struct Envelope * env
Envelope information.
Definition: email.h:66
void * edata
Driver-specific data.
Definition: email.h:72
int lines
How many lines in the body of this message?
Definition: email.h:60
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct Body * body
List of MIME parts.
Definition: email.h:67
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:86
bool changed
Email has been edited.
Definition: email.h:75
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
bool deleted
Email is deleted.
Definition: email.h:76
int index
The absolute (unsorted) message number.
Definition: email.h:109
char * real_subj
Offset of the real subject.
Definition: envelope.h:71
Wrapper for Email retrieved from the header cache.
Definition: lib.h:99
struct Email * email
Retrieved email.
Definition: lib.h:102
Header cache structure.
Definition: lib.h:88
char * folder
Folder name.
Definition: lib.h:89
A mailbox.
Definition: mailbox.h:79
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:109
int msg_count
Total number of messages.
Definition: mailbox.h:88
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:117
struct HashTable * subj_hash
Hash Table: "subject" -> Email.
Definition: mailbox.h:124
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:127
off_t size
Size of the Mailbox.
Definition: mailbox.h:84
bool verbose
Display status messages?
Definition: mailbox.h:114
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
char * path
path to temp file
Definition: mxapi.h:45
Definition: mxapi.h:112
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mxapi.h:113
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
POP-specific Account data -.
Definition: adata.h:37
size_t size
Definition: adata.h:50
bool clear_cache
Definition: adata.h:49
time_t check_time
Definition: adata.h:51
unsigned int cmd_top
optional command TOP
Definition: adata.h:46
char err_msg[POP_CMD_RESPONSE]
Definition: adata.h:56
unsigned int status
Definition: adata.h:39
struct Connection * conn
Connection to POP server.
Definition: adata.h:38
struct PopCache cache[POP_CACHE_LEN]
Definition: adata.h:57
struct BodyCache * bcache
body cache
Definition: adata.h:55
unsigned int cmd_uidl
optional command UIDL
Definition: adata.h:45
POP-specific email cache.
Definition: private.h:69
unsigned int index
Definition: private.h:70
char * path
Definition: private.h:71
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
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:37
#define mutt_file_mkstemp()
Definition: tmp.h:40
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:238
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:422
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:225
#define U_NO_FLAGS
Definition: url.h:49
@ U_UNKNOWN
Url wasn't recognised.
Definition: url.h:35
#define U_PATH
Definition: url.h:50