NeoMutt  2019-12-07-60-g0cfa53
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 "imap_private.h"
45 #include "mutt/mutt.h"
46 #include "config/lib.h"
47 #include "email/lib.h"
48 #include "core/lib.h"
49 #include "conn/conn.h"
50 #include "gui/lib.h"
51 #include "bcache.h"
52 #include "globals.h"
53 #include "imap/imap.h"
54 #include "mutt_account.h"
55 #include "options.h"
56 #ifdef USE_HCACHE
57 #include "hcache/hcache.h"
58 #include "message.h"
59 #endif
60 
61 /* These Config Variables are only used in imap/util.c */
64 
69 void imap_adata_free(void **ptr)
70 {
71  if (!ptr || !*ptr)
72  return;
73 
74  struct ImapAccountData *adata = *ptr;
75 
76  FREE(&adata->capstr);
77  mutt_buffer_dealloc(&adata->cmdbuf);
78  FREE(&adata->buf);
79  FREE(&adata->cmds);
80 
81  if (adata->conn)
82  {
83  if (adata->conn->conn_close)
84  adata->conn->conn_close(adata->conn);
85  FREE(&adata->conn);
86  }
87 
88  FREE(ptr);
89 }
90 
96 {
97  struct ImapAccountData *adata = mutt_mem_calloc(1, sizeof(struct ImapAccountData));
98  static unsigned char new_seqid = 'a';
99 
100  adata->seqid = new_seqid;
101  adata->cmdslots = C_ImapPipelineDepth + 2;
102  adata->cmds = mutt_mem_calloc(adata->cmdslots, sizeof(*adata->cmds));
103 
104  if (++new_seqid > 'z')
105  new_seqid = 'a';
106 
107  return adata;
108 }
109 
116 {
117  if (!m || (m->magic != MUTT_IMAP) || !m->account)
118  return NULL;
119  return m->account->adata;
120 }
121 
130 int imap_adata_find(const char *path, struct ImapAccountData **adata,
131  struct ImapMboxData **mdata)
132 {
133  struct ConnAccount conn_account;
134  struct ImapAccountData *tmp_adata = NULL;
135  char tmp[1024];
136 
137  if (imap_parse_path(path, &conn_account, tmp, sizeof(tmp)) < 0)
138  return -1;
139 
140  struct Account *np = NULL;
141  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
142  {
143  if (np->magic != MUTT_IMAP)
144  continue;
145 
146  tmp_adata = np->adata;
147  if (!tmp_adata)
148  continue;
149  if (imap_account_match(&tmp_adata->conn_account, &conn_account))
150  {
151  *mdata = imap_mdata_new(tmp_adata, tmp);
152  *adata = tmp_adata;
153  return 0;
154  }
155  }
156  mutt_debug(LL_DEBUG3, "no ImapAccountData found\n");
157  return -1;
158 }
159 
166 struct ImapMboxData *imap_mdata_new(struct ImapAccountData *adata, const char *name)
167 {
168  char buf[1024];
169  struct ImapMboxData *mdata = mutt_mem_calloc(1, sizeof(struct ImapMboxData));
170 
171  mdata->real_name = mutt_str_strdup(name);
172 
173  imap_fix_path(adata->delim, name, buf, sizeof(buf));
174  if (buf[0] == '\0')
175  mutt_str_strfcpy(buf, "INBOX", sizeof(buf));
176  mdata->name = mutt_str_strdup(buf);
177 
178  imap_munge_mbox_name(adata->unicode, buf, sizeof(buf), mdata->name);
179  mdata->munge_name = mutt_str_strdup(buf);
180 
181  mdata->reopen &= IMAP_REOPEN_ALLOW;
182 
183  STAILQ_INIT(&mdata->flags);
184 
185 #ifdef USE_HCACHE
186  header_cache_t *hc = imap_hcache_open(adata, mdata);
187  if (hc)
188  {
189  void *uidvalidity = mutt_hcache_fetch_raw(hc, "/UIDVALIDITY", 12);
190  void *uidnext = mutt_hcache_fetch_raw(hc, "/UIDNEXT", 8);
191  unsigned long long *modseq = mutt_hcache_fetch_raw(hc, "/MODSEQ", 7);
192  if (uidvalidity)
193  {
194  mdata->uid_validity = *(unsigned int *) uidvalidity;
195  mdata->uid_next = uidnext ? *(unsigned int *) uidnext : 0;
196  mdata->modseq = modseq ? *modseq : 0;
197  mutt_debug(LL_DEBUG3, "hcache uidvalidity %u, uidnext %u, modseq %llu\n",
198  mdata->uid_validity, mdata->uid_next, mdata->modseq);
199  }
200  mutt_hcache_free(hc, &uidvalidity);
201  mutt_hcache_free(hc, &uidnext);
202  mutt_hcache_free(hc, (void **) &modseq);
203  mutt_hcache_close(hc);
204  }
205 #endif
206 
207  return mdata;
208 }
209 
215 {
216  mutt_hash_free(&mdata->uid_hash);
217  FREE(&mdata->msn_index);
218  mdata->msn_index_size = 0;
219  mdata->max_msn = 0;
220  mutt_bcache_close(&mdata->bcache);
221 }
222 
227 void imap_mdata_free(void **ptr)
228 {
229  if (!ptr || !*ptr)
230  return;
231 
232  struct ImapMboxData *mdata = *ptr;
233 
234  imap_mdata_cache_reset(mdata);
235  mutt_list_free(&mdata->flags);
236  FREE(&mdata->name);
237  FREE(&mdata->real_name);
238  FREE(&mdata->munge_name);
239  FREE(ptr);
240 }
241 
247 {
248  if (!m || (m->magic != MUTT_IMAP) || !m->mdata)
249  return NULL;
250  return m->mdata;
251 }
252 
260 void imap_get_parent(const char *mbox, char delim, char *buf, size_t buflen)
261 {
262  int n;
263 
264  /* Make a copy of the mailbox name, but only if the pointers are different */
265  if (mbox != buf)
266  mutt_str_strfcpy(buf, mbox, buflen);
267 
268  n = mutt_str_strlen(buf);
269 
270  /* Let's go backwards until the next delimiter
271  *
272  * If buf[n] is a '/', the first n-- will allow us
273  * to ignore it. If it isn't, then buf looks like
274  * "/aaaaa/bbbb". There is at least one "b", so we can't skip
275  * the "/" after the 'a's.
276  *
277  * If buf == '/', then n-- => n == 0, so the loop ends
278  * immediately */
279  for (n--; n >= 0 && buf[n] != delim; n--)
280  ;
281 
282  /* We stopped before the beginning. There is a trailing slash. */
283  if (n > 0)
284  {
285  /* Strip the trailing delimiter. */
286  buf[n] = '\0';
287  }
288  else
289  {
290  buf[0] = (n == 0) ? delim : '\0';
291  }
292 }
293 
303 void imap_get_parent_path(const char *path, char *buf, size_t buflen)
304 {
305  struct ImapAccountData *adata = NULL;
306  struct ImapMboxData *mdata = NULL;
307  char mbox[1024];
308 
309  if (imap_adata_find(path, &adata, &mdata) < 0)
310  {
311  mutt_str_strfcpy(buf, path, buflen);
312  return;
313  }
314 
315  /* Gets the parent mbox in mbox */
316  imap_get_parent(mdata->name, adata->delim, mbox, sizeof(mbox));
317 
318  /* Returns a fully qualified IMAP url */
319  imap_qualify_path(buf, buflen, &adata->conn_account, mbox);
320  imap_mdata_free((void *) &mdata);
321 }
322 
330 void imap_clean_path(char *path, size_t plen)
331 {
332  struct ImapAccountData *adata = NULL;
333  struct ImapMboxData *mdata = NULL;
334 
335  if (imap_adata_find(path, &adata, &mdata) < 0)
336  return;
337 
338  /* Returns a fully qualified IMAP url */
339  imap_qualify_path(path, plen, &adata->conn_account, mdata->name);
340  imap_mdata_free((void *) &mdata);
341 }
342 
343 #ifdef USE_HCACHE
344 
352 static void imap_msn_index_to_uid_seqset(struct Buffer *buf, struct ImapMboxData *mdata)
353 {
354  int first = 1, state = 0;
355  unsigned int cur_uid = 0, last_uid = 0;
356  unsigned int range_begin = 0, range_end = 0;
357 
358  for (unsigned int msn = 1; msn <= mdata->max_msn + 1; msn++)
359  {
360  bool match = false;
361  if (msn <= mdata->max_msn)
362  {
363  struct Email *e_cur = mdata->msn_index[msn - 1];
364  cur_uid = e_cur ? imap_edata_get(e_cur)->uid : 0;
365  if (!state || (cur_uid && ((cur_uid - 1) == last_uid)))
366  match = true;
367  last_uid = cur_uid;
368  }
369 
370  if (match)
371  {
372  switch (state)
373  {
374  case 1: /* single: convert to a range */
375  state = 2;
376  /* fall through */
377  case 2: /* extend range ending */
378  range_end = cur_uid;
379  break;
380  default:
381  state = 1;
382  range_begin = cur_uid;
383  break;
384  }
385  }
386  else if (state)
387  {
388  if (first)
389  first = 0;
390  else
391  mutt_buffer_addch(buf, ',');
392 
393  if (state == 1)
394  mutt_buffer_add_printf(buf, "%u", range_begin);
395  else if (state == 2)
396  mutt_buffer_add_printf(buf, "%u:%u", range_begin, range_end);
397 
398  state = 1;
399  range_begin = cur_uid;
400  }
401  }
402 }
403 
407 static void imap_hcache_namer(const char *path, struct Buffer *dest)
408 {
409  mutt_buffer_printf(dest, "%s.hcache", path);
410 }
411 
420 {
421  if (!adata || !mdata)
422  return NULL;
423 
424  header_cache_t *hc = NULL;
425  struct Buffer *mbox = mutt_buffer_pool_get();
426  struct Buffer *cachepath = mutt_buffer_pool_get();
427 
428  imap_cachepath(adata->delim, mdata->name, mbox);
429 
430  if (strstr(mutt_b2s(mbox), "/../") || (strcmp(mutt_b2s(mbox), "..") == 0) ||
431  (strncmp(mutt_b2s(mbox), "../", 3) == 0))
432  {
433  goto cleanup;
434  }
435  size_t len = mutt_buffer_len(mbox);
436  if ((len > 3) && (strcmp(mutt_b2s(mbox) + len - 3, "/..") == 0))
437  goto cleanup;
438 
439  struct Url url;
440  mutt_account_tourl(&adata->conn->account, &url);
441  url.path = mbox->data;
442  url_tobuffer(&url, cachepath, U_PATH);
443 
445 
446 cleanup:
448  mutt_buffer_pool_release(&cachepath);
449  return hc;
450 }
451 
456 void imap_hcache_close(struct ImapMboxData *mdata)
457 {
458  if (!mdata->hcache)
459  return;
460 
461  mutt_hcache_close(mdata->hcache);
462  mdata->hcache = NULL;
463 }
464 
472 struct Email *imap_hcache_get(struct ImapMboxData *mdata, unsigned int uid)
473 {
474  if (!mdata->hcache)
475  return NULL;
476 
477  char key[16];
478  struct Email *e = NULL;
479 
480  sprintf(key, "/%u", uid);
481  void *uv = mutt_hcache_fetch(mdata->hcache, key, mutt_str_strlen(key));
482  if (uv)
483  {
484  const size_t *const uid_validity = uv;
485  if (*uid_validity == mdata->uid_validity)
486  e = mutt_hcache_restore(uv);
487  else
488  mutt_debug(LL_DEBUG3, "hcache uidvalidity mismatch: %zu\n", *uid_validity);
489  mutt_hcache_free(mdata->hcache, &uv);
490  }
491 
492  return e;
493 }
494 
502 int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
503 {
504  if (!mdata->hcache)
505  return -1;
506 
507  char key[16];
508 
509  sprintf(key, "/%u", imap_edata_get(e)->uid);
510  return mutt_hcache_store(mdata->hcache, key, mutt_str_strlen(key), e, mdata->uid_validity);
511 }
512 
520 int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
521 {
522  if (!mdata->hcache)
523  return -1;
524 
525  char key[16];
526 
527  sprintf(key, "/%u", uid);
528  return mutt_hcache_delete_header(mdata->hcache, key, mutt_str_strlen(key));
529 }
530 
538 {
539  if (!mdata->hcache)
540  return -1;
541 
542  /* The seqset is likely large. Preallocate to reduce reallocs */
543  struct Buffer buf = mutt_buffer_make(8192);
544  imap_msn_index_to_uid_seqset(&buf, mdata);
545 
546  int rc = mutt_hcache_store_raw(mdata->hcache, "/UIDSEQSET", 10, buf.data,
547  mutt_buffer_len(&buf) + 1);
548  mutt_debug(LL_DEBUG3, "Stored /UIDSEQSET %s\n", buf.data);
549  mutt_buffer_dealloc(&buf);
550  return rc;
551 }
552 
560 {
561  if (!mdata->hcache)
562  return -1;
563 
564  return mutt_hcache_delete_header(mdata->hcache, "/UIDSEQSET", 10);
565 }
566 
574 {
575  if (!mdata->hcache)
576  return NULL;
577 
578  char *hc_seqset = mutt_hcache_fetch_raw(mdata->hcache, "/UIDSEQSET", 10);
579  char *seqset = mutt_str_strdup(hc_seqset);
580  mutt_hcache_free(mdata->hcache, (void **) &hc_seqset);
581  mutt_debug(LL_DEBUG3, "Retrieved /UIDSEQSET %s\n", NONULL(seqset));
582 
583  return seqset;
584 }
585 #endif
586 
599 int imap_parse_path(const char *path, struct ConnAccount *account, char *mailbox, size_t mailboxlen)
600 {
601  static unsigned short ImapPort = 0;
602  static unsigned short ImapsPort = 0;
603  struct servent *service = NULL;
604 
605  if (ImapPort == 0)
606  {
607  service = getservbyname("imap", "tcp");
608  if (service)
609  ImapPort = ntohs(service->s_port);
610  else
611  ImapPort = IMAP_PORT;
612  mutt_debug(LL_DEBUG3, "Using default IMAP port %d\n", ImapPort);
613  }
614  if (ImapsPort == 0)
615  {
616  service = getservbyname("imaps", "tcp");
617  if (service)
618  ImapsPort = ntohs(service->s_port);
619  else
620  ImapsPort = IMAP_SSL_PORT;
621  mutt_debug(LL_DEBUG3, "Using default IMAPS port %d\n", ImapsPort);
622  }
623 
624  /* Defaults */
625  memset(account, 0, sizeof(struct ConnAccount));
626  account->port = ImapPort;
627  account->type = MUTT_ACCT_TYPE_IMAP;
628 
629  struct Url *url = url_parse(path);
630  if (!url)
631  return -1;
632 
633  if ((url->scheme != U_IMAP) && (url->scheme != U_IMAPS))
634  {
635  url_free(&url);
636  return -1;
637  }
638 
639  if ((mutt_account_fromurl(account, url) < 0) || (account->host[0] == '\0'))
640  {
641  url_free(&url);
642  return -1;
643  }
644 
645  if (url->scheme == U_IMAPS)
646  account->flags |= MUTT_ACCT_SSL;
647 
648  mutt_str_strfcpy(mailbox, url->path, mailboxlen);
649 
650  url_free(&url);
651 
652  if ((account->flags & MUTT_ACCT_SSL) && !(account->flags & MUTT_ACCT_PORT))
653  account->port = ImapsPort;
654 
655  return 0;
656 }
657 
669 int imap_mxcmp(const char *mx1, const char *mx2)
670 {
671  char *b1 = NULL;
672  char *b2 = NULL;
673  int rc;
674 
675  if (!mx1 || !*mx1)
676  mx1 = "INBOX";
677  if (!mx2 || !*mx2)
678  mx2 = "INBOX";
679  if ((mutt_str_strcasecmp(mx1, "INBOX") == 0) &&
680  (mutt_str_strcasecmp(mx2, "INBOX") == 0))
681  {
682  return 0;
683  }
684 
685  b1 = mutt_mem_malloc(strlen(mx1) + 1);
686  b2 = mutt_mem_malloc(strlen(mx2) + 1);
687 
688  imap_fix_path('\0', mx1, b1, strlen(mx1) + 1);
689  imap_fix_path('\0', mx2, b2, strlen(mx2) + 1);
690 
691  rc = mutt_str_strcmp(b1, b2);
692  FREE(&b1);
693  FREE(&b2);
694 
695  return rc;
696 }
697 
706 void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
707 {
708  struct ConnAccount target_conn_account, home_conn_account;
709  struct Url url;
710  char *delim = NULL;
711  int tlen;
712  int hlen = 0;
713  bool home_match = false;
714  char target_mailbox[1024];
715  char home_mailbox[1024];
716 
717  if (imap_parse_path(path, &target_conn_account, target_mailbox, sizeof(target_mailbox)) < 0)
718  return;
719 
720  if (imap_path_probe(folder, NULL) != MUTT_IMAP)
721  goto fallback;
722 
723  if (imap_parse_path(folder, &home_conn_account, home_mailbox, sizeof(home_mailbox)) < 0)
724  goto fallback;
725 
726  tlen = mutt_str_strlen(target_mailbox);
727  hlen = mutt_str_strlen(home_mailbox);
728 
729  /* check whether we can do '+' substitution */
730  if (tlen && mutt_account_match(&home_conn_account, &target_conn_account) &&
731  (mutt_str_strncmp(home_mailbox, target_mailbox, hlen) == 0))
732  {
733  if (hlen == 0)
734  home_match = true;
735  else if (C_ImapDelimChars)
736  {
737  for (delim = C_ImapDelimChars; *delim != '\0'; delim++)
738  if (target_mailbox[hlen] == *delim)
739  home_match = true;
740  }
741  }
742 
743  /* do the '+' substitution */
744  if (home_match)
745  {
746  *path++ = '+';
747  /* copy remaining path, skipping delimiter */
748  if (hlen == 0)
749  hlen = -1;
750  memcpy(path, target_mailbox + hlen + 1, tlen - hlen - 1);
751  path[tlen - hlen - 1] = '\0';
752  return;
753  }
754 
755 fallback:
756  mutt_account_tourl(&target_conn_account, &url);
757  url.path = target_mailbox;
758  url_tostring(&url, path, pathlen, 0);
759 }
760 
767 enum QuadOption imap_continue(const char *msg, const char *resp)
768 {
769  imap_error(msg, resp);
770  return mutt_yesorno(_("Continue?"), MUTT_NO);
771 }
772 
778 void imap_error(const char *where, const char *msg)
779 {
780  mutt_error("%s [%s]", where, msg);
781 }
782 
797 char *imap_fix_path(char server_delim, const char *mailbox, char *path, size_t plen)
798 {
799  int i = 0;
800  char delim = server_delim;
801 
802  while (mailbox && *mailbox && (i < plen - 1))
803  {
804  if ((C_ImapDelimChars && strchr(C_ImapDelimChars, *mailbox)) ||
805  (delim && (*mailbox == delim)))
806  {
807  /* use connection delimiter if known. Otherwise use user delimiter */
808  if (server_delim == '\0')
809  delim = *mailbox;
810 
811  while (*mailbox && ((C_ImapDelimChars && strchr(C_ImapDelimChars, *mailbox)) ||
812  (delim && (*mailbox == delim))))
813  {
814  mailbox++;
815  }
816  path[i] = delim;
817  }
818  else
819  {
820  path[i] = *mailbox;
821  mailbox++;
822  }
823  i++;
824  }
825  if (i && (path[--i] != delim))
826  i++;
827  path[i] = '\0';
828 
829  return path;
830 }
831 
838 void imap_cachepath(char delim, const char *mailbox, struct Buffer *dest)
839 {
840  const char *p = mailbox;
841  mutt_buffer_reset(dest);
842  if (!p)
843  return;
844 
845  while (*p)
846  {
847  if (p[0] == delim)
848  {
849  mutt_buffer_addch(dest, '/');
850  /* simple way to avoid collisions with UIDs */
851  if ((p[1] >= '0') && (p[1] <= '9'))
852  mutt_buffer_addch(dest, '_');
853  }
854  else
855  mutt_buffer_addch(dest, *p);
856  p++;
857  }
858 }
859 
867 int imap_get_literal_count(const char *buf, unsigned int *bytes)
868 {
869  char *pc = NULL;
870  char *pn = NULL;
871 
872  if (!buf || !(pc = strchr(buf, '{')))
873  return -1;
874 
875  pc++;
876  pn = pc;
877  while (isdigit((unsigned char) *pc))
878  pc++;
879  *pc = '\0';
880  if (mutt_str_atoui(pn, bytes) < 0)
881  return -1;
882 
883  return 0;
884 }
885 
894 char *imap_get_qualifier(char *buf)
895 {
896  char *s = buf;
897 
898  /* skip tag */
899  s = imap_next_word(s);
900  /* skip OK/NO/BAD response */
901  s = imap_next_word(s);
902 
903  return s;
904 }
905 
911 char *imap_next_word(char *s)
912 {
913  bool quoted = false;
914 
915  while (*s)
916  {
917  if (*s == '\\')
918  {
919  s++;
920  if (*s)
921  s++;
922  continue;
923  }
924  if (*s == '\"')
925  quoted = !quoted;
926  if (!quoted && IS_SPACE(*s))
927  break;
928  s++;
929  }
930 
931  SKIPWS(s);
932  return s;
933 }
934 
942 void imap_qualify_path(char *buf, size_t buflen, struct ConnAccount *conn_account, char *path)
943 {
944  struct Url url;
945  mutt_account_tourl(conn_account, &url);
946  url.path = path;
947  url_tostring(&url, buf, buflen, 0);
948 }
949 
959 void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
960 {
961  const char *quote = "`\"\\";
962  if (!quote_backtick)
963  quote++;
964 
965  char *pt = dest;
966  const char *s = src;
967 
968  *pt++ = '"';
969  /* save room for quote-chars */
970  dlen -= 3;
971 
972  for (; *s && dlen; s++)
973  {
974  if (strchr(quote, *s))
975  {
976  if (dlen < 2)
977  break;
978  dlen -= 2;
979  *pt++ = '\\';
980  *pt++ = *s;
981  }
982  else
983  {
984  *pt++ = *s;
985  dlen--;
986  }
987  }
988  *pt++ = '"';
989  *pt = '\0';
990 }
991 
996 void imap_unquote_string(char *s)
997 {
998  char *d = s;
999 
1000  if (*s == '\"')
1001  s++;
1002  else
1003  return;
1004 
1005  while (*s)
1006  {
1007  if (*s == '\"')
1008  {
1009  *d = '\0';
1010  return;
1011  }
1012  if (*s == '\\')
1013  {
1014  s++;
1015  }
1016  if (*s)
1017  {
1018  *d = *s;
1019  d++;
1020  s++;
1021  }
1022  }
1023  *d = '\0';
1024 }
1025 
1033 void imap_munge_mbox_name(bool unicode, char *dest, size_t dlen, const char *src)
1034 {
1035  char *buf = mutt_str_strdup(src);
1036  imap_utf_encode(unicode, &buf);
1037 
1038  imap_quote_string(dest, dlen, buf, false);
1039 
1040  FREE(&buf);
1041 }
1042 
1050 void imap_unmunge_mbox_name(bool unicode, char *s)
1051 {
1053 
1054  char *buf = mutt_str_strdup(s);
1055  if (buf)
1056  {
1057  imap_utf_decode(unicode, &buf);
1058  strncpy(s, buf, strlen(s));
1059  }
1060 
1061  FREE(&buf);
1062 }
1063 
1067 void imap_keepalive(void)
1068 {
1069  time_t now = mutt_date_epoch();
1070  struct Account *np = NULL;
1071  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
1072  {
1073  if (np->magic != MUTT_IMAP)
1074  continue;
1075 
1076  struct ImapAccountData *adata = np->adata;
1077  if (!adata || !adata->mailbox)
1078  continue;
1079 
1080  if ((adata->state >= IMAP_AUTHENTICATED) && (now >= (adata->lastread + C_ImapKeepalive)))
1081  imap_check_mailbox(adata->mailbox, true);
1082  }
1083 }
1084 
1090 int imap_wait_keepalive(pid_t pid)
1091 {
1092  struct sigaction oldalrm;
1093  struct sigaction act;
1094  sigset_t oldmask;
1095  int rc;
1096 
1097  bool imap_passive = C_ImapPassive;
1098 
1099  C_ImapPassive = true;
1100  OptKeepQuiet = true;
1101 
1102  sigprocmask(SIG_SETMASK, NULL, &oldmask);
1103 
1104  sigemptyset(&act.sa_mask);
1105  act.sa_handler = mutt_sig_empty_handler;
1106 #ifdef SA_INTERRUPT
1107  act.sa_flags = SA_INTERRUPT;
1108 #else
1109  act.sa_flags = 0;
1110 #endif
1111 
1112  sigaction(SIGALRM, &act, &oldalrm);
1113 
1114  alarm(C_ImapKeepalive);
1115  while ((waitpid(pid, &rc, 0) < 0) && (errno == EINTR))
1116  {
1117  alarm(0); /* cancel a possibly pending alarm */
1118  imap_keepalive();
1119  alarm(C_ImapKeepalive);
1120  }
1121 
1122  alarm(0); /* cancel a possibly pending alarm */
1123 
1124  sigaction(SIGALRM, &oldalrm, NULL);
1125  sigprocmask(SIG_SETMASK, &oldmask, NULL);
1126 
1127  OptKeepQuiet = false;
1128  if (!imap_passive)
1129  C_ImapPassive = false;
1130 
1131  return rc;
1132 }
1133 
1139 {
1140  struct ImapAccountData *adata = imap_adata_get(m);
1141  struct ImapMboxData *mdata = imap_mdata_get(m);
1142  if (!adata || !adata->mailbox || (adata->mailbox != m) || !mdata)
1143  return;
1144  mdata->reopen |= IMAP_REOPEN_ALLOW;
1145 }
1146 
1152 {
1153  struct ImapAccountData *adata = imap_adata_get(m);
1154  struct ImapMboxData *mdata = imap_mdata_get(m);
1155  if (!adata || !adata->mailbox || (adata->mailbox != m) || !mdata)
1156  return;
1157  mdata->reopen &= ~IMAP_REOPEN_ALLOW;
1158 }
1159 
1166 bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
1167 {
1168  if (!a1 || !a2)
1169  return false;
1170  if (a1->type != a2->type)
1171  return false;
1172  if (mutt_str_strcasecmp(a1->host, a2->host) != 0)
1173  return false;
1174  if ((a1->port != 0) && (a2->port != 0) && (a1->port != a2->port))
1175  return false;
1176  if (a1->flags & a2->flags & MUTT_ACCT_USER)
1177  return strcmp(a1->user, a2->user) == 0;
1178 
1179  const char *user = NONULL(Username);
1180 
1181  if ((a1->type == MUTT_ACCT_TYPE_IMAP) && C_ImapUser)
1182  user = C_ImapUser;
1183 
1184  if (a1->flags & MUTT_ACCT_USER)
1185  return strcmp(a1->user, user) == 0;
1186  if (a2->flags & MUTT_ACCT_USER)
1187  return strcmp(a2->user, user) == 0;
1188 
1189  return true;
1190 }
1191 
1197 struct SeqsetIterator *mutt_seqset_iterator_new(const char *seqset)
1198 {
1199  if (!seqset || !*seqset)
1200  return NULL;
1201 
1202  struct SeqsetIterator *iter = mutt_mem_calloc(1, sizeof(struct SeqsetIterator));
1203  iter->full_seqset = mutt_str_strdup(seqset);
1204  iter->eostr = strchr(iter->full_seqset, '\0');
1205  iter->substr_cur = iter->substr_end = iter->full_seqset;
1206 
1207  return iter;
1208 }
1209 
1218 int mutt_seqset_iterator_next(struct SeqsetIterator *iter, unsigned int *next)
1219 {
1220  if (!iter || !next)
1221  return -1;
1222 
1223  if (iter->in_range)
1224  {
1225  if ((iter->down && (iter->range_cur == (iter->range_end - 1))) ||
1226  (!iter->down && (iter->range_cur == (iter->range_end + 1))))
1227  {
1228  iter->in_range = 0;
1229  }
1230  }
1231 
1232  if (!iter->in_range)
1233  {
1234  iter->substr_cur = iter->substr_end;
1235  if (iter->substr_cur == iter->eostr)
1236  return 1;
1237 
1238  while (!*(iter->substr_cur))
1239  iter->substr_cur++;
1240  iter->substr_end = strchr(iter->substr_cur, ',');
1241  if (!iter->substr_end)
1242  iter->substr_end = iter->eostr;
1243  else
1244  *(iter->substr_end) = '\0';
1245 
1246  char *range_sep = strchr(iter->substr_cur, ':');
1247  if (range_sep)
1248  *range_sep++ = '\0';
1249 
1250  if (mutt_str_atoui(iter->substr_cur, &iter->range_cur) != 0)
1251  return -1;
1252  if (range_sep)
1253  {
1254  if (mutt_str_atoui(range_sep, &iter->range_end) != 0)
1255  return -1;
1256  }
1257  else
1258  iter->range_end = iter->range_cur;
1259 
1260  iter->down = (iter->range_end < iter->range_cur);
1261  iter->in_range = 1;
1262  }
1263 
1264  *next = iter->range_cur;
1265  if (iter->down)
1266  iter->range_cur--;
1267  else
1268  iter->range_cur++;
1269 
1270  return 0;
1271 }
1272 
1278 {
1279  if (!ptr || !*ptr)
1280  return;
1281 
1282  struct SeqsetIterator *iter = *ptr;
1283  FREE(&iter->full_seqset);
1284  FREE(ptr);
1285 }
void * mutt_hcache_fetch(header_cache_t *hc, const char *key, size_t keylen)
Multiplexor for HcacheOps::fetch.
Definition: hcache.c:343
void imap_utf_decode(bool unicode, char **s)
Decode email from UTF-8 to local charset.
Definition: utf7.c:345
Convenience wrapper for the gui headers.
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:411
WHERE char * Username
User&#39;s login name.
Definition: globals.h:52
struct ImapCommand * cmds
Definition: imap_private.h:198
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
void imap_unquote_string(char *s)
equally stupid unquoting routine
Definition: util.c:996
void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
Prettify an IMAP mailbox name.
Definition: util.c:706
The envelope/body of an email.
Definition: email.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
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:407
struct Email ** msn_index
look up headers by (MSN-1)
Definition: imap_private.h:234
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2474
struct ConnAccount account
Definition: connection.h:36
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
Structs that make up an email.
void * mutt_hcache_fetch_raw(header_cache_t *hc, const char *key, size_t keylen)
Fetch a message&#39;s header from the cache.
Definition: hcache.c:373
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:100
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:66
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:39
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition: util.c:456
void mutt_sig_empty_handler(int sig)
Dummy signal handler.
Definition: signal.c:57
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:303
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:68
#define IMAP_SSL_PORT
Port for IMAP over SSL/TLS.
Definition: imap_private.h:44
struct ConnAccount conn_account
Definition: imap_private.h:169
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
void imap_mdata_free(void **ptr)
Release and clear storage in an ImapMboxData structure.
Definition: util.c:227
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: imap_private.h:172
struct Email * imap_hcache_get(struct ImapMboxData *mdata, unsigned int uid)
Get a header cache entry by its UID.
Definition: util.c:472
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
Url is imaps://.
Definition: url.h:39
size_t msn_index_size
allocation size
Definition: imap_private.h:235
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: imap_private.h:219
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
A group of associated Mailboxes.
Definition: account.h:36
String manipulation buffer.
Definition: buffer.h:33
char user[128]
Definition: connaccount.h:33
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: imap_private.h:205
WHERE char * C_ImapUser
Config: (imap) Username for the IMAP server.
Definition: globals.h:115
#define IMAP_PORT
Default port for IMAP.
Definition: imap_private.h:43
char * C_ImapDelimChars
Config: (imap) Characters that denote separators in IMAP folders.
Definition: util.c:62
Url is imap://.
Definition: url.h:38
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
int url_tostring(struct Url *u, char *dest, size_t len, int flags)
Output the URL string for a given Url object.
Definition: url.c:399
void imap_clean_path(char *path, size_t plen)
Cleans an IMAP path using imap_fix_path.
Definition: util.c:330
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:115
int mutt_hcache_store_raw(header_cache_t *hc, const char *key, size_t keylen, void *data, size_t dlen)
store a key / data pair
Definition: hcache.c:431
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
int imap_adata_find(const char *path, struct ImapAccountData **adata, struct ImapMboxData **mdata)
Find the Account data for this path.
Definition: util.c:130
WHERE char * C_HeaderCache
Config: (hcache) Directory/file for the header cache database.
Definition: globals.h:121
struct Email * mutt_hcache_restore(const unsigned char *d)
restore an Email from data retrieved from the cache
Definition: serialize.c:634
Container for Accounts, Notifications.
Definition: neomutt.h:35
void imap_unmunge_mbox_name(bool unicode, char *s)
Remove quoting from a mailbox name.
Definition: util.c:1050
void imap_error(const char *where, const char *msg)
show an error and abort
Definition: util.c:778
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
unsigned int max_msn
the largest MSN fetched so far
Definition: imap_private.h:236
Convenience wrapper for the config headers.
void mutt_hcache_close(header_cache_t *hc)
Multiplexor for HcacheOps::close.
Definition: hcache.c:329
unsigned char seqid
Definition: imap_private.h:184
Hundreds of global variables to back the user variables.
void imap_get_parent(const char *mbox, char delim, char *buf, size_t buflen)
Get an IMAP folder&#39;s parent.
Definition: util.c:260
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:246
struct BodyCache * bcache
Definition: imap_private.h:237
char host[128]
Definition: connaccount.h:36
Manage IMAP messages.
header_cache_t * hcache
Definition: imap_private.h:239
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:376
void imap_cachepath(char delim, const char *mailbox, struct Buffer *dest)
Generate a cache path for a mailbox.
Definition: util.c:838
short C_ImapPipelineDepth
Config: (imap) Number of IMAP commands that may be queued up.
Definition: util.c:63
#define STAILQ_INIT(head)
Definition: queue.h:369
void imap_allow_reopen(struct Mailbox *m)
Allow re-opening a folder upon expunge.
Definition: util.c:1138
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:104
int imap_hcache_store_uid_seqset(struct ImapMboxData *mdata)
Store a UID Sequence Set in the header cache.
Definition: util.c:537
unsigned int range_end
Definition: imap_private.h:252
const char * name
Definition: pgpmicalg.c:46
int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
Delete an item from the header cache.
Definition: util.c:520
IMAP network mailbox.
struct Buffer cmdbuf
Definition: imap_private.h:202
Convenience wrapper for the core headers.
#define SKIPWS(ch)
Definition: string2.h:47
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
void * mdata
Driver specific data.
Definition: mailbox.h:135
header_cache_t * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for HcacheOps::open.
Definition: hcache.c:250
int url_tobuffer(struct Url *u, struct Buffer *buf, int flags)
Output the URL string for a given Url object.
Definition: url.c:352
unsigned long long modseq
Definition: imap_private.h:227
int imap_wait_keepalive(pid_t pid)
Wait for a process to change state.
Definition: util.c:1090
void imap_utf_encode(bool unicode, char **s)
Encode email from local charset to UTF-8.
Definition: utf7.c:316
#define mutt_b2s(buf)
Definition: buffer.h:41
unsigned short port
Definition: connaccount.h:37
#define MUTT_ACCT_PORT
Port field has been set.
Definition: mutt_account.h:60
void imap_adata_free(void **ptr)
Release and clear storage in an ImapAccountData structure.
Definition: util.c:69
WHERE short C_ImapKeepalive
Config: (imap) Time to wait before polling an open IMAP connection.
Definition: globals.h:155
int mutt_hcache_delete_header(header_cache_t *hc, const char *key, size_t keylen)
Multiplexor for HcacheOps::delete_header.
Definition: hcache.c:451
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition: util.c:1166
ConnAccount object used by POP and IMAP.
unsigned int uid
32-bit Message UID
Definition: message.h:44
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
A mailbox.
Definition: mailbox.h:80
enum MailboxType magic
Type of Mailboxes this Account contains.
Definition: account.h:38
void imap_disallow_reopen(struct Mailbox *m)
Disallow re-opening a folder upon expunge.
Definition: util.c:1151
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
struct Hash * uid_hash
Definition: imap_private.h:233
struct ListHead flags
Definition: imap_private.h:224
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
char * data
Pointer to data.
Definition: buffer.h:35
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
quote string according to IMAP rules
Definition: util.c:959
int mutt_hcache_store(header_cache_t *hc, const char *key, size_t keylen, struct Email *e, unsigned int uidvalidity)
Multiplexor for HcacheOps::store.
Definition: hcache.c:405
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
int(* conn_close)(struct Connection *conn)
Close a socket Connection.
Definition: connection.h:87
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition: connaccount.h:38
Connection is authenticated.
Definition: imap_private.h:106
char * name
Mailbox name.
Definition: imap_private.h:215
bool mutt_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare account info (host/port/user)
Definition: mutt_account.c:61
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:292
char * imap_get_qualifier(char *buf)
Get the qualifier from a tagged response.
Definition: util.c:894
struct ImapMboxData * imap_mdata_new(struct ImapAccountData *adata, const char *name)
Allocate and initialise a new ImapMboxData structure.
Definition: util.c:166
char * imap_hcache_get_uid_seqset(struct ImapMboxData *mdata)
Get a UID Sequence Set from the header cache.
Definition: util.c:573
void imap_mdata_cache_reset(struct ImapMboxData *mdata)
Release and clear cache data of ImapMboxData structure.
Definition: util.c:214
time_t lastread
last time we read a command for the server
Definition: imap_private.h:186
char * imap_fix_path(char server_delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition: util.c:797
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
Login details for a remote server.
Definition: connaccount.h:31
Imap Account.
Definition: mutt_account.h:52
Body Caching - local copies of email bodies.
char * path
Path.
Definition: url.h:73
char * real_name
Original Mailbox name, e.g.: INBOX can be just \0.
Definition: imap_private.h:217
Header cache multiplexor.
unsigned int uid_validity
Definition: imap_private.h:225
#define IS_SPACE(ch)
Definition: string2.h:38
int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
Add an entry to the header cache.
Definition: util.c:502
int imap_check_mailbox(struct Mailbox *m, bool force)
use the NOOP or IDLE command to poll for new mail
Definition: imap.c:1190
int imap_get_literal_count(const char *buf, unsigned int *bytes)
write number of bytes in an IMAP literal into bytes
Definition: util.c:867
IMAP-specific Account data -.
Definition: imap_private.h:166
unsigned int uid_next
Definition: imap_private.h:226
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:130
Shared constants/structs that are private to IMAP.
int imap_mxcmp(const char *mx1, const char *mx2)
Compare mailbox names, giving priority to INBOX.
Definition: util.c:669
IMAP-specific Mailbox data -.
Definition: imap_private.h:213
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
int mutt_str_strncmp(const char *a, const char *b, size_t l)
Compare two strings (to a maximum), safely.
Definition: string.c:642
header_cache_t * imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata)
Open a header cache.
Definition: util.c:419
int imap_hcache_clear_uid_seqset(struct ImapMboxData *mdata)
Delete a UID Sequence Set from the header cache.
Definition: util.c:559
#define mutt_error(...)
Definition: logging.h:84
struct SeqsetIterator * mutt_seqset_iterator_new(const char *seqset)
Create a new Sequence Set Iterator.
Definition: util.c:1197
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
WHERE bool C_ImapPassive
Config: (imap) Reuse an existing IMAP connection to check for new mail.
Definition: globals.h:225
Connection Library.
char * path
Path of Email (for local Mailboxes)
Definition: email.h:91
void imap_qualify_path(char *buf, size_t buflen, struct ConnAccount *conn_account, char *path)
Make an absolute IMAP folder target.
Definition: util.c:942
void url_free(struct Url **u)
Free the contents of a URL.
Definition: url.c:288
#define FREE(x)
Definition: memory.h:40
#define MUTT_ACCT_SSL
Account uses SSL/TLS.
Definition: mutt_account.h:64
void mutt_account_tourl(struct ConnAccount *account, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:145
void imap_keepalive(void)
poll the current folder to keep the connection alive
Definition: util.c:1067
void mutt_hcache_free(header_cache_t *hc, void **data)
Multiplexor for HcacheOps::free.
Definition: hcache.c:392
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:1033
int mutt_seqset_iterator_next(struct SeqsetIterator *iter, unsigned int *next)
Get the next UID from a Sequence Set.
Definition: util.c:1218
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
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:767
int imap_parse_path(const char *path, struct ConnAccount *account, char *mailbox, size_t mailboxlen)
Parse an IMAP mailbox name into ConnAccount, name.
Definition: util.c:599
static void imap_msn_index_to_uid_seqset(struct Buffer *buf, struct ImapMboxData *mdata)
Convert MSN index of UIDs to Seqset.
Definition: util.c:352
header cache structure
Definition: hcache.h:67
void mutt_seqset_iterator_free(struct SeqsetIterator **ptr)
Free a Sequence Set Iterator.
Definition: util.c:1277
void mutt_hash_free(struct Hash **ptr)
Free a hash table.
Definition: hash.c:471
int mutt_account_fromurl(struct ConnAccount *account, const struct Url *url)
Fill ConnAccount with information from url.
Definition: mutt_account.c:109
WHERE bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program ...
Definition: options.h:37
char * munge_name
Munged version of the mailbox name.
Definition: imap_private.h:216
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:52
char * full_seqset
Definition: imap_private.h:247
struct ImapAccountData * imap_adata_new(void)
Allocate and initialise a new ImapAccountData structure.
Definition: util.c:95
unsigned int range_cur
Definition: imap_private.h:251
void mutt_bcache_close(struct BodyCache **bcache)
Close an Email-Body Cache.
Definition: bcache.c:153
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
Log at debug level 3.
Definition: logging.h:42
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
char * src
Raw URL string.
Definition: url.h:75
UID Sequence Set Iterator.
Definition: imap_private.h:245
#define IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition: imap_private.h:64
#define U_PATH
Definition: url.h:48
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:911
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:39
#define MUTT_ACCT_USER
User field has been set.
Definition: mutt_account.h:61
struct Connection * conn
Definition: imap_private.h:168
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:161