NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
util.c
Go to the documentation of this file.
1
28
34
35#include "config.h"
36#include <arpa/inet.h>
37#include <errno.h>
38#include <netdb.h>
39#include <signal.h>
40#include <stdbool.h>
41#include <stdio.h>
42#include <string.h>
43#include <sys/types.h>
44#include <sys/wait.h>
45#include <unistd.h>
46#include "private.h"
47#include "mutt/lib.h"
48#include "config/lib.h"
49#include "email/lib.h"
50#include "core/lib.h"
51#include "conn/lib.h"
52#include "lib.h"
53#include "bcache/lib.h"
54#include "question/lib.h"
55#include "store/lib.h"
56#include "adata.h"
57#include "edata.h"
58#include "globals.h"
59#include "mdata.h"
60#include "msn.h"
61#ifdef USE_HCACHE
62#include "hcache/lib.h"
63#endif
64
73int imap_adata_find(const char *path, struct ImapAccountData **adata,
74 struct ImapMboxData **mdata)
75{
76 struct ConnAccount cac = { { 0 } };
77 struct ImapAccountData *tmp_adata = NULL;
78 char tmp[1024] = { 0 };
79
80 if (imap_parse_path(path, &cac, tmp, sizeof(tmp)) < 0)
81 return -1;
82
83 struct Account **ap = NULL;
85 {
86 struct Account *a = *ap;
87 if (a->type != MUTT_IMAP)
88 continue;
89
90 tmp_adata = a->adata;
91 if (!tmp_adata)
92 continue;
93 if (imap_account_match(&tmp_adata->conn->account, &cac))
94 {
95 if (mdata)
96 {
97 *mdata = imap_mdata_new(tmp_adata, tmp);
98 }
99 *adata = tmp_adata;
100 return 0;
101 }
102 }
103 mutt_debug(LL_DEBUG3, "no ImapAccountData found\n");
104 return -1;
105}
106
112{
114 mdata->reopen = IMAP_OPEN_NONE;
115 mutt_hash_free(&mdata->uid_hash);
116 imap_msn_free(&mdata->msn);
117 mutt_bcache_close(&mdata->bcache);
118}
119
127void imap_get_parent(const char *mbox, char delim, char *buf, size_t buflen)
128{
129 /* Make a copy of the mailbox name, but only if the pointers are different */
130 if (mbox != buf)
131 mutt_str_copy(buf, mbox, buflen);
132
133 int n = mutt_str_len(buf);
134
135 /* Let's go backwards until the next delimiter
136 *
137 * If buf[n] is a '/', the first n-- will allow us
138 * to ignore it. If it isn't, then buf looks like
139 * "/aaaaa/bbbb". There is at least one "b", so we can't skip
140 * the "/" after the 'a's.
141 *
142 * If buf == '/', then n-- => n == 0, so the loop ends
143 * immediately */
144 for (n--; (n >= 0) && (buf[n] != delim); n--)
145 ; // do nothing
146
147 /* We stopped before the beginning. There is a trailing slash. */
148 if (n > 0)
149 {
150 /* Strip the trailing delimiter. */
151 buf[n] = '\0';
152 }
153 else
154 {
155 buf[0] = (n == 0) ? delim : '\0';
156 }
157}
158
168void imap_get_parent_path(const char *path, char *buf, size_t buflen)
169{
170 struct ImapAccountData *adata = NULL;
171 struct ImapMboxData *mdata = NULL;
172 char mbox[1024] = { 0 };
173
174 if (imap_adata_find(path, &adata, &mdata) < 0)
175 {
176 mutt_str_copy(buf, path, buflen);
177 return;
178 }
179
180 /* Gets the parent mbox in mbox */
181 imap_get_parent(mdata->name, adata->delim, mbox, sizeof(mbox));
182
183 /* Returns a fully qualified IMAP url */
184 imap_qualify_path(buf, buflen, &adata->conn->account, mbox);
185 imap_mdata_free((void *) &mdata);
186}
187
195void imap_clean_path(char *path, size_t plen)
196{
197 struct ImapAccountData *adata = NULL;
198 struct ImapMboxData *mdata = NULL;
199
200 if (imap_adata_find(path, &adata, &mdata) < 0)
201 return;
202
203 /* Returns a fully qualified IMAP url */
204 imap_qualify_path(path, plen, &adata->conn->account, mdata->name);
205 imap_mdata_free((void *) &mdata);
206}
207
211static const char *imap_get_field(enum ConnAccountField field, void *gf_data)
212{
213 switch (field)
214 {
215 case MUTT_CA_LOGIN:
216 return cs_subset_string(NeoMutt->sub, "imap_login");
217 case MUTT_CA_USER:
218 return cs_subset_string(NeoMutt->sub, "imap_user");
219 case MUTT_CA_PASS:
220 return cs_subset_string(NeoMutt->sub, "imap_pass");
222 return cs_subset_string(NeoMutt->sub, "imap_oauth_refresh_command");
223 case MUTT_CA_HOST:
224 default:
225 return NULL;
226 }
227}
228
229#ifdef USE_HCACHE
238static void imap_msn_index_to_uid_seqset(struct Buffer *buf, struct ImapMboxData *mdata)
239{
240 int first = 1;
241 int state = 0;
242 unsigned int cur_uid = 0;
243 unsigned int last_uid = 0;
244 unsigned int range_begin = 0;
245 unsigned int range_end = 0;
246 const size_t max_msn = imap_msn_highest(&mdata->msn);
247
248 for (unsigned int msn = 1; msn <= max_msn + 1; msn++)
249 {
250 bool match = false;
251 if (msn <= max_msn)
252 {
253 struct Email *e_cur = imap_msn_get(&mdata->msn, msn - 1);
254 cur_uid = e_cur ? imap_edata_get(e_cur)->uid : 0;
255 if (!state || (cur_uid && ((cur_uid - 1) == last_uid)))
256 match = true;
257 last_uid = cur_uid;
258 }
259
260 if (match)
261 {
262 switch (state)
263 {
264 case 1: /* single: convert to a range */
265 state = 2;
267
268 case 2: /* extend range ending */
269 range_end = cur_uid;
270 break;
271 default:
272 state = 1;
273 range_begin = cur_uid;
274 break;
275 }
276 }
277 else if (state)
278 {
279 if (first)
280 first = 0;
281 else
282 buf_addch(buf, ',');
283
284 if (state == 1)
285 buf_add_printf(buf, "%u", range_begin);
286 else if (state == 2)
287 buf_add_printf(buf, "%u:%u", range_begin, range_end);
288
289 state = 1;
290 range_begin = cur_uid;
291 }
292 }
293}
294
298static void imap_hcache_namer(const struct StoreOps *store_ops,
299 const char *path, struct Buffer *dest)
300{
301 buf_printf(dest, "%s.%s.hcache", path, store_ops->name);
302}
303
310void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool create)
311{
312 if (!adata || !mdata)
313 return;
314
315 if (mdata->hcache)
316 return;
317
318 struct HeaderCache *hc = NULL;
319 struct Buffer *mbox = buf_pool_get();
320 struct Buffer *cachepath = buf_pool_get();
321
322 imap_cachepath(adata->delim, mdata->name, mbox);
323
324 if (strstr(buf_string(mbox), "/../") || mutt_str_equal(buf_string(mbox), "..") ||
325 mutt_strn_equal(buf_string(mbox), "../", 3))
326 {
327 goto cleanup;
328 }
329 size_t len = buf_len(mbox);
330 if ((len > 3) && (mutt_str_equal(buf_string(mbox) + len - 3, "/..")))
331 goto cleanup;
332
333 struct Url url = { 0 };
334 account_to_url(&adata->conn->account, &url);
335 url.path = mbox->data;
336 url_tobuffer(&url, cachepath, U_PATH);
337
338 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
339 hc = hcache_open(c_header_cache, buf_string(cachepath), imap_hcache_namer, create);
340
341cleanup:
342 buf_pool_release(&mbox);
343 buf_pool_release(&cachepath);
344 mdata->hcache = hc;
345}
346
352{
353 if (!mdata->hcache)
354 return;
355
356 hcache_close(&mdata->hcache);
357}
358
366struct Email *imap_hcache_get(struct ImapMboxData *mdata, unsigned int uid)
367{
368 if (!mdata->hcache)
369 return NULL;
370
371 char key[16] = { 0 };
372
373 snprintf(key, sizeof(key), "%u", uid);
374 struct HCacheEntry hce = hcache_fetch_email(mdata->hcache, key, mutt_str_len(key),
375 mdata->uidvalidity);
376 if (!hce.email && hce.uidvalidity)
377 {
378 mutt_debug(LL_DEBUG3, "hcache uidvalidity mismatch: %u\n", hce.uidvalidity);
379 }
380
381 return hce.email;
382}
383
391int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
392{
393 if (!mdata->hcache)
394 return -1;
395
396 char key[16] = { 0 };
397
398 snprintf(key, sizeof(key), "%u", imap_edata_get(e)->uid);
399 return hcache_store_email(mdata->hcache, key, mutt_str_len(key), e, mdata->uidvalidity);
400}
401
409int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
410{
411 if (!mdata->hcache)
412 return -1;
413
414 char key[16] = { 0 };
415
416 snprintf(key, sizeof(key), "%u", uid);
417 return hcache_delete_email(mdata->hcache, key, mutt_str_len(key));
418}
419
427{
428 if (!mdata->hcache)
429 return -1;
430
431 struct Buffer *buf = buf_pool_get();
432 buf_alloc(buf, 8192); // The seqset is likely large. Preallocate to reduce reallocs
434
435 int rc = hcache_store_raw(mdata->hcache, "UIDSEQSET", 9, buf->data, buf_len(buf) + 1);
436 mutt_debug(LL_DEBUG3, "Stored UIDSEQSET %s\n", buf_string(buf));
437 buf_pool_release(&buf);
438 return rc;
439}
440
448{
449 if (!mdata->hcache)
450 return -1;
451
452 return hcache_delete_raw(mdata->hcache, "UIDSEQSET", 9);
453}
454
462{
463 if (!mdata->hcache)
464 return NULL;
465
466 char *seqset = hcache_fetch_raw_str(mdata->hcache, "UIDSEQSET", 9);
467 mutt_debug(LL_DEBUG3, "Retrieved UIDSEQSET %s\n", NONULL(seqset));
468
469 return seqset;
470}
471#endif
472
485int imap_parse_path(const char *path, struct ConnAccount *cac, char *mailbox, size_t mailboxlen)
486{
487 static unsigned short ImapPort = 0;
488 static unsigned short ImapsPort = 0;
489
490 if (ImapPort == 0)
491 {
492 struct servent *service = getservbyname("imap", "tcp");
493 if (service)
494 ImapPort = ntohs(service->s_port);
495 else
496 ImapPort = IMAP_PORT;
497 mutt_debug(LL_DEBUG3, "Using default IMAP port %d\n", ImapPort);
498 }
499
500 if (ImapsPort == 0)
501 {
502 struct servent *service = getservbyname("imaps", "tcp");
503 if (service)
504 ImapsPort = ntohs(service->s_port);
505 else
506 ImapsPort = IMAP_SSL_PORT;
507 mutt_debug(LL_DEBUG3, "Using default IMAPS port %d\n", ImapsPort);
508 }
509
510 /* Defaults */
511 cac->port = ImapPort;
513 cac->service = "imap";
515
516 struct Url *url = url_parse(path);
517 if (!url)
518 return -1;
519
520 if ((url->scheme != U_IMAP) && (url->scheme != U_IMAPS))
521 {
522 url_free(&url);
523 return -1;
524 }
525
526 if ((account_from_url(cac, url) < 0) || (cac->host[0] == '\0'))
527 {
528 url_free(&url);
529 return -1;
530 }
531
532 if (url->scheme == U_IMAPS)
533 cac->flags |= MUTT_ACCT_SSL;
534
535 mutt_str_copy(mailbox, url->path, mailboxlen);
536
537 url_free(&url);
538
539 if ((cac->flags & MUTT_ACCT_SSL) && !(cac->flags & MUTT_ACCT_PORT))
540 cac->port = ImapsPort;
541
542 return 0;
543}
544
556int imap_mxcmp(const char *mx1, const char *mx2)
557{
558 char *b1 = NULL;
559 char *b2 = NULL;
560 int rc;
561
562 if (!mx1 || (*mx1 == '\0'))
563 mx1 = "INBOX";
564 if (!mx2 || (*mx2 == '\0'))
565 mx2 = "INBOX";
566 if (mutt_istr_equal(mx1, "INBOX") && mutt_istr_equal(mx2, "INBOX"))
567 {
568 return 0;
569 }
570
571 b1 = MUTT_MEM_MALLOC(strlen(mx1) + 1, char);
572 b2 = MUTT_MEM_MALLOC(strlen(mx2) + 1, char);
573
574 imap_fix_path(mx1, b1, strlen(mx1) + 1);
575 imap_fix_path(mx2, b2, strlen(mx2) + 1);
576
577 rc = mutt_str_cmp(b1, b2);
578 FREE(&b1);
579 FREE(&b2);
580
581 return rc;
582}
583
592void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
593{
594 struct ConnAccount cac_target = { { 0 } };
595 struct ConnAccount cac_home = { { 0 } };
596 struct Url url = { 0 };
597 const char *delim = NULL;
598 int tlen;
599 int hlen = 0;
600 bool home_match = false;
601 char target_mailbox[1024] = { 0 };
602 char home_mailbox[1024] = { 0 };
603
604 if (imap_parse_path(path, &cac_target, target_mailbox, sizeof(target_mailbox)) < 0)
605 return;
606
607 if (imap_path_probe(folder, NULL) != MUTT_IMAP)
608 goto fallback;
609
610 if (imap_parse_path(folder, &cac_home, home_mailbox, sizeof(home_mailbox)) < 0)
611 goto fallback;
612
613 tlen = mutt_str_len(target_mailbox);
614 hlen = mutt_str_len(home_mailbox);
615
616 /* check whether we can do '+' substitution */
617 if (tlen && imap_account_match(&cac_home, &cac_target) &&
618 mutt_strn_equal(home_mailbox, target_mailbox, hlen))
619 {
620 const char *const c_imap_delim_chars = cs_subset_string(NeoMutt->sub, "imap_delim_chars");
621 if (hlen == 0)
622 {
623 home_match = true;
624 }
625 else if (c_imap_delim_chars)
626 {
627 for (delim = c_imap_delim_chars; *delim != '\0'; delim++)
628 if (target_mailbox[hlen] == *delim)
629 home_match = true;
630 }
631 }
632
633 /* do the '+' substitution */
634 if (home_match)
635 {
636 *path++ = '+';
637 /* copy remaining path, skipping delimiter */
638 if (hlen != 0)
639 hlen++;
640 memcpy(path, target_mailbox + hlen, tlen - hlen);
641 path[tlen - hlen] = '\0';
642 return;
643 }
644
645fallback:
646 account_to_url(&cac_target, &url);
647 url.path = target_mailbox;
648 url_tostring(&url, path, pathlen, U_NONE);
649}
650
657enum QuadOption imap_continue(const char *msg, const char *resp)
658{
659 imap_error(msg, resp);
660 return query_yesorno(_("Continue?"), MUTT_NO);
661}
662
668void imap_error(const char *where, const char *msg)
669{
670 mutt_error("%s [%s]", where, msg);
671}
672
689char *imap_fix_path(const char *mailbox, char *path, size_t plen)
690{
691 const char *const c_imap_delim_chars = cs_subset_string(NeoMutt->sub, "imap_delim_chars");
692
693 char *out = path;
694 size_t space_left = plen - 1;
695
696 if (mailbox)
697 {
698 for (const char *c = mailbox; *c && space_left; c++, space_left--)
699 {
700 if (strchr(NONULL(c_imap_delim_chars), *c))
701 {
702 return imap_fix_path_with_delim(*c, mailbox, path, plen);
703 }
704 *out++ = *c;
705 }
706 }
707
708 *out = '\0';
709 return path;
710}
711
721char *imap_fix_path_with_delim(const char delim, const char *mailbox, char *path, size_t plen)
722{
723 char *out = path;
724 size_t space_left = plen - 1;
725
726 if (mailbox)
727 {
728 for (const char *c = mailbox; *c && space_left; c++, space_left--)
729 {
730 if (*c == delim || *c == '/')
731 {
732 while (*c && *(c + 1) == *c)
733 c++;
734 *out++ = delim;
735 }
736 else
737 {
738 *out++ = *c;
739 }
740 }
741 }
742
743 if (out != path && *(out - 1) == delim)
744 {
745 out--;
746 }
747 *out = '\0';
748 return path;
749}
750
757void imap_cachepath(char delim, const char *mailbox, struct Buffer *dest)
758{
759 const char *p = mailbox;
760 buf_reset(dest);
761 if (!p)
762 return;
763
764 while (*p)
765 {
766 if (p[0] == delim)
767 {
768 buf_addch(dest, '/');
769 /* simple way to avoid collisions with UIDs */
770 if ((p[1] >= '0') && (p[1] <= '9'))
771 buf_addch(dest, '_');
772 }
773 else
774 {
775 buf_addch(dest, *p);
776 }
777 p++;
778 }
779}
780
788int imap_get_literal_count(char *buf, unsigned int *bytes)
789{
790 char *pc = NULL;
791 char *pn = NULL;
792
793 if (!buf || !(pc = strchr(buf, '{')))
794 return -1;
795
796 pc++;
797 pn = pc;
798 while (mutt_isdigit(*pc))
799 pc++;
800 *pc = '\0';
801 if (!mutt_str_atoui(pn, bytes))
802 return -1;
803
804 return 0;
805}
806
815char *imap_get_qualifier(char *buf)
816{
817 char *s = buf;
818
819 /* skip tag */
820 s = imap_next_word(s);
821 /* skip OK/NO/BAD response */
822 s = imap_next_word(s);
823
824 return s;
825}
826
832char *imap_next_word(char *s)
833{
834 bool quoted = false;
835
836 while (*s)
837 {
838 if (*s == '\\')
839 {
840 s++;
841 if (*s)
842 s++;
843 continue;
844 }
845 if (*s == '\"')
846 quoted = !quoted;
847 if (!quoted && mutt_isspace(*s))
848 break;
849 s++;
850 }
851
852 SKIPWS(s);
853 return s;
854}
855
863void imap_qualify_path(char *buf, size_t buflen, struct ConnAccount *cac, char *path)
864{
865 struct Url url = { 0 };
866 account_to_url(cac, &url);
867 url.path = path;
868 url_tostring(&url, buf, buflen, U_NONE);
869}
870
877void imap_buf_qualify_path(struct Buffer *buf, struct ConnAccount *cac, char *path)
878{
879 struct Url url = { 0 };
880 account_to_url(cac, &url);
881 url.path = path;
882 url_tobuffer(&url, buf, U_NONE);
883}
884
894void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
895{
896 const char *quote = "`\"\\";
897 if (!quote_backtick)
898 quote++;
899
900 char *pt = dest;
901 const char *s = src;
902
903 if (dlen < 3)
904 {
905 *dest = '\0';
906 return;
907 }
908
909 *pt++ = '"';
910 /* save room for quote-chars */
911 dlen -= 3;
912
913 for (; *s && dlen; s++)
914 {
915 if (strchr(quote, *s))
916 {
917 if (dlen < 2)
918 break;
919 dlen -= 2;
920 *pt++ = '\\';
921 *pt++ = *s;
922 }
923 else
924 {
925 *pt++ = *s;
926 dlen--;
927 }
928 }
929 *pt++ = '"';
930 *pt = '\0';
931}
932
938{
939 char *d = s;
940
941 if (*s == '\"')
942 s++;
943 else
944 return;
945
946 while (*s)
947 {
948 if (*s == '\"')
949 {
950 *d = '\0';
951 return;
952 }
953 if (*s == '\\')
954 {
955 s++;
956 }
957 if (*s)
958 {
959 *d = *s;
960 d++;
961 s++;
962 }
963 }
964 *d = '\0';
965}
966
974void imap_munge_mbox_name(bool unicode, char *dest, size_t dlen, const char *src)
975{
976 char *buf = mutt_str_dup(src);
977 imap_utf_encode(unicode, &buf);
978
979 imap_quote_string(dest, dlen, buf, false);
980
981 FREE(&buf);
982}
983
991void imap_unmunge_mbox_name(bool unicode, char *s)
992{
994
995 char *buf = mutt_str_dup(s);
996 if (buf)
997 {
998 imap_utf_decode(unicode, &buf);
999 strncpy(s, buf, strlen(s));
1000 }
1001
1002 FREE(&buf);
1003}
1004
1009{
1010 time_t now = mutt_date_now();
1011 const short c_imap_keep_alive = cs_subset_number(NeoMutt->sub, "imap_keep_alive");
1012
1013 struct Account **ap = NULL;
1015 {
1016 struct Account *a = *ap;
1017 if (a->type != MUTT_IMAP)
1018 continue;
1019
1020 struct ImapAccountData *adata = a->adata;
1021 if (!adata || !adata->mailbox)
1022 continue;
1023
1024 if ((adata->state >= IMAP_AUTHENTICATED) && (now >= (adata->lastread + c_imap_keep_alive)))
1025 imap_check_mailbox(adata->mailbox, true);
1026 }
1027}
1028
1035{
1036 struct sigaction oldalrm = { 0 };
1037 struct sigaction act = { 0 };
1038 sigset_t oldmask = { 0 };
1039 int rc = 0;
1040
1041 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
1042 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", true, NULL);
1043 OptKeepQuiet = true;
1044
1045 sigprocmask(SIG_SETMASK, NULL, &oldmask);
1046
1047 sigemptyset(&act.sa_mask);
1048 act.sa_handler = mutt_sig_empty_handler;
1049#ifdef SA_INTERRUPT
1050 act.sa_flags = SA_INTERRUPT;
1051#else
1052 act.sa_flags = 0;
1053#endif
1054
1055 sigaction(SIGALRM, &act, &oldalrm);
1056
1057 const short c_imap_keep_alive = cs_subset_number(NeoMutt->sub, "imap_keep_alive");
1058 alarm(c_imap_keep_alive);
1059 while ((waitpid(pid, &rc, 0) < 0) && (errno == EINTR))
1060 {
1061 alarm(0); /* cancel a possibly pending alarm */
1063 alarm(c_imap_keep_alive);
1064 }
1065
1066 alarm(0); /* cancel a possibly pending alarm */
1067
1068 sigaction(SIGALRM, &oldalrm, NULL);
1069 sigprocmask(SIG_SETMASK, &oldmask, NULL);
1070
1071 OptKeepQuiet = false;
1072 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1073
1074 return rc;
1075}
1076
1082{
1084 struct ImapMboxData *mdata = imap_mdata_get(m);
1085 if (!adata || !adata->mailbox || (adata->mailbox != m) || !mdata)
1086 return;
1087 mdata->reopen |= IMAP_REOPEN_ALLOW;
1088}
1089
1095{
1097 struct ImapMboxData *mdata = imap_mdata_get(m);
1098 if (!adata || !adata->mailbox || (adata->mailbox != m) || !mdata)
1099 return;
1100 mdata->reopen &= ~IMAP_REOPEN_ALLOW;
1101}
1102
1109bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
1110{
1111 if (!a1 || !a2)
1112 return false;
1113 if (a1->type != a2->type)
1114 return false;
1115 if (!mutt_istr_equal(a1->host, a2->host))
1116 return false;
1117 if ((a1->port != 0) && (a2->port != 0) && (a1->port != a2->port))
1118 return false;
1119 if (a1->flags & a2->flags & MUTT_ACCT_USER)
1120 return mutt_str_equal(a1->user, a2->user);
1121
1122 const char *user = NONULL(NeoMutt->username);
1123
1124 const char *const c_imap_user = cs_subset_string(NeoMutt->sub, "imap_user");
1125 if ((a1->type == MUTT_ACCT_TYPE_IMAP) && c_imap_user)
1126 user = c_imap_user;
1127
1128 if (a1->flags & MUTT_ACCT_USER)
1129 return mutt_str_equal(a1->user, user);
1130 if (a2->flags & MUTT_ACCT_USER)
1131 return mutt_str_equal(a2->user, user);
1132
1133 return true;
1134}
1135
1141struct SeqsetIterator *mutt_seqset_iterator_new(const char *seqset)
1142{
1143 if (!seqset || (*seqset == '\0'))
1144 return NULL;
1145
1146 struct SeqsetIterator *iter = MUTT_MEM_CALLOC(1, struct SeqsetIterator);
1147 iter->full_seqset = mutt_str_dup(seqset);
1148 iter->eostr = strchr(iter->full_seqset, '\0');
1149 iter->substr_cur = iter->substr_end = iter->full_seqset;
1150
1151 return iter;
1152}
1153
1162int mutt_seqset_iterator_next(struct SeqsetIterator *iter, unsigned int *next)
1163{
1164 if (!iter || !next)
1165 return -1;
1166
1167 if (iter->in_range)
1168 {
1169 if ((iter->down && (iter->range_cur == (iter->range_end - 1))) ||
1170 (!iter->down && (iter->range_cur == (iter->range_end + 1))))
1171 {
1172 iter->in_range = 0;
1173 }
1174 }
1175
1176 if (!iter->in_range)
1177 {
1178 iter->substr_cur = iter->substr_end;
1179 if (iter->substr_cur == iter->eostr)
1180 return 1;
1181
1182 iter->substr_end = strchr(iter->substr_cur, ',');
1183 if (!iter->substr_end)
1184 iter->substr_end = iter->eostr;
1185 else
1186 *(iter->substr_end++) = '\0';
1187
1188 char *range_sep = strchr(iter->substr_cur, ':');
1189 if (range_sep)
1190 *range_sep++ = '\0';
1191
1192 if (!mutt_str_atoui_full(iter->substr_cur, &iter->range_cur))
1193 return -1;
1194 if (range_sep)
1195 {
1196 if (!mutt_str_atoui_full(range_sep, &iter->range_end))
1197 return -1;
1198 }
1199 else
1200 {
1201 iter->range_end = iter->range_cur;
1202 }
1203
1204 iter->down = (iter->range_end < iter->range_cur);
1205 iter->in_range = 1;
1206 }
1207
1208 *next = iter->range_cur;
1209 if (iter->down)
1210 iter->range_cur--;
1211 else
1212 iter->range_cur++;
1213
1214 return 0;
1215}
1216
1222{
1223 if (!ptr || !*ptr)
1224 return;
1225
1226 struct SeqsetIterator *iter = *ptr;
1227 FREE(&iter->full_seqset);
1228 FREE(ptr);
1229}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition atoi.c:217
Body Caching (local copies of email bodies)
void mutt_bcache_close(struct BodyCache **ptr)
Close an Email-Body Cache.
Definition bcache.c:183
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:211
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:248
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:342
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.
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
@ MUTT_ACCT_PORT
Port field has been set.
Definition connaccount.h:47
@ MUTT_ACCT_SSL
Account uses SSL/TLS.
Definition connaccount.h:51
@ MUTT_ACCT_USER
User field has been set.
Definition connaccount.h:48
Convenience wrapper for the core headers.
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:96
bool mutt_isdigit(int arg)
Wrapper for isdigit(3)
Definition ctype.c:66
Structs that make up an email.
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition globals.c:49
Global variables.
static const char * imap_get_field(enum ConnAccountField field, void *gf_data)
Get connection login credentials - Implements ConnAccount::get_field() -.
Definition util.c:211
static void imap_hcache_namer(const struct StoreOps *store_ops, const char *path, struct Buffer *dest)
Generate a filename for the header cache - Implements hcache_namer_t -.
Definition util.c:298
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
void imap_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free() -.
Definition mdata.c:40
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2683
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition hash.c:460
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer, bool create)
Multiplexor for StoreOps::open.
Definition hcache.c:492
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition hcache.c:769
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition hcache.c:564
struct HCacheEntry hcache_fetch_email(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition hcache.c:584
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:700
char * hcache_fetch_raw_str(struct HeaderCache *hc, const char *key, size_t keylen)
Fetch a string from the cache.
Definition hcache.c:679
int hcache_delete_raw(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition hcache.c:782
int 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:754
Header cache multiplexor.
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition adata.c:162
Imap-specific Account data.
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition edata.c:66
Imap-specific Email data.
IMAP network mailbox.
struct ImapMboxData * imap_mdata_new(struct ImapAccountData *adata, const char *name)
Allocate and initialise a new ImapMboxData structure.
Definition mdata.c:74
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition mdata.c:61
Imap-specific Mailbox data.
Shared constants/structs that are private to IMAP.
#define IMAP_PORT
Default port for IMAP.
Definition private.h:44
@ IMAP_AUTHENTICATED
Connection is authenticated.
Definition private.h:120
void imap_utf_encode(bool unicode, char **s)
Encode email from local charset to UTF-8.
Definition utf7.c:401
#define IMAP_SSL_PORT
Port for IMAP over SSL/TLS.
Definition private.h:45
void imap_utf_decode(bool unicode, char **s)
Decode email from UTF-8 to local charset.
Definition utf7.c:434
@ IMAP_OPEN_NONE
No flags are set.
Definition private.h:67
@ IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition private.h:68
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition imap.c:1220
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
#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
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:53
void imap_msn_free(struct MSNArray *msn)
Free the cache.
Definition msn.c:62
struct Email * imap_msn_get(const struct MSNArray *msn, int idx)
Return the Email associated with an msn.
Definition msn.c:83
size_t imap_msn_highest(const struct MSNArray *msn)
Return the highest MSN in use.
Definition msn.c:72
IMAP MSN helper functions.
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:459
Convenience wrapper for the library headers.
#define FALLTHROUGH
Definition lib.h:117
#define _(a)
Definition message.h:28
int mutt_str_cmp(const char *a, const char *b)
Compare two strings, safely.
Definition string.c:403
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
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:429
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
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:587
void account_to_url(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
int account_from_url(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
@ MUTT_ACCT_TYPE_IMAP
Imap Account.
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
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 query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:329
void mutt_sig_empty_handler(int sig)
Dummy signal handler.
Definition signal.c:130
Key value store.
#define NONULL(x)
Definition string2.h:44
#define SKIPWS(ch)
Definition string2.h:52
A group of associated Mailboxes.
Definition account.h:36
enum MailboxType type
Type of Mailboxes this Account contains.
Definition account.h:37
void * adata
Private data (for Mailbox backends)
Definition account.h:42
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
Login details for a remote server.
Definition connaccount.h:59
char user[128]
Username.
Definition connaccount.h:62
const char * service
Name of the service, e.g. "imap".
Definition connaccount.h:67
char host[128]
Server to login to.
Definition connaccount.h:60
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Definition connaccount.h:76
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition connaccount.h:65
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition connaccount.h:66
unsigned short port
Port to connect to.
Definition connaccount.h:64
struct ConnAccount account
Account details: username, password, etc.
Definition connection.h:49
The envelope/body of an email.
Definition email.h:39
char * path
Path of Email (for local Mailboxes)
Definition email.h:70
Wrapper for Email retrieved from the header cache.
Definition lib.h:100
uint32_t uidvalidity
IMAP-specific UIDVALIDITY.
Definition lib.h:101
struct Email * email
Retrieved email.
Definition lib.h:103
Header Cache.
Definition lib.h:87
IMAP-specific Account data -.
Definition adata.h:40
char delim
Path delimiter.
Definition adata.h:79
struct Mailbox * mailbox
Current selected mailbox.
Definition adata.h:80
struct Connection * conn
Connection to IMAP server.
Definition adata.h:41
unsigned int uid
32-bit Message UID
Definition edata.h:45
IMAP-specific Mailbox data -.
Definition mdata.h:40
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition mdata.h:45
struct HeaderCache * hcache
Email header cache.
Definition mdata.h:64
struct BodyCache * bcache
Email body cache.
Definition mdata.h:62
struct HashTable * uid_hash
Hash Table: "uid" -> Email.
Definition mdata.h:60
ImapOpenFlags check_status
Flags, e.g. IMAP_NEWMAIL_PENDING.
Definition mdata.h:46
uint32_t uidvalidity
UID validity.
Definition mdata.h:51
char * name
Mailbox name.
Definition mdata.h:41
A mailbox.
Definition mailbox.h:81
void * mdata
Driver specific data.
Definition mailbox.h:134
Container for Accounts, Notifications.
Definition neomutt.h:41
struct AccountArray accounts
All Accounts.
Definition neomutt.h:50
char * username
User's login name.
Definition neomutt.h:56
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
UID Sequence Set Iterator.
Definition private.h:185
char * eostr
End of string.
Definition private.h:187
char * substr_end
End of substring.
Definition private.h:193
unsigned int range_end
End of range.
Definition private.h:191
int down
Counting down.
Definition private.h:189
char * substr_cur
Current position in substring.
Definition private.h:192
int in_range
Currently in a range.
Definition private.h:188
char * full_seqset
Full sequence set string.
Definition private.h:186
unsigned int range_cur
Current range value.
Definition private.h:190
Definition lib.h:66
const char * name
Store name.
Definition lib.h:67
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition url.h:69
char * 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:303
struct Url * url_parse(const char *src)
Fill in Url.
Definition url.c:242
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition url.c:124
int url_tostring(const struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition url.c:426
int url_tobuffer(const struct Url *url, struct Buffer *buf, uint8_t flags)
Output the URL string for a given Url object.
Definition url.c:361
@ U_IMAP
Url is imap://.
Definition url.h:39
@ U_IMAPS
Url is imaps://.
Definition url.h:40
#define U_PATH
Path is included in URL.
Definition url.h:50
#define U_NONE
No flags are set for URL parsing.
Definition url.h:49
void imap_unmunge_mbox_name(bool unicode, char *s)
Remove quoting from a mailbox name.
Definition util.c:991
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:485
void imap_qualify_path(char *buf, size_t buflen, struct ConnAccount *cac, char *path)
Make an absolute IMAP folder target.
Definition util.c:863
void imap_allow_reopen(struct Mailbox *m)
Allow re-opening a folder upon expunge.
Definition util.c:1081
void imap_disallow_reopen(struct Mailbox *m)
Disallow re-opening a folder upon expunge.
Definition util.c:1094
void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool create)
Open a header cache.
Definition util.c:310
int imap_hcache_store_uid_seqset(struct ImapMboxData *mdata)
Store a UID Sequence Set in the header cache.
Definition util.c:426
int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
Add an entry to the header cache.
Definition util.c:391
void imap_mdata_cache_reset(struct ImapMboxData *mdata)
Release and clear cache data of ImapMboxData structure.
Definition util.c:111
void imap_get_parent(const char *mbox, char delim, char *buf, size_t buflen)
Get an IMAP folder's parent.
Definition util.c:127
struct SeqsetIterator * mutt_seqset_iterator_new(const char *seqset)
Create a new Sequence Set Iterator.
Definition util.c:1141
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
Quote string according to IMAP rules.
Definition util.c:894
char * imap_hcache_get_uid_seqset(struct ImapMboxData *mdata)
Get a UID Sequence Set from the header cache.
Definition util.c:461
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:657
void imap_unquote_string(char *s)
Equally stupid unquoting routine.
Definition util.c:937
struct Email * imap_hcache_get(struct ImapMboxData *mdata, unsigned int uid)
Get a header cache entry by its UID.
Definition util.c:366
int imap_wait_keep_alive(pid_t pid)
Wait for a process to change state.
Definition util.c:1034
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition util.c:168
int mutt_seqset_iterator_next(struct SeqsetIterator *iter, unsigned int *next)
Get the next UID from a Sequence Set.
Definition util.c:1162
void imap_clean_path(char *path, size_t plen)
Cleans an IMAP path using imap_fix_path.
Definition util.c:195
void mutt_seqset_iterator_free(struct SeqsetIterator **ptr)
Free a Sequence Set Iterator.
Definition util.c:1221
int imap_get_literal_count(char *buf, unsigned int *bytes)
Write number of bytes in an IMAP literal into bytes.
Definition util.c:788
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition util.c:556
void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
Prettify an IMAP mailbox name.
Definition util.c:592
void imap_cachepath(char delim, const char *mailbox, struct Buffer *dest)
Generate a cache path for a mailbox.
Definition util.c:757
char * imap_fix_path(const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition util.c:689
void imap_error(const char *where, const char *msg)
Show an error and abort.
Definition util.c:668
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition util.c:351
char * imap_fix_path_with_delim(const char delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition util.c:721
int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
Delete an item from the header cache.
Definition util.c:409
int imap_hcache_clear_uid_seqset(struct ImapMboxData *mdata)
Delete a UID Sequence Set from the header cache.
Definition util.c:447
int imap_adata_find(const char *path, struct ImapAccountData **adata, struct ImapMboxData **mdata)
Find the Account data for this path.
Definition util.c:73
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition util.c:1109
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:974
void imap_keep_alive(void)
Poll the current folder to keep the connection alive.
Definition util.c:1008
static void imap_msn_index_to_uid_seqset(struct Buffer *buf, struct ImapMboxData *mdata)
Convert MSN index of UIDs to Seqset.
Definition util.c:238
void imap_buf_qualify_path(struct Buffer *buf, struct ConnAccount *cac, char *path)
Make an absolute IMAP folder target to a buffer.
Definition util.c:877
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition util.c:832
char * imap_get_qualifier(char *buf)
Get the qualifier from a tagged response.
Definition util.c:815