NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
util.c
Go to the documentation of this file.
1
32#include "config.h"
33#include <ctype.h>
34#include <errno.h>
35#include <netdb.h>
36#include <netinet/in.h>
37#include <signal.h>
38#include <stdbool.h>
39#include <stdio.h>
40#include <string.h>
41#include <sys/wait.h>
42#include <time.h>
43#include <unistd.h>
44#include "private.h"
45#include "mutt/lib.h"
46#include "config/lib.h"
47#include "email/lib.h"
48#include "core/lib.h"
49#include "conn/lib.h"
50#include "lib.h"
51#include "bcache/lib.h"
52#include "question/lib.h"
53#include "adata.h"
54#include "edata.h"
55#include "mdata.h"
56#include "msn.h"
57#include "mutt_account.h"
58#include "mutt_globals.h"
59#include "options.h"
60#ifdef USE_HCACHE
61#include "hcache/lib.h"
62#endif
63
72int imap_adata_find(const char *path, struct ImapAccountData **adata,
73 struct ImapMboxData **mdata)
74{
75 struct ConnAccount cac = { { 0 } };
76 struct ImapAccountData *tmp_adata = NULL;
77 char tmp[1024] = { 0 };
78
79 if (imap_parse_path(path, &cac, tmp, sizeof(tmp)) < 0)
80 return -1;
81
82 struct Account *np = NULL;
83 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
84 {
85 if (np->type != MUTT_IMAP)
86 continue;
87
88 tmp_adata = np->adata;
89 if (!tmp_adata)
90 continue;
91 if (imap_account_match(&tmp_adata->conn->account, &cac))
92 {
93 *mdata = imap_mdata_new(tmp_adata, tmp);
94 *adata = tmp_adata;
95 return 0;
96 }
97 }
98 mutt_debug(LL_DEBUG3, "no ImapAccountData found\n");
99 return -1;
100}
101
107{
108 mutt_hash_free(&mdata->uid_hash);
109 imap_msn_free(&mdata->msn);
110 mutt_bcache_close(&mdata->bcache);
111}
112
120void imap_get_parent(const char *mbox, char delim, char *buf, size_t buflen)
121{
122 /* Make a copy of the mailbox name, but only if the pointers are different */
123 if (mbox != buf)
124 mutt_str_copy(buf, mbox, buflen);
125
126 int n = mutt_str_len(buf);
127
128 /* Let's go backwards until the next delimiter
129 *
130 * If buf[n] is a '/', the first n-- will allow us
131 * to ignore it. If it isn't, then buf looks like
132 * "/aaaaa/bbbb". There is at least one "b", so we can't skip
133 * the "/" after the 'a's.
134 *
135 * If buf == '/', then n-- => n == 0, so the loop ends
136 * immediately */
137 for (n--; (n >= 0) && (buf[n] != delim); n--)
138 ; // do nothing
139
140 /* We stopped before the beginning. There is a trailing slash. */
141 if (n > 0)
142 {
143 /* Strip the trailing delimiter. */
144 buf[n] = '\0';
145 }
146 else
147 {
148 buf[0] = (n == 0) ? delim : '\0';
149 }
150}
151
161void imap_get_parent_path(const char *path, char *buf, size_t buflen)
162{
163 struct ImapAccountData *adata = NULL;
164 struct ImapMboxData *mdata = NULL;
165 char mbox[1024] = { 0 };
166
167 if (imap_adata_find(path, &adata, &mdata) < 0)
168 {
169 mutt_str_copy(buf, path, buflen);
170 return;
171 }
172
173 /* Gets the parent mbox in mbox */
174 imap_get_parent(mdata->name, adata->delim, mbox, sizeof(mbox));
175
176 /* Returns a fully qualified IMAP url */
177 imap_qualify_path(buf, buflen, &adata->conn->account, mbox);
178 imap_mdata_free((void *) &mdata);
179}
180
188void imap_clean_path(char *path, size_t plen)
189{
190 struct ImapAccountData *adata = NULL;
191 struct ImapMboxData *mdata = NULL;
192
193 if (imap_adata_find(path, &adata, &mdata) < 0)
194 return;
195
196 /* Returns a fully qualified IMAP url */
197 imap_qualify_path(path, plen, &adata->conn->account, mdata->name);
198 imap_mdata_free((void *) &mdata);
199}
200
204static const char *imap_get_field(enum ConnAccountField field, void *gf_data)
205{
206 switch (field)
207 {
208 case MUTT_CA_LOGIN:
209 return cs_subset_string(NeoMutt->sub, "imap_login");
210 case MUTT_CA_USER:
211 return cs_subset_string(NeoMutt->sub, "imap_user");
212 case MUTT_CA_PASS:
213 return cs_subset_string(NeoMutt->sub, "imap_pass");
215 return cs_subset_string(NeoMutt->sub, "imap_oauth_refresh_command");
216 case MUTT_CA_HOST:
217 default:
218 return NULL;
219 }
220}
221
222#ifdef USE_HCACHE
231static void imap_msn_index_to_uid_seqset(struct Buffer *buf, struct ImapMboxData *mdata)
232{
233 int first = 1, state = 0;
234 unsigned int cur_uid = 0, last_uid = 0;
235 unsigned int range_begin = 0, range_end = 0;
236 const size_t max_msn = imap_msn_highest(&mdata->msn);
237
238 for (unsigned int msn = 1; msn <= max_msn + 1; msn++)
239 {
240 bool match = false;
241 if (msn <= max_msn)
242 {
243 struct Email *e_cur = imap_msn_get(&mdata->msn, msn - 1);
244 cur_uid = e_cur ? imap_edata_get(e_cur)->uid : 0;
245 if (!state || (cur_uid && ((cur_uid - 1) == last_uid)))
246 match = true;
247 last_uid = cur_uid;
248 }
249
250 if (match)
251 {
252 switch (state)
253 {
254 case 1: /* single: convert to a range */
255 state = 2;
256 /* fall through */
257 case 2: /* extend range ending */
258 range_end = cur_uid;
259 break;
260 default:
261 state = 1;
262 range_begin = cur_uid;
263 break;
264 }
265 }
266 else if (state)
267 {
268 if (first)
269 first = 0;
270 else
271 mutt_buffer_addch(buf, ',');
272
273 if (state == 1)
274 mutt_buffer_add_printf(buf, "%u", range_begin);
275 else if (state == 2)
276 mutt_buffer_add_printf(buf, "%u:%u", range_begin, range_end);
277
278 state = 1;
279 range_begin = cur_uid;
280 }
281 }
282}
283
287static void imap_hcache_namer(const char *path, struct Buffer *dest)
288{
289 mutt_buffer_printf(dest, "%s.hcache", path);
290}
291
297void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata)
298{
299 if (!adata || !mdata)
300 return;
301
302 if (mdata->hcache)
303 return;
304
305 struct HeaderCache *hc = NULL;
306 struct Buffer *mbox = mutt_buffer_pool_get();
307 struct Buffer *cachepath = mutt_buffer_pool_get();
308
309 imap_cachepath(adata->delim, mdata->name, mbox);
310
311 if (strstr(mutt_buffer_string(mbox), "/../") ||
312 mutt_str_equal(mutt_buffer_string(mbox), "..") ||
313 mutt_strn_equal(mutt_buffer_string(mbox), "../", 3))
314 {
315 goto cleanup;
316 }
317 size_t len = mutt_buffer_len(mbox);
318 if ((len > 3) && (strcmp(mutt_buffer_string(mbox) + len - 3, "/..") == 0))
319 goto cleanup;
320
321 struct Url url = { 0 };
322 mutt_account_tourl(&adata->conn->account, &url);
323 url.path = mbox->data;
324 url_tobuffer(&url, cachepath, U_PATH);
325
326 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
327 hc = mutt_hcache_open(c_header_cache, mutt_buffer_string(cachepath), imap_hcache_namer);
328
329cleanup:
331 mutt_buffer_pool_release(&cachepath);
332 mdata->hcache = hc;
333}
334
340{
341 if (!mdata->hcache)
342 return;
343
345 mdata->hcache = NULL;
346}
347
355struct Email *imap_hcache_get(struct ImapMboxData *mdata, unsigned int uid)
356{
357 if (!mdata->hcache)
358 return NULL;
359
360 char key[16] = { 0 };
361
362 sprintf(key, "/%u", uid);
363 struct HCacheEntry hce = mutt_hcache_fetch(mdata->hcache, key, mutt_str_len(key),
364 mdata->uidvalidity);
365 if (!hce.email && hce.uidvalidity)
366 {
367 mutt_debug(LL_DEBUG3, "hcache uidvalidity mismatch: %u\n", hce.uidvalidity);
368 }
369
370 return hce.email;
371}
372
380int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
381{
382 if (!mdata->hcache)
383 return -1;
384
385 char key[16] = { 0 };
386
387 sprintf(key, "/%u", imap_edata_get(e)->uid);
388 return mutt_hcache_store(mdata->hcache, key, mutt_str_len(key), e, mdata->uidvalidity);
389}
390
398int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
399{
400 if (!mdata->hcache)
401 return -1;
402
403 char key[16] = { 0 };
404
405 sprintf(key, "/%u", uid);
406 return mutt_hcache_delete_record(mdata->hcache, key, mutt_str_len(key));
407}
408
416{
417 if (!mdata->hcache)
418 return -1;
419
420 /* The seqset is likely large. Preallocate to reduce reallocs */
421 struct Buffer buf = mutt_buffer_make(8192);
422 imap_msn_index_to_uid_seqset(&buf, mdata);
423
424 int rc = mutt_hcache_store_raw(mdata->hcache, "/UIDSEQSET", 10, buf.data,
425 mutt_buffer_len(&buf) + 1);
426 mutt_debug(LL_DEBUG3, "Stored /UIDSEQSET %s\n", buf.data);
428 return rc;
429}
430
438{
439 if (!mdata->hcache)
440 return -1;
441
442 return mutt_hcache_delete_record(mdata->hcache, "/UIDSEQSET", 10);
443}
444
452{
453 if (!mdata->hcache)
454 return NULL;
455
456 char *seqset = NULL;
457 size_t dlen = 0;
458 char *hc_seqset = mutt_hcache_fetch_raw(mdata->hcache, "/UIDSEQSET", 10, &dlen);
459 if (hc_seqset)
460 {
461 seqset = mutt_strn_dup(hc_seqset, dlen);
462 mutt_hcache_free_raw(mdata->hcache, (void **) &hc_seqset);
463 }
464 mutt_debug(LL_DEBUG3, "Retrieved /UIDSEQSET %s\n", NONULL(seqset));
465
466 return seqset;
467}
468#endif
469
482int imap_parse_path(const char *path, struct ConnAccount *cac, char *mailbox, size_t mailboxlen)
483{
484 static unsigned short ImapPort = 0;
485 static unsigned short ImapsPort = 0;
486
487 if (ImapPort == 0)
488 {
489 struct servent *service = getservbyname("imap", "tcp");
490 if (service)
491 ImapPort = ntohs(service->s_port);
492 else
493 ImapPort = IMAP_PORT;
494 mutt_debug(LL_DEBUG3, "Using default IMAP port %d\n", ImapPort);
495 }
496
497 if (ImapsPort == 0)
498 {
499 struct servent *service = getservbyname("imaps", "tcp");
500 if (service)
501 ImapsPort = ntohs(service->s_port);
502 else
503 ImapsPort = IMAP_SSL_PORT;
504 mutt_debug(LL_DEBUG3, "Using default IMAPS port %d\n", ImapsPort);
505 }
506
507 /* Defaults */
508 cac->port = ImapPort;
510 cac->service = "imap";
512
513 struct Url *url = url_parse(path);
514 if (!url)
515 return -1;
516
517 if ((url->scheme != U_IMAP) && (url->scheme != U_IMAPS))
518 {
519 url_free(&url);
520 return -1;
521 }
522
523 if ((mutt_account_fromurl(cac, url) < 0) || (cac->host[0] == '\0'))
524 {
525 url_free(&url);
526 return -1;
527 }
528
529 if (url->scheme == U_IMAPS)
530 cac->flags |= MUTT_ACCT_SSL;
531
532 mutt_str_copy(mailbox, url->path, mailboxlen);
533
534 url_free(&url);
535
536 if ((cac->flags & MUTT_ACCT_SSL) && !(cac->flags & MUTT_ACCT_PORT))
537 cac->port = ImapsPort;
538
539 return 0;
540}
541
553int imap_mxcmp(const char *mx1, const char *mx2)
554{
555 char *b1 = NULL;
556 char *b2 = NULL;
557 int rc;
558
559 if (!mx1 || (*mx1 == '\0'))
560 mx1 = "INBOX";
561 if (!mx2 || (*mx2 == '\0'))
562 mx2 = "INBOX";
563 if (mutt_istr_equal(mx1, "INBOX") && mutt_istr_equal(mx2, "INBOX"))
564 {
565 return 0;
566 }
567
568 b1 = mutt_mem_malloc(strlen(mx1) + 1);
569 b2 = mutt_mem_malloc(strlen(mx2) + 1);
570
571 imap_fix_path('\0', mx1, b1, strlen(mx1) + 1);
572 imap_fix_path('\0', mx2, b2, strlen(mx2) + 1);
573
574 rc = mutt_str_cmp(b1, b2);
575 FREE(&b1);
576 FREE(&b2);
577
578 return rc;
579}
580
589void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
590{
591 struct ConnAccount cac_target = { { 0 } };
592 struct ConnAccount cac_home = { { 0 } };
593 struct Url url = { 0 };
594 const char *delim = NULL;
595 int tlen;
596 int hlen = 0;
597 bool home_match = false;
598 char target_mailbox[1024] = { 0 };
599 char home_mailbox[1024] = { 0 };
600
601 if (imap_parse_path(path, &cac_target, target_mailbox, sizeof(target_mailbox)) < 0)
602 return;
603
604 if (imap_path_probe(folder, NULL) != MUTT_IMAP)
605 goto fallback;
606
607 if (imap_parse_path(folder, &cac_home, home_mailbox, sizeof(home_mailbox)) < 0)
608 goto fallback;
609
610 tlen = mutt_str_len(target_mailbox);
611 hlen = mutt_str_len(home_mailbox);
612
613 /* check whether we can do '+' substitution */
614 if (tlen && imap_account_match(&cac_home, &cac_target) &&
615 mutt_strn_equal(home_mailbox, target_mailbox, hlen))
616 {
617 const char *const c_imap_delim_chars = cs_subset_string(NeoMutt->sub, "imap_delim_chars");
618 if (hlen == 0)
619 home_match = true;
620 else if (c_imap_delim_chars)
621 {
622 for (delim = c_imap_delim_chars; *delim != '\0'; delim++)
623 if (target_mailbox[hlen] == *delim)
624 home_match = true;
625 }
626 }
627
628 /* do the '+' substitution */
629 if (home_match)
630 {
631 *path++ = '+';
632 /* copy remaining path, skipping delimiter */
633 if (hlen == 0)
634 hlen = -1;
635 memcpy(path, target_mailbox + hlen + 1, tlen - hlen - 1);
636 path[tlen - hlen - 1] = '\0';
637 return;
638 }
639
640fallback:
641 mutt_account_tourl(&cac_target, &url);
642 url.path = target_mailbox;
643 url_tostring(&url, path, pathlen, U_NO_FLAGS);
644}
645
652enum QuadOption imap_continue(const char *msg, const char *resp)
653{
654 imap_error(msg, resp);
655 return mutt_yesorno(_("Continue?"), MUTT_NO);
656}
657
663void imap_error(const char *where, const char *msg)
664{
665 mutt_error("%s [%s]", where, msg);
666}
667
685char *imap_fix_path(char delim, const char *mailbox, char *path, size_t plen)
686{
687 int i = 0;
688 for (; mailbox && *mailbox && (i < plen - 1); i++)
689 {
690 const char *const c_imap_delim_chars = cs_subset_string(NeoMutt->sub, "imap_delim_chars");
691 if (*mailbox == delim || (!delim && strchr(NONULL(c_imap_delim_chars), *mailbox)))
692 {
693 delim = *mailbox;
694 /* Skip multiple occurrences of delim */
695 while (*mailbox && *(mailbox + 1) == delim)
696 mailbox++;
697 }
698 path[i] = *mailbox++;
699 }
700
701 /* Do not terminate with a delimiter */
702 if (i && path[i - 1] == delim)
703 i--;
704
705 /* Ensure null termination */
706 path[i] = '\0';
707 return path;
708}
709
716void imap_cachepath(char delim, const char *mailbox, struct Buffer *dest)
717{
718 const char *p = mailbox;
719 mutt_buffer_reset(dest);
720 if (!p)
721 return;
722
723 while (*p)
724 {
725 if (p[0] == delim)
726 {
727 mutt_buffer_addch(dest, '/');
728 /* simple way to avoid collisions with UIDs */
729 if ((p[1] >= '0') && (p[1] <= '9'))
730 mutt_buffer_addch(dest, '_');
731 }
732 else
733 mutt_buffer_addch(dest, *p);
734 p++;
735 }
736}
737
745int imap_get_literal_count(const char *buf, unsigned int *bytes)
746{
747 char *pc = NULL;
748 char *pn = NULL;
749
750 if (!buf || !(pc = strchr(buf, '{')))
751 return -1;
752
753 pc++;
754 pn = pc;
755 while (isdigit((unsigned char) *pc))
756 pc++;
757 *pc = '\0';
758 if (!mutt_str_atoui(pn, bytes))
759 return -1;
760
761 return 0;
762}
763
772char *imap_get_qualifier(char *buf)
773{
774 char *s = buf;
775
776 /* skip tag */
777 s = imap_next_word(s);
778 /* skip OK/NO/BAD response */
779 s = imap_next_word(s);
780
781 return s;
782}
783
789char *imap_next_word(char *s)
790{
791 bool quoted = false;
792
793 while (*s)
794 {
795 if (*s == '\\')
796 {
797 s++;
798 if (*s)
799 s++;
800 continue;
801 }
802 if (*s == '\"')
803 quoted = !quoted;
804 if (!quoted && IS_SPACE(*s))
805 break;
806 s++;
807 }
808
809 SKIPWS(s);
810 return s;
811}
812
820void imap_qualify_path(char *buf, size_t buflen, struct ConnAccount *cac, char *path)
821{
822 struct Url url = { 0 };
823 mutt_account_tourl(cac, &url);
824 url.path = path;
825 url_tostring(&url, buf, buflen, U_NO_FLAGS);
826}
827
837void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
838{
839 const char *quote = "`\"\\";
840 if (!quote_backtick)
841 quote++;
842
843 char *pt = dest;
844 const char *s = src;
845
846 *pt++ = '"';
847 /* save room for quote-chars */
848 dlen -= 3;
849
850 for (; *s && dlen; s++)
851 {
852 if (strchr(quote, *s))
853 {
854 if (dlen < 2)
855 break;
856 dlen -= 2;
857 *pt++ = '\\';
858 *pt++ = *s;
859 }
860 else
861 {
862 *pt++ = *s;
863 dlen--;
864 }
865 }
866 *pt++ = '"';
867 *pt = '\0';
868}
869
875{
876 char *d = s;
877
878 if (*s == '\"')
879 s++;
880 else
881 return;
882
883 while (*s)
884 {
885 if (*s == '\"')
886 {
887 *d = '\0';
888 return;
889 }
890 if (*s == '\\')
891 {
892 s++;
893 }
894 if (*s)
895 {
896 *d = *s;
897 d++;
898 s++;
899 }
900 }
901 *d = '\0';
902}
903
911void imap_munge_mbox_name(bool unicode, char *dest, size_t dlen, const char *src)
912{
913 char *buf = mutt_str_dup(src);
914 imap_utf_encode(unicode, &buf);
915
916 imap_quote_string(dest, dlen, buf, false);
917
918 FREE(&buf);
919}
920
928void imap_unmunge_mbox_name(bool unicode, char *s)
929{
931
932 char *buf = mutt_str_dup(s);
933 if (buf)
934 {
935 imap_utf_decode(unicode, &buf);
936 strncpy(s, buf, strlen(s));
937 }
938
939 FREE(&buf);
940}
941
946{
947 time_t now = mutt_date_epoch();
948 struct Account *np = NULL;
949 TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
950 {
951 if (np->type != MUTT_IMAP)
952 continue;
953
954 struct ImapAccountData *adata = np->adata;
955 if (!adata || !adata->mailbox)
956 continue;
957
958 const short c_imap_keepalive = cs_subset_number(NeoMutt->sub, "imap_keepalive");
959 if ((adata->state >= IMAP_AUTHENTICATED) && (now >= (adata->lastread + c_imap_keepalive)))
960 imap_check_mailbox(adata->mailbox, true);
961 }
962}
963
970{
971 struct sigaction oldalrm;
972 struct sigaction act;
973 sigset_t oldmask;
974 int rc;
975
976 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
977 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", true, NULL);
978 OptKeepQuiet = true;
979
980 sigprocmask(SIG_SETMASK, NULL, &oldmask);
981
982 sigemptyset(&act.sa_mask);
983 act.sa_handler = mutt_sig_empty_handler;
984#ifdef SA_INTERRUPT
985 act.sa_flags = SA_INTERRUPT;
986#else
987 act.sa_flags = 0;
988#endif
989
990 sigaction(SIGALRM, &act, &oldalrm);
991
992 const short c_imap_keepalive = cs_subset_number(NeoMutt->sub, "imap_keepalive");
993 alarm(c_imap_keepalive);
994 while ((waitpid(pid, &rc, 0) < 0) && (errno == EINTR))
995 {
996 alarm(0); /* cancel a possibly pending alarm */
998 alarm(c_imap_keepalive);
999 }
1000
1001 alarm(0); /* cancel a possibly pending alarm */
1002
1003 sigaction(SIGALRM, &oldalrm, NULL);
1004 sigprocmask(SIG_SETMASK, &oldmask, NULL);
1005
1006 OptKeepQuiet = false;
1007 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1008
1009 return rc;
1010}
1011
1017{
1019 struct ImapMboxData *mdata = imap_mdata_get(m);
1020 if (!adata || !adata->mailbox || (adata->mailbox != m) || !mdata)
1021 return;
1022 mdata->reopen |= IMAP_REOPEN_ALLOW;
1023}
1024
1030{
1032 struct ImapMboxData *mdata = imap_mdata_get(m);
1033 if (!adata || !adata->mailbox || (adata->mailbox != m) || !mdata)
1034 return;
1035 mdata->reopen &= ~IMAP_REOPEN_ALLOW;
1036}
1037
1044bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
1045{
1046 if (!a1 || !a2)
1047 return false;
1048 if (a1->type != a2->type)
1049 return false;
1050 if (!mutt_istr_equal(a1->host, a2->host))
1051 return false;
1052 if ((a1->port != 0) && (a2->port != 0) && (a1->port != a2->port))
1053 return false;
1054 if (a1->flags & a2->flags & MUTT_ACCT_USER)
1055 return strcmp(a1->user, a2->user) == 0;
1056
1057 const char *user = NONULL(Username);
1058
1059 const char *const c_imap_user = cs_subset_string(NeoMutt->sub, "imap_user");
1060 if ((a1->type == MUTT_ACCT_TYPE_IMAP) && c_imap_user)
1061 user = c_imap_user;
1062
1063 if (a1->flags & MUTT_ACCT_USER)
1064 return strcmp(a1->user, user) == 0;
1065 if (a2->flags & MUTT_ACCT_USER)
1066 return strcmp(a2->user, user) == 0;
1067
1068 return true;
1069}
1070
1076struct SeqsetIterator *mutt_seqset_iterator_new(const char *seqset)
1077{
1078 if (!seqset || (*seqset == '\0'))
1079 return NULL;
1080
1081 struct SeqsetIterator *iter = mutt_mem_calloc(1, sizeof(struct SeqsetIterator));
1082 iter->full_seqset = mutt_str_dup(seqset);
1083 iter->eostr = strchr(iter->full_seqset, '\0');
1084 iter->substr_cur = iter->substr_end = iter->full_seqset;
1085
1086 return iter;
1087}
1088
1097int mutt_seqset_iterator_next(struct SeqsetIterator *iter, unsigned int *next)
1098{
1099 if (!iter || !next)
1100 return -1;
1101
1102 if (iter->in_range)
1103 {
1104 if ((iter->down && (iter->range_cur == (iter->range_end - 1))) ||
1105 (!iter->down && (iter->range_cur == (iter->range_end + 1))))
1106 {
1107 iter->in_range = 0;
1108 }
1109 }
1110
1111 if (!iter->in_range)
1112 {
1113 iter->substr_cur = iter->substr_end;
1114 if (iter->substr_cur == iter->eostr)
1115 return 1;
1116
1117 iter->substr_end = strchr(iter->substr_cur, ',');
1118 if (!iter->substr_end)
1119 iter->substr_end = iter->eostr;
1120 else
1121 *(iter->substr_end++) = '\0';
1122
1123 char *range_sep = strchr(iter->substr_cur, ':');
1124 if (range_sep)
1125 *range_sep++ = '\0';
1126
1127 if (!mutt_str_atoui_full(iter->substr_cur, &iter->range_cur))
1128 return -1;
1129 if (range_sep)
1130 {
1131 if (!mutt_str_atoui_full(range_sep, &iter->range_end))
1132 return -1;
1133 }
1134 else
1135 iter->range_end = iter->range_cur;
1136
1137 iter->down = (iter->range_end < iter->range_cur);
1138 iter->in_range = 1;
1139 }
1140
1141 *next = iter->range_cur;
1142 if (iter->down)
1143 iter->range_cur--;
1144 else
1145 iter->range_cur++;
1146
1147 return 0;
1148}
1149
1155{
1156 if (!ptr || !*ptr)
1157 return;
1158
1159 struct SeqsetIterator *iter = *ptr;
1160 FREE(&iter->full_seqset);
1161 FREE(ptr);
1162}
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: atoi.c:202
Body Caching (local copies of email bodies)
void mutt_bcache_close(struct BodyCache **bcache)
Close an Email-Body Cache.
Definition: bcache.c:165
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:371
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:211
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
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.
ConnAccountField
Login credentials.
Definition: connaccount.h:33
@ MUTT_CA_OAUTH_CMD
OAuth refresh command.
Definition: connaccount.h:38
@ MUTT_CA_USER
User name.
Definition: connaccount.h:36
@ MUTT_CA_LOGIN
Login name.
Definition: connaccount.h:35
@ MUTT_CA_HOST
Server name.
Definition: connaccount.h:34
@ MUTT_CA_PASS
Password.
Definition: connaccount.h:37
#define MUTT_ACCT_SSL
Account uses SSL/TLS.
Definition: connaccount.h:47
#define MUTT_ACCT_USER
User field has been set.
Definition: connaccount.h:44
#define MUTT_ACCT_PORT
Port field has been set.
Definition: connaccount.h:43
Convenience wrapper for the core headers.
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
Structs that make up an email.
static void imap_hcache_namer(const char *path, struct Buffer *dest)
Generate a filename for the header cache - Implements hcache_namer_t -.
Definition: util.c:287
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2400
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
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:552
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:432
void * mutt_hcache_fetch_raw(struct HeaderCache *hc, const char *key, size_t keylen, size_t *dlen)
Fetch a message's header from the cache.
Definition: hcache.c:519
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:332
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:631
int mutt_hcache_store_raw(struct HeaderCache *hc, const char *key, size_t keylen, void *data, size_t dlen)
Store a key / data pair.
Definition: hcache.c:610
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:456
void mutt_hcache_free_raw(struct HeaderCache *hc, void **data)
Multiplexor for StoreOps::free.
Definition: hcache.c:538
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: adata.c:89
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:65
struct ImapMboxData * imap_mdata_new(struct ImapAccountData *adata, const char *name)
Allocate and initialise a new ImapMboxData structure.
Definition: mdata.c:73
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: mdata.c:60
void imap_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:40
#define IMAP_PORT
Default port for IMAP.
Definition: private.h:45
@ IMAP_AUTHENTICATED
Connection is authenticated.
Definition: private.h:109
#define IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition: private.h:66
void imap_utf_encode(bool unicode, char **s)
Encode email from local charset to UTF-8.
Definition: utf7.c:390
#define IMAP_SSL_PORT
Port for IMAP over SSL/TLS.
Definition: private.h:46
void imap_utf_decode(bool unicode, char **s)
Decode email from UTF-8 to local charset.
Definition: utf7.c:420
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition: imap.c:1106
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:43
void imap_msn_free(struct MSN *msn)
Free the cache.
Definition: msn.c:59
size_t imap_msn_highest(const struct MSN *msn)
Return the highest MSN in use.
Definition: msn.c:69
struct Email * imap_msn_get(const struct MSN *msn, size_t idx)
Return the Email associated with an msn.
Definition: msn.c:80
IMAP MSN helper functions.
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:451
int mutt_str_cmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:470
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:496
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:652
int mutt_account_fromurl(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
Definition: mutt_account.c:43
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.
@ MUTT_ACCT_TYPE_IMAP
Imap Account.
Definition: mutt_account.h:37
Hundreds of global variables to back the user variables.
char * Username
User's login name.
Definition: mutt_globals.h:52
Notmuch-specific Mailbox data.
Handling of global boolean variables.
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition: options.h:44
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Pop-specific Account data.
Pop-specific Email data.
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
Ask the user a question.
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
GUI display the mailboxes in a side panel.
void mutt_sig_empty_handler(int sig)
Dummy signal handler.
Definition: signal.c:57
Key value store.
#define NONULL(x)
Definition: string2.h:37
#define IS_SPACE(ch)
Definition: string2.h:38
#define SKIPWS(ch)
Definition: string2.h:46
A group of associated Mailboxes.
Definition: account.h:37
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:38
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
Login details for a remote server.
Definition: connaccount.h:53
char user[128]
Username.
Definition: connaccount.h:56
const char * service
Name of the service, e.g. "imap".
Definition: connaccount.h:61
char host[128]
Server to login to.
Definition: connaccount.h:54
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Function to get some login credentials.
Definition: connaccount.h:68
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition: connaccount.h:59
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:60
unsigned short port
Port to connect to.
Definition: connaccount.h:58
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
The envelope/body of an email.
Definition: email.h:37
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
Wrapper for Email retrieved from the header cache.
Definition: lib.h:98
uint32_t uidvalidity
IMAP-specific UIDVALIDITY.
Definition: lib.h:99
struct Email * email
Retrieved email.
Definition: lib.h:101
Header cache structure.
Definition: lib.h:87
IMAP-specific Account data -.
Definition: adata.h:40
char delim
Path delimiter.
Definition: adata.h:75
struct Mailbox * mailbox
Current selected mailbox.
Definition: adata.h:76
struct Connection * conn
Connection to IMAP server.
Definition: adata.h:41
unsigned int uid
32-bit Message UID
Definition: edata.h:44
IMAP-specific Mailbox data -.
Definition: mdata.h:39
struct HeaderCache * hcache
Email header cache.
Definition: mdata.h:62
struct BodyCache * bcache
Email body cache.
Definition: mdata.h:60
struct HashTable * uid_hash
Definition: mdata.h:58
uint32_t uidvalidity
Definition: mdata.h:50
char * name
Mailbox name.
Definition: mdata.h:40
A mailbox.
Definition: mailbox.h:79
void * mdata
Driver specific data.
Definition: mailbox.h:132
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
UID Sequence Set Iterator.
Definition: private.h:170
char * eostr
Definition: private.h:172
char * substr_end
Definition: private.h:178
unsigned int range_end
Definition: private.h:176
char * substr_cur
Definition: private.h:177
char * full_seqset
Definition: private.h:171
unsigned int range_cur
Definition: private.h:175
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * src
Raw URL string.
Definition: url.h:77
char * path
Path.
Definition: url.h:75
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:70
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234
int url_tostring(struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition: url.c:418
int url_tobuffer(struct Url *url, struct Buffer *buf, uint8_t flags)
Output the URL string for a given Url object.
Definition: url.c:353
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
#define U_NO_FLAGS
Definition: url.h:49
@ U_IMAP
Url is imap://.
Definition: url.h:39
@ U_IMAPS
Url is imaps://.
Definition: url.h:40
#define U_PATH
Definition: url.h:50
void imap_unmunge_mbox_name(bool unicode, char *s)
Remove quoting from a mailbox name.
Definition: util.c:928
int imap_parse_path(const char *path, struct ConnAccount *cac, char *mailbox, size_t mailboxlen)
Parse an IMAP mailbox name into ConnAccount, name.
Definition: util.c:482
static const char * imap_get_field(enum ConnAccountField field, void *gf_data)
Get connection login credentials - Implements ConnAccount::get_field()
Definition: util.c:204
void imap_qualify_path(char *buf, size_t buflen, struct ConnAccount *cac, char *path)
Make an absolute IMAP folder target.
Definition: util.c:820
void imap_allow_reopen(struct Mailbox *m)
Allow re-opening a folder upon expunge.
Definition: util.c:1016
void imap_disallow_reopen(struct Mailbox *m)
Disallow re-opening a folder upon expunge.
Definition: util.c:1029
int imap_get_literal_count(const char *buf, unsigned int *bytes)
Write number of bytes in an IMAP literal into bytes.
Definition: util.c:745
int imap_hcache_store_uid_seqset(struct ImapMboxData *mdata)
Store a UID Sequence Set in the header cache.
Definition: util.c:415
int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
Add an entry to the header cache.
Definition: util.c:380
void imap_mdata_cache_reset(struct ImapMboxData *mdata)
Release and clear cache data of ImapMboxData structure.
Definition: util.c:106
void imap_get_parent(const char *mbox, char delim, char *buf, size_t buflen)
Get an IMAP folder's parent.
Definition: util.c:120
struct SeqsetIterator * mutt_seqset_iterator_new(const char *seqset)
Create a new Sequence Set Iterator.
Definition: util.c:1076
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
Quote string according to IMAP rules.
Definition: util.c:837
int imap_wait_keepalive(pid_t pid)
Wait for a process to change state.
Definition: util.c:969
char * imap_hcache_get_uid_seqset(struct ImapMboxData *mdata)
Get a UID Sequence Set from the header cache.
Definition: util.c:451
enum QuadOption imap_continue(const char *msg, const char *resp)
Display a message and ask the user if they want to go on.
Definition: util.c:652
void imap_unquote_string(char *s)
Equally stupid unquoting routine.
Definition: util.c:874
struct Email * imap_hcache_get(struct ImapMboxData *mdata, unsigned int uid)
Get a header cache entry by its UID.
Definition: util.c:355
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:161
int mutt_seqset_iterator_next(struct SeqsetIterator *iter, unsigned int *next)
Get the next UID from a Sequence Set.
Definition: util.c:1097
void imap_clean_path(char *path, size_t plen)
Cleans an IMAP path using imap_fix_path.
Definition: util.c:188
void mutt_seqset_iterator_free(struct SeqsetIterator **ptr)
Free a Sequence Set Iterator.
Definition: util.c:1154
char * imap_fix_path(char delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition: util.c:685
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:553
void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
Prettify an IMAP mailbox name.
Definition: util.c:589
void imap_cachepath(char delim, const char *mailbox, struct Buffer *dest)
Generate a cache path for a mailbox.
Definition: util.c:716
void imap_keepalive(void)
Poll the current folder to keep the connection alive.
Definition: util.c:945
void imap_error(const char *where, const char *msg)
Show an error and abort.
Definition: util.c:663
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition: util.c:339
int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
Delete an item from the header cache.
Definition: util.c:398
int imap_hcache_clear_uid_seqset(struct ImapMboxData *mdata)
Delete a UID Sequence Set from the header cache.
Definition: util.c:437
int imap_adata_find(const char *path, struct ImapAccountData **adata, struct ImapMboxData **mdata)
Find the Account data for this path.
Definition: util.c:72
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition: util.c:1044
void imap_munge_mbox_name(bool unicode, char *dest, size_t dlen, const char *src)
Quote awkward characters in a mailbox name.
Definition: util.c:911
void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata)
Open a header cache.
Definition: util.c:297
static void imap_msn_index_to_uid_seqset(struct Buffer *buf, struct ImapMboxData *mdata)
Convert MSN index of UIDs to Seqset.
Definition: util.c:231
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:789
char * imap_get_qualifier(char *buf)
Get the qualifier from a tagged response.
Definition: util.c:772