NeoMutt  2025-12-11-276-g10b23b
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 "adata.h"
54#include "edata.h"
55#include "mutt_logging.h"
56#include "mutt_socket.h"
57#include "mx.h"
58#ifdef ENABLE_NLS
59#include <libintl.h>
60#endif
61#ifdef USE_HCACHE
62#include "hcache/lib.h"
63#endif
64
65struct BodyCache;
66struct stat;
67
68#define HC_FNAME "neomutt" /* filename for hcache as POP lacks paths */
69#define HC_FEXT "hcache" /* extension for hcache as POP lacks paths */
70
80static const char *cache_id(const char *id)
81{
82 static char clean[128];
83 mutt_str_copy(clean, id, sizeof(clean));
84 mutt_file_sanitize_filename(clean, true);
85 return clean;
86}
87
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 pop_bcache_delete(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 hcache_open(c_header_cache, path, NULL, true);
303
304 struct Url url = { 0 };
305 char p[1024] = { 0 };
306
307 account_to_url(&adata->conn->account, &url);
308 url.path = HC_FNAME;
309 url_tostring(&url, p, sizeof(p), U_PATH);
310 return hcache_open(c_header_cache, p, pop_hcache_namer, true);
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(MUTT_PROGRESS_READ, new_count - old_count);
370 progress_set_message(progress, _("Fetching message headers..."));
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 progress_update(progress, i + 1 - old_count, -1);
396 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
397#ifdef USE_HCACHE
398 struct HCacheEntry hce = hcache_fetch_email(hc, edata->uid, strlen(edata->uid), 0);
399 if (hce.email)
400 {
401 /* Detach the private data */
402 m->emails[i]->edata = NULL;
403
404 int index = m->emails[i]->index;
405 /* - POP dynamically numbers headers and relies on e->refno
406 * to map messages; so restore header and overwrite restored
407 * refno with current refno, same for index
408 * - e->data needs to a separate pointer as it's driver-specific
409 * data freed separately elsewhere
410 * (the old e->data should point inside a malloc'd block from
411 * hcache so there shouldn't be a memleak here) */
412 email_free(&m->emails[i]);
413 m->emails[i] = hce.email;
414 m->emails[i]->index = index;
415
416 /* Reattach the private data */
417 m->emails[i]->edata = edata;
419 rc = 0;
420 hcached = true;
421 }
422 else
423#endif
424 if ((rc = pop_read_header(adata, m->emails[i])) < 0)
425 break;
426#ifdef USE_HCACHE
427 else
428 {
429 hcache_store_email(hc, edata->uid, strlen(edata->uid), m->emails[i], 0);
430 }
431#endif
432
433 /* faked support for flags works like this:
434 * - if 'hcached' is true, we have the message in our hcache:
435 * - if we also have a body: read
436 * - if we don't have a body: old
437 * (if $mark_old is set which is maybe wrong as
438 * $mark_old should be considered for syncing the
439 * folder and not when opening it XXX)
440 * - if 'hcached' is false, we don't have the message in our hcache:
441 * - if we also have a body: read
442 * - if we don't have a body: new */
443 const bool bcached = (mutt_bcache_exists(adata->bcache, cache_id(edata->uid)) == 0);
444 m->emails[i]->old = false;
445 m->emails[i]->read = false;
446 if (hcached)
447 {
448 const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
449 if (bcached)
450 m->emails[i]->read = true;
451 else if (c_mark_old)
452 m->emails[i]->old = true;
453 }
454 else
455 {
456 if (bcached)
457 m->emails[i]->read = true;
458 }
459
460 m->msg_count++;
461 }
462 }
463 progress_free(&progress);
464
465#ifdef USE_HCACHE
466 hcache_close(&hc);
467#endif
468
469 if (rc < 0)
470 {
471 for (int i = m->msg_count; i < new_count; i++)
472 email_free(&m->emails[i]);
473 return rc;
474 }
475
476 /* after putting the result into our structures,
477 * clean up cache, i.e. wipe messages deleted outside
478 * the availability of our cache */
479 const bool c_message_cache_clean = cs_subset_bool(NeoMutt->sub, "message_cache_clean");
480 if (c_message_cache_clean)
482
484 return new_count - old_count;
485}
486
491static void pop_clear_cache(struct PopAccountData *adata)
492{
493 if (!adata->clear_cache)
494 return;
495
496 mutt_debug(LL_DEBUG1, "delete cached messages\n");
497
498 for (int i = 0; i < POP_CACHE_LEN; i++)
499 {
500 if (adata->cache[i].path)
501 {
502 unlink(adata->cache[i].path);
503 FREE(&adata->cache[i].path);
504 }
505 }
506}
507
512{
513 const char *const c_pop_host = cs_subset_string(NeoMutt->sub, "pop_host");
514 if (!c_pop_host)
515 {
516 mutt_error(_("POP host is not defined"));
517 return;
518 }
519
520 char buf[1024] = { 0 };
521 char msgbuf[128] = { 0 };
522 int last = 0, msgs = 0, bytes = 0, rset = 0, rc;
523 struct ConnAccount cac = { { 0 } };
524
525 char *p = MUTT_MEM_CALLOC(strlen(c_pop_host) + 7, char);
526 char *url = p;
527 if (url_check_scheme(c_pop_host) == U_UNKNOWN)
528 {
529 strcpy(url, "pop://");
530 p = strchr(url, '\0');
531 }
532 strcpy(p, c_pop_host);
533
534 rc = pop_parse_path(url, &cac);
535 FREE(&url);
536 if (rc)
537 {
538 mutt_error(_("%s is an invalid POP path"), c_pop_host);
539 return;
540 }
541
542 struct Connection *conn = mutt_conn_find(&cac);
543 if (!conn)
544 return;
545
547 adata->conn = conn;
548
549 if (pop_open_connection(adata) < 0)
550 {
551 pop_adata_free((void **) &adata);
552 return;
553 }
554
555 mutt_message(_("Checking for new messages..."));
556
557 /* find out how many messages are in the mailbox. */
558 mutt_str_copy(buf, "STAT\r\n", sizeof(buf));
559 rc = pop_query(adata, buf, sizeof(buf));
560 if (rc == -1)
561 goto fail;
562 if (rc == -2)
563 {
564 mutt_error("%s", adata->err_msg);
565 goto finish;
566 }
567
568 sscanf(buf, "+OK %d %d", &msgs, &bytes);
569
570 /* only get unread messages */
571 const bool c_pop_last = cs_subset_bool(NeoMutt->sub, "pop_last");
572 if ((msgs > 0) && c_pop_last)
573 {
574 mutt_str_copy(buf, "LAST\r\n", sizeof(buf));
575 rc = pop_query(adata, buf, sizeof(buf));
576 if (rc == -1)
577 goto fail;
578 if (rc == 0)
579 sscanf(buf, "+OK %d", &last);
580 }
581
582 if (msgs <= last)
583 {
584 mutt_message(_("No new mail in POP mailbox"));
585 goto finish;
586 }
587
588 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
589 struct Mailbox *m_spool = mx_path_resolve(c_spool_file);
590
591 if (!mx_mbox_open(m_spool, MUTT_OPEN_NO_FLAGS))
592 {
593 mailbox_free(&m_spool);
594 goto finish;
595 }
596 bool old_append = m_spool->append;
597 m_spool->append = true;
598
599 enum QuadOption delanswer = query_quadoption(_("Delete messages from server?"),
600 NeoMutt->sub, "pop_delete");
601
602 snprintf(msgbuf, sizeof(msgbuf),
603 ngettext("Reading new messages (%d byte)...",
604 "Reading new messages (%d bytes)...", bytes),
605 bytes);
606 mutt_message("%s", msgbuf);
607
608 for (int i = last + 1; i <= msgs; i++)
609 {
610 struct Message *msg = mx_msg_open_new(m_spool, NULL, MUTT_ADD_FROM);
611 if (msg)
612 {
613 snprintf(buf, sizeof(buf), "RETR %d\r\n", i);
614 rc = pop_fetch_data(adata, buf, NULL, fetch_message, msg->fp);
615 if (rc == -3)
616 rset = 1;
617
618 if ((rc == 0) && (mx_msg_commit(m_spool, msg) != 0))
619 {
620 rset = 1;
621 rc = -3;
622 }
623
624 mx_msg_close(m_spool, &msg);
625 }
626 else
627 {
628 rc = -3;
629 }
630
631 if ((rc == 0) && (delanswer == MUTT_YES))
632 {
633 /* delete the message on the server */
634 snprintf(buf, sizeof(buf), "DELE %d\r\n", i);
635 rc = pop_query(adata, buf, sizeof(buf));
636 }
637
638 if (rc == -1)
639 {
640 m_spool->append = old_append;
641 mx_mbox_close(m_spool);
642 goto fail;
643 }
644 if (rc == -2)
645 {
646 mutt_error("%s", adata->err_msg);
647 break;
648 }
649 if (rc == -3)
650 {
651 mutt_error(_("Error while writing mailbox"));
652 break;
653 }
654
655 /* L10N: The plural is picked by the second numerical argument, i.e.
656 the %d right before 'messages', i.e. the total number of messages. */
657 mutt_message(ngettext("%s [%d of %d message read]",
658 "%s [%d of %d messages read]", msgs - last),
659 msgbuf, i - last, msgs - last);
660 }
661
662 m_spool->append = old_append;
663 mx_mbox_close(m_spool);
664
665 if (rset)
666 {
667 /* make sure no messages get deleted */
668 mutt_str_copy(buf, "RSET\r\n", sizeof(buf));
669 if (pop_query(adata, buf, sizeof(buf)) == -1)
670 goto fail;
671 }
672
673finish:
674 /* exit gracefully */
675 mutt_str_copy(buf, "QUIT\r\n", sizeof(buf));
676 if (pop_query(adata, buf, sizeof(buf)) == -1)
677 goto fail;
678 mutt_socket_close(conn);
679 pop_adata_free((void **) &adata);
680 return;
681
682fail:
683 mutt_error(_("Server closed connection"));
684 mutt_socket_close(conn);
685 pop_adata_free((void **) &adata);
686}
687
691static bool pop_ac_owns_path(struct Account *a, const char *path)
692{
693 struct Url *url = url_parse(path);
694 if (!url)
695 return false;
696
697 struct PopAccountData *adata = a->adata;
698 struct ConnAccount *cac = &adata->conn->account;
699
700 const bool rc = mutt_istr_equal(url->host, cac->host) &&
701 mutt_istr_equal(url->user, cac->user);
702 url_free(&url);
703 return rc;
704}
705
709static bool pop_ac_add(struct Account *a, struct Mailbox *m)
710{
711 if (a->adata)
712 return true;
713
714 struct ConnAccount cac = { { 0 } };
715 if (pop_parse_path(mailbox_path(m), &cac))
716 {
717 mutt_error(_("%s is an invalid POP path"), mailbox_path(m));
718 return false;
719 }
720
722 adata->conn = mutt_conn_new(&cac);
723 if (!adata->conn)
724 {
725 pop_adata_free((void **) &adata);
726 return false;
727 }
728 a->adata = adata;
730
731 return true;
732}
733
739static enum MxOpenReturns pop_mbox_open(struct Mailbox *m)
740{
741 if (!m->account)
742 return MX_OPEN_ERROR;
743
744 char buf[PATH_MAX] = { 0 };
745 struct ConnAccount cac = { { 0 } };
746 struct Url url = { 0 };
747
748 if (pop_parse_path(mailbox_path(m), &cac))
749 {
750 mutt_error(_("%s is an invalid POP path"), mailbox_path(m));
751 return MX_OPEN_ERROR;
752 }
753
754 account_to_url(&cac, &url);
755 url.path = NULL;
756 url_tostring(&url, buf, sizeof(buf), U_NO_FLAGS);
757
758 buf_strcpy(&m->pathbuf, buf);
760
761 struct PopAccountData *adata = m->account->adata;
762 if (!adata)
763 {
765 m->account->adata = adata;
767 }
768
769 struct Connection *conn = adata->conn;
770 if (!conn)
771 {
772 adata->conn = mutt_conn_new(&cac);
773 conn = adata->conn;
774 if (!conn)
775 return MX_OPEN_ERROR;
776 }
777
778 if (conn->fd < 0)
780
781 if (pop_open_connection(adata) < 0)
782 return MX_OPEN_ERROR;
783
784 adata->bcache = mutt_bcache_open(&cac, NULL);
785
786 /* init (hard-coded) ACL rights */
788#ifdef USE_HCACHE
789 /* flags are managed using header cache, so it only makes sense to
790 * enable them in that case */
792#endif
793
794 while (true)
795 {
796 if (pop_reconnect(m) < 0)
797 return MX_OPEN_ERROR;
798
799 m->size = adata->size;
800
801 mutt_message(_("Fetching list of messages..."));
802
803 const int rc = pop_fetch_headers(m);
804
805 if (rc >= 0)
806 return MX_OPEN_OK;
807
808 if (rc < -1)
809 return MX_OPEN_ERROR;
810 }
811}
812
816static enum MxStatus pop_mbox_check(struct Mailbox *m)
817{
818 if (!m || !m->account)
819 return MX_STATUS_ERROR;
820
822
823 const short c_pop_check_interval = cs_subset_number(NeoMutt->sub, "pop_check_interval");
824 if ((adata->check_time + c_pop_check_interval) > mutt_date_now())
825 return MX_STATUS_OK;
826
827 pop_logout(m);
828
830
831 if (pop_open_connection(adata) < 0)
832 return MX_STATUS_ERROR;
833
834 m->size = adata->size;
835
836 mutt_message(_("Checking for new messages..."));
837
838 int old_msg_count = m->msg_count;
839 int rc = pop_fetch_headers(m);
841 if (m->msg_count > old_msg_count)
843
844 if (rc < 0)
845 return MX_STATUS_ERROR;
846
847 if (rc > 0)
848 return MX_STATUS_NEW_MAIL;
849
850 return MX_STATUS_OK;
851}
852
858static enum MxStatus pop_mbox_sync(struct Mailbox *m)
859{
860 int i, j, rc = 0;
861 char buf[1024] = { 0 };
863#ifdef USE_HCACHE
864 struct HeaderCache *hc = NULL;
865#endif
866
867 adata->check_time = 0;
868
869 int num_deleted = 0;
870 for (i = 0; i < m->msg_count; i++)
871 {
872 if (m->emails[i]->deleted)
873 num_deleted++;
874 }
875
876 while (true)
877 {
878 if (pop_reconnect(m) < 0)
879 return MX_STATUS_ERROR;
880
881#ifdef USE_HCACHE
882 hc = pop_hcache_open(adata, mailbox_path(m));
883#endif
884
885 struct Progress *progress = NULL;
886 if (m->verbose)
887 {
888 progress = progress_new(MUTT_PROGRESS_WRITE, num_deleted);
889 progress_set_message(progress, _("Marking messages deleted..."));
890 }
891
892 for (i = 0, j = 0, rc = 0; (rc == 0) && (i < m->msg_count); i++)
893 {
894 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
895 if (m->emails[i]->deleted && (edata->refno != -1))
896 {
897 j++;
898 progress_update(progress, j, -1);
899 snprintf(buf, sizeof(buf), "DELE %d\r\n", edata->refno);
900 rc = pop_query(adata, buf, sizeof(buf));
901 if (rc == 0)
902 {
903 mutt_bcache_del(adata->bcache, cache_id(edata->uid));
904#ifdef USE_HCACHE
905 hcache_delete_email(hc, edata->uid, strlen(edata->uid));
906#endif
907 }
908 }
909
910#ifdef USE_HCACHE
911 if (m->emails[i]->changed)
912 {
913 hcache_store_email(hc, edata->uid, strlen(edata->uid), m->emails[i], 0);
914 }
915#endif
916 }
917 progress_free(&progress);
918
919#ifdef USE_HCACHE
920 hcache_close(&hc);
921#endif
922
923 if (rc == 0)
924 {
925 mutt_str_copy(buf, "QUIT\r\n", sizeof(buf));
926 rc = pop_query(adata, buf, sizeof(buf));
927 }
928
929 if (rc == 0)
930 {
931 adata->clear_cache = true;
932 pop_clear_cache(adata);
933 adata->status = POP_DISCONNECTED;
934 return MX_STATUS_OK;
935 }
936
937 if (rc == -2)
938 {
939 mutt_error("%s", adata->err_msg);
940 return MX_STATUS_ERROR;
941 }
942 }
943}
944
948static enum MxStatus pop_mbox_close(struct Mailbox *m)
949{
951 if (!adata)
952 return MX_STATUS_OK;
953
954 pop_logout(m);
955
956 if (adata->status != POP_NONE)
957 {
959 }
960
961 adata->status = POP_NONE;
962
963 adata->clear_cache = true;
965
966 mutt_bcache_close(&adata->bcache);
967
968 return MX_STATUS_OK;
969}
970
974static bool pop_msg_open(struct Mailbox *m, struct Message *msg, struct Email *e)
975{
976 char buf[1024] = { 0 };
978 struct PopEmailData *edata = pop_edata_get(e);
979 bool bcache = true;
980 bool success = false;
981 struct Buffer *path = NULL;
982
983 /* see if we already have the message in body cache */
984 msg->fp = mutt_bcache_get(adata->bcache, cache_id(edata->uid));
985 if (msg->fp)
986 return true;
987
988 /* see if we already have the message in our cache in
989 * case $message_cache_dir is unset */
990 struct PopCache *cache = &adata->cache[e->index % POP_CACHE_LEN];
991
992 if (cache->path)
993 {
994 if (cache->index == e->index)
995 {
996 /* yes, so just return a pointer to the message */
997 msg->fp = mutt_file_fopen(cache->path, "r");
998 if (msg->fp)
999 return true;
1000
1001 mutt_perror("%s", cache->path);
1002 return false;
1003 }
1004 else
1005 {
1006 /* clear the previous entry */
1007 unlink(cache->path);
1008 FREE(&cache->path);
1009 }
1010 }
1011
1012 path = buf_pool_get();
1013
1014 while (true)
1015 {
1016 if (pop_reconnect(m) < 0)
1017 goto cleanup;
1018
1019 /* verify that massage index is correct */
1020 if (edata->refno < 0)
1021 {
1022 mutt_error(_("The message index is incorrect. Try reopening the mailbox."));
1023 goto cleanup;
1024 }
1025
1026 /* see if we can put in body cache; use our cache as fallback */
1027 msg->fp = mutt_bcache_put(adata->bcache, cache_id(edata->uid));
1028 if (!msg->fp)
1029 {
1030 /* no */
1031 bcache = false;
1033 msg->fp = mutt_file_fopen(buf_string(path), "w+");
1034 if (!msg->fp)
1035 {
1036 mutt_perror("%s", buf_string(path));
1037 goto cleanup;
1038 }
1039 }
1040
1041 snprintf(buf, sizeof(buf), "RETR %d\r\n", edata->refno);
1042
1043 struct Progress *progress = progress_new(MUTT_PROGRESS_NET,
1044 e->body->length + e->body->offset - 1);
1045 progress_set_message(progress, _("Fetching message..."));
1046 const int rc = pop_fetch_data(adata, buf, progress, fetch_message, msg->fp);
1047 progress_free(&progress);
1048
1049 if (rc == 0)
1050 break;
1051
1052 mutt_file_fclose(&msg->fp);
1053
1054 /* if RETR failed (e.g. connection closed), be sure to remove either
1055 * the file in bcache or from POP's own cache since the next iteration
1056 * of the loop will re-attempt to put() the message */
1057 if (!bcache)
1058 unlink(buf_string(path));
1059
1060 if (rc == -2)
1061 {
1062 mutt_error("%s", adata->err_msg);
1063 goto cleanup;
1064 }
1065
1066 if (rc == -3)
1067 {
1068 mutt_error(_("Can't write message to temporary file"));
1069 goto cleanup;
1070 }
1071 }
1072
1073 /* Update the header information. Previously, we only downloaded a
1074 * portion of the headers, those required for the main display. */
1075 if (bcache)
1076 {
1077 mutt_bcache_commit(adata->bcache, cache_id(edata->uid));
1078 }
1079 else
1080 {
1081 cache->index = e->index;
1082 cache->path = buf_strdup(path);
1083 }
1084 rewind(msg->fp);
1085
1086 /* Detach the private data */
1087 e->edata = NULL;
1088
1089 /* we replace envelope, key in subj_hash has to be updated as well */
1090 if (m->subj_hash && e->env->real_subj)
1093 mutt_env_free(&e->env);
1094 e->env = mutt_rfc822_read_header(msg->fp, e, false, false);
1095 if (m->subj_hash && e->env->real_subj)
1097 mutt_label_hash_add(m, e);
1098
1099 /* Reattach the private data */
1100 e->edata = edata;
1102
1103 e->lines = 0;
1104 while (fgets(buf, sizeof(buf), msg->fp) && !feof(msg->fp))
1105 {
1106 e->lines++;
1107 }
1108
1109 e->body->length = ftello(msg->fp) - e->body->offset;
1110
1111 /* This needs to be done in case this is a multipart message */
1112 if (!WithCrypto)
1113 e->security = crypt_query(e->body);
1114
1116 rewind(msg->fp);
1117
1118 success = true;
1119
1120cleanup:
1121 buf_pool_release(&path);
1122 return success;
1123}
1124
1130static int pop_msg_close(struct Mailbox *m, struct Message *msg)
1131{
1132 return mutt_file_fclose(&msg->fp);
1133}
1134
1138static int pop_msg_save_hcache(struct Mailbox *m, struct Email *e)
1139{
1140 int rc = 0;
1141#ifdef USE_HCACHE
1142 struct PopAccountData *adata = pop_adata_get(m);
1143 struct PopEmailData *edata = e->edata;
1144 struct HeaderCache *hc = pop_hcache_open(adata, mailbox_path(m));
1145 rc = hcache_store_email(hc, edata->uid, strlen(edata->uid), e, 0);
1146 hcache_close(&hc);
1147#endif
1148
1149 return rc;
1150}
1151
1155enum MailboxType pop_path_probe(const char *path, const struct stat *st)
1156{
1157 if (mutt_istr_startswith(path, "pop://"))
1158 return MUTT_POP;
1159
1160 if (mutt_istr_startswith(path, "pops://"))
1161 return MUTT_POP;
1162
1163 return MUTT_UNKNOWN;
1164}
1165
1169static int pop_path_canon(struct Buffer *path)
1170{
1171 return 0;
1172}
1173
1177const struct MxOps MxPopOps = {
1178 // clang-format off
1179 .type = MUTT_POP,
1180 .name = "pop",
1181 .is_local = false,
1182 .ac_owns_path = pop_ac_owns_path,
1183 .ac_add = pop_ac_add,
1184 .mbox_open = pop_mbox_open,
1185 .mbox_open_append = NULL,
1186 .mbox_check = pop_mbox_check,
1187 .mbox_check_stats = NULL,
1188 .mbox_sync = pop_mbox_sync,
1189 .mbox_close = pop_mbox_close,
1190 .msg_open = pop_msg_open,
1191 .msg_open_new = NULL,
1192 .msg_commit = NULL,
1193 .msg_close = pop_msg_close,
1194 .msg_padding_size = NULL,
1195 .msg_save_hcache = pop_msg_save_hcache,
1196 .tags_edit = NULL,
1197 .tags_commit = NULL,
1198 .path_probe = pop_path_probe,
1199 .path_canon = pop_path_canon,
1200 .path_is_empty = NULL,
1201 // clang-format on
1202};
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:292
int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition bcache.c:252
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:334
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:269
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:179
#define MUTT_ACL_DELETE
Delete a message.
Definition mailbox.h:62
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:213
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition mailbox.h:70
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
#define MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition mailbox.h:69
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition crypt.c:687
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:1210
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:586
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
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:254
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 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: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:709
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:691
const struct MxOps MxPopOps
POP Mailbox - Implements MxOps -.
Definition pop.c:1177
static enum MxStatus pop_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition pop.c:816
static enum MxStatus pop_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close() -.
Definition pop.c:948
static enum MxOpenReturns pop_mbox_open(struct Mailbox *m)
Open a Mailbox - Implements MxOps::mbox_open() -.
Definition pop.c:739
static enum MxStatus pop_mbox_sync(struct Mailbox *m)
Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
Definition pop.c:858
static int pop_msg_close(struct Mailbox *m, struct Message *msg)
Close an email - Implements MxOps::msg_close() -.
Definition pop.c:1130
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:974
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:1138
static int pop_path_canon(struct Buffer *path)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition pop.c:1169
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox?
Definition pop.c:1155
static int fetch_message(const char *line, void *data)
Parse a Message response - Implements pop_fetch_t -.
Definition pop.c:97
static int fetch_uidl(const char *line, void *data)
Parse UIDL response - 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: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:476
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition hcache.c:744
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition hcache.c:547
struct HCacheEntry hcache_fetch_email(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition hcache.c:567
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:675
Header cache multiplexor.
void exec_account_hook(const char *url)
Perform an account hook.
Definition exec.c:323
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
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
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:674
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
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:583
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:48
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.
#define MUTT_ADD_FROM
add a From_ line
Definition mx.h:39
MxOpenReturns
Return values for mbox_open()
Definition mxapi.h:72
@ MX_OPEN_ERROR
Open failed with an error.
Definition mxapi.h:74
@ MX_OPEN_OK
Open succeeded.
Definition mxapi.h:73
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition mxapi.h:39
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h:59
@ MX_STATUS_ERROR
An error occurred.
Definition mxapi.h:60
@ MX_STATUS_OK
No changes.
Definition mxapi.h:61
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:62
API for encryption/signing of emails.
#define WithCrypto
Definition lib.h:124
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: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:608
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:491
#define HC_FNAME
Definition pop.c:68
static const char * cache_id(const char *id)
Make a message-cache-compatible id.
Definition pop.c:80
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:69
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:511
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: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:378
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition socket.c:100
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: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: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:78
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition mailbox.h:80
bool append
Mailbox is opened in append mode.
Definition mailbox.h:108
int msg_count
Total number of messages.
Definition mailbox.h:87
AclFlags rights
ACL bits, see AclFlags.
Definition mailbox.h:118
struct HashTable * subj_hash
Hash Table: "subject" -> Email.
Definition mailbox.h:123
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:79
struct Account * account
Account that owns this Mailbox.
Definition mailbox.h:126
off_t size
Size of the Mailbox.
Definition mailbox.h:83
bool verbose
Display status messages?
Definition mailbox.h:116
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:87
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
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:239
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:226
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:423
#define U_NO_FLAGS
No flags are set for URL parsing.
Definition url.h:49
@ U_UNKNOWN
Url wasn't recognised.
Definition url.h:35
#define U_PATH
Path is included in URL.
Definition url.h:50