NeoMutt  2020-08-07-1-gab41a1
Teaching an old dog new tricks
DOXYGEN
imap.c
Go to the documentation of this file.
1 
32 #include "config.h"
33 #include <limits.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include "private.h"
39 #include "mutt/lib.h"
40 #include "config/lib.h"
41 #include "email/lib.h"
42 #include "core/lib.h"
43 #include "conn/lib.h"
44 #include "gui/lib.h"
45 #include "mutt.h"
46 #include "lib.h"
47 #include "bcache/lib.h"
48 #include "pattern/lib.h"
49 #include "auth.h"
50 #include "commands.h"
51 #include "hook.h"
52 #include "init.h"
53 #include "message.h"
54 #include "mutt_globals.h"
55 #include "mutt_logging.h"
56 #include "mutt_socket.h"
57 #include "muttlib.h"
58 #include "mx.h"
59 #include "progress.h"
60 #include "sort.h"
61 #ifdef ENABLE_NLS
62 #include <libintl.h>
63 #endif
64 
65 struct stat;
66 
73 static int check_capabilities(struct ImapAccountData *adata)
74 {
75  if (imap_exec(adata, "CAPABILITY", IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
76  {
77  imap_error("check_capabilities", adata->buf);
78  return -1;
79  }
80 
81  if (!((adata->capabilities & IMAP_CAP_IMAP4) || (adata->capabilities & IMAP_CAP_IMAP4REV1)))
82  {
83  mutt_error(
84  _("This IMAP server is ancient. NeoMutt does not work with it."));
85  return -1;
86  }
87 
88  return 0;
89 }
90 
100 static char *get_flags(struct ListHead *hflags, char *s)
101 {
102  /* sanity-check string */
103  const size_t plen = mutt_istr_startswith(s, "FLAGS");
104  if (plen == 0)
105  {
106  mutt_debug(LL_DEBUG1, "not a FLAGS response: %s\n", s);
107  return NULL;
108  }
109  s += plen;
110  SKIPWS(s);
111  if (*s != '(')
112  {
113  mutt_debug(LL_DEBUG1, "bogus FLAGS response: %s\n", s);
114  return NULL;
115  }
116 
117  /* update caller's flags handle */
118  while (*s && (*s != ')'))
119  {
120  s++;
121  SKIPWS(s);
122  const char *flag_word = s;
123  while (*s && (*s != ')') && !IS_SPACE(*s))
124  s++;
125  const char ctmp = *s;
126  *s = '\0';
127  if (*flag_word)
128  mutt_list_insert_tail(hflags, mutt_str_dup(flag_word));
129  *s = ctmp;
130  }
131 
132  /* note bad flags response */
133  if (*s != ')')
134  {
135  mutt_debug(LL_DEBUG1, "Unterminated FLAGS response: %s\n", s);
136  mutt_list_free(hflags);
137 
138  return NULL;
139  }
140 
141  s++;
142 
143  return s;
144 }
145 
155 static void set_flag(struct Mailbox *m, AclFlags aclflag, int flag,
156  const char *str, char *flags, size_t flsize)
157 {
158  if (m->rights & aclflag)
159  if (flag && imap_has_flag(&imap_mdata_get(m)->flags, str))
160  mutt_str_cat(flags, flsize, str);
161 }
162 
176 static int make_msg_set(struct Mailbox *m, struct Buffer *buf, int flag,
177  bool changed, bool invert, int *pos)
178 {
179  int count = 0; /* number of messages in message set */
180  unsigned int setstart = 0; /* start of current message range */
181  int n;
182  bool started = false;
183 
184  struct ImapAccountData *adata = imap_adata_get(m);
185  if (!adata || (adata->mailbox != m))
186  return -1;
187 
188  for (n = *pos; (n < m->msg_count) && (mutt_buffer_len(buf) < IMAP_MAX_CMDLEN); n++)
189  {
190  struct Email *e = m->emails[n];
191  if (!e)
192  break;
193  bool match = false; /* whether current message matches flag condition */
194  /* don't include pending expunged messages.
195  *
196  * TODO: can we unset active in cmd_parse_expunge() and
197  * cmd_parse_vanished() instead of checking for index != INT_MAX. */
198  if (e->active && (e->index != INT_MAX))
199  {
200  switch (flag)
201  {
202  case MUTT_DELETED:
203  if (e->deleted != imap_edata_get(e)->deleted)
204  match = invert ^ e->deleted;
205  break;
206  case MUTT_FLAG:
207  if (e->flagged != imap_edata_get(e)->flagged)
208  match = invert ^ e->flagged;
209  break;
210  case MUTT_OLD:
211  if (e->old != imap_edata_get(e)->old)
212  match = invert ^ e->old;
213  break;
214  case MUTT_READ:
215  if (e->read != imap_edata_get(e)->read)
216  match = invert ^ e->read;
217  break;
218  case MUTT_REPLIED:
219  if (e->replied != imap_edata_get(e)->replied)
220  match = invert ^ e->replied;
221  break;
222  case MUTT_TAG:
223  if (e->tagged)
224  match = true;
225  break;
226  case MUTT_TRASH:
227  if (e->deleted && !e->purge)
228  match = true;
229  break;
230  }
231  }
232 
233  if (match && (!changed || e->changed))
234  {
235  count++;
236  if (setstart == 0)
237  {
238  setstart = imap_edata_get(e)->uid;
239  if (started)
240  {
241  mutt_buffer_add_printf(buf, ",%u", imap_edata_get(e)->uid);
242  }
243  else
244  {
245  mutt_buffer_add_printf(buf, "%u", imap_edata_get(e)->uid);
246  started = true;
247  }
248  }
249  /* tie up if the last message also matches */
250  else if (n == (m->msg_count - 1))
251  mutt_buffer_add_printf(buf, ":%u", imap_edata_get(e)->uid);
252  }
253  /* End current set if message doesn't match or we've reached the end
254  * of the mailbox via inactive messages following the last match. */
255  else if (setstart && (e->active || (n == adata->mailbox->msg_count - 1)))
256  {
257  if (imap_edata_get(m->emails[n - 1])->uid > setstart)
258  mutt_buffer_add_printf(buf, ":%u", imap_edata_get(m->emails[n - 1])->uid);
259  setstart = 0;
260  }
261  }
262 
263  *pos = n;
264 
265  return count;
266 }
267 
276 static bool compare_flags_for_copy(struct Email *e)
277 {
278  struct ImapEmailData *edata = e->edata;
279 
280  if (e->read != edata->read)
281  return true;
282  if (e->old != edata->old)
283  return true;
284  if (e->flagged != edata->flagged)
285  return true;
286  if (e->replied != edata->replied)
287  return true;
288 
289  return false;
290 }
291 
301 static int sync_helper(struct Mailbox *m, AclFlags right, int flag, const char *name)
302 {
303  int count = 0;
304  int rc;
305  char buf[1024];
306 
307  if (!m)
308  return -1;
309 
310  if ((m->rights & right) == 0)
311  return 0;
312 
313  if ((right == MUTT_ACL_WRITE) && !imap_has_flag(&imap_mdata_get(m)->flags, name))
314  return 0;
315 
316  snprintf(buf, sizeof(buf), "+FLAGS.SILENT (%s)", name);
317  rc = imap_exec_msgset(m, "UID STORE", buf, flag, true, false);
318  if (rc < 0)
319  return rc;
320  count += rc;
321 
322  buf[0] = '-';
323  rc = imap_exec_msgset(m, "UID STORE", buf, flag, true, true);
324  if (rc < 0)
325  return rc;
326  count += rc;
327 
328  return count;
329 }
330 
341 static size_t longest_common_prefix(char *dest, const char *src, size_t start, size_t dlen)
342 {
343  size_t pos = start;
344 
345  while ((pos < dlen) && dest[pos] && (dest[pos] == src[pos]))
346  pos++;
347  dest[pos] = '\0';
348 
349  return pos;
350 }
351 
362 static int complete_hosts(char *buf, size_t buflen)
363 {
364  // struct Connection *conn = NULL;
365  int rc = -1;
366  size_t matchlen;
367 
368  matchlen = mutt_str_len(buf);
369  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
371  struct MailboxNode *np = NULL;
372  STAILQ_FOREACH(np, &ml, entries)
373  {
374  if (!mutt_str_startswith(mailbox_path(np->mailbox), buf))
375  continue;
376 
377  if (rc)
378  {
379  mutt_str_copy(buf, mailbox_path(np->mailbox), buflen);
380  rc = 0;
381  }
382  else
383  longest_common_prefix(buf, mailbox_path(np->mailbox), matchlen, buflen);
384  }
386 
387 #if 0
388  TAILQ_FOREACH(conn, mutt_socket_head(), entries)
389  {
390  struct Url url = { 0 };
391  char urlstr[1024];
392 
393  if (conn->account.type != MUTT_ACCT_TYPE_IMAP)
394  continue;
395 
396  mutt_account_tourl(&conn->account, &url);
397  /* FIXME: how to handle multiple users on the same host? */
398  url.user = NULL;
399  url.path = NULL;
400  url_tostring(&url, urlstr, sizeof(urlstr), 0);
401  if (mutt_strn_equal(buf, urlstr, matchlen))
402  {
403  if (rc)
404  {
405  mutt_str_copy(buf, urlstr, buflen);
406  rc = 0;
407  }
408  else
409  longest_common_prefix(buf, urlstr, matchlen, buflen);
410  }
411  }
412 #endif
413 
414  return rc;
415 }
416 
424 int imap_create_mailbox(struct ImapAccountData *adata, char *mailbox)
425 {
426  char buf[2048], mbox[1024];
427 
428  imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), mailbox);
429  snprintf(buf, sizeof(buf), "CREATE %s", mbox);
430 
431  if (imap_exec(adata, buf, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
432  {
433  mutt_error(_("CREATE failed: %s"), imap_cmd_trailer(adata));
434  return -1;
435  }
436 
437  return 0;
438 }
439 
450 int imap_access(const char *path)
451 {
452  if (imap_path_status(path, false) >= 0)
453  return 0;
454  return -1;
455 }
456 
465 int imap_rename_mailbox(struct ImapAccountData *adata, char *oldname, const char *newname)
466 {
467  char oldmbox[1024];
468  char newmbox[1024];
469  int rc = 0;
470 
471  imap_munge_mbox_name(adata->unicode, oldmbox, sizeof(oldmbox), oldname);
472  imap_munge_mbox_name(adata->unicode, newmbox, sizeof(newmbox), newname);
473 
474  struct Buffer *buf = mutt_buffer_pool_get();
475  mutt_buffer_printf(buf, "RENAME %s %s", oldmbox, newmbox);
476 
478  rc = -1;
479 
481 
482  return rc;
483 }
484 
492 int imap_delete_mailbox(struct Mailbox *m, char *path)
493 {
494  char buf[PATH_MAX + 7];
495  char mbox[PATH_MAX];
496  struct Url *url = url_parse(path);
497 
498  struct ImapAccountData *adata = imap_adata_get(m);
499  imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), url->path);
500  url_free(&url);
501  snprintf(buf, sizeof(buf), "DELETE %s", mbox);
503  return -1;
504 
505  return 0;
506 }
507 
512 static void imap_logout(struct ImapAccountData *adata)
513 {
514  /* we set status here to let imap_handle_untagged know we _expect_ to
515  * receive a bye response (so it doesn't freak out and close the conn) */
516  if (adata->state == IMAP_DISCONNECTED)
517  {
518  return;
519  }
520 
521  adata->status = IMAP_BYE;
522  imap_cmd_start(adata, "LOGOUT");
523  if ((C_ImapPollTimeout <= 0) || (mutt_socket_poll(adata->conn, C_ImapPollTimeout) != 0))
524  {
525  while (imap_cmd_step(adata) == IMAP_RES_CONTINUE)
526  ; // do nothing
527  }
528  mutt_socket_close(adata->conn);
529  adata->state = IMAP_DISCONNECTED;
530 }
531 
537 void imap_logout_all(void)
538 {
539  struct Account *np = NULL;
540  TAILQ_FOREACH(np, &NeoMutt->accounts, entries)
541  {
542  if (np->type != MUTT_IMAP)
543  continue;
544 
545  struct ImapAccountData *adata = np->adata;
546  if (!adata)
547  continue;
548 
549  struct Connection *conn = adata->conn;
550  if (!conn || (conn->fd < 0))
551  continue;
552 
553  mutt_message(_("Closing connection to %s..."), conn->account.host);
554  imap_logout(np->adata);
556  }
557 }
558 
573 int imap_read_literal(FILE *fp, struct ImapAccountData *adata,
574  unsigned long bytes, struct Progress *pbar)
575 {
576  char c;
577  bool r = false;
578  struct Buffer buf = { 0 }; // Do not allocate, maybe it won't be used
579 
581  mutt_buffer_alloc(&buf, bytes + 10);
582 
583  mutt_debug(LL_DEBUG2, "reading %ld bytes\n", bytes);
584 
585  for (unsigned long pos = 0; pos < bytes; pos++)
586  {
587  if (mutt_socket_readchar(adata->conn, &c) != 1)
588  {
589  mutt_debug(LL_DEBUG1, "error during read, %ld bytes read\n", pos);
590  adata->status = IMAP_FATAL;
591 
592  mutt_buffer_dealloc(&buf);
593  return -1;
594  }
595 
596  if (r && (c != '\n'))
597  fputc('\r', fp);
598 
599  if (c == '\r')
600  {
601  r = true;
602  continue;
603  }
604  else
605  r = false;
606 
607  fputc(c, fp);
608 
609  if (pbar && !(pos % 1024))
610  mutt_progress_update(pbar, pos, -1);
612  mutt_buffer_addch(&buf, c);
613  }
614 
616  {
617  mutt_debug(IMAP_LOG_LTRL, "\n%s", buf.data);
618  mutt_buffer_dealloc(&buf);
619  }
620  return 0;
621 }
622 
628 void imap_notify_delete_email(struct Mailbox *m, struct Email *e)
629 {
630  struct ImapMboxData *mdata = imap_mdata_get(m);
631  struct ImapEmailData *edata = imap_edata_get(e);
632 
633  if (!mdata || !edata)
634  return;
635 
636  int msn = edata->msn;
637  if ((msn < 1) || (msn > mdata->max_msn))
638  {
639  mutt_debug(LL_DEBUG3, "MSN %d out of range (max %d)\n", msn, mdata->max_msn);
640  return;
641  }
642 
643  mutt_debug(LL_DEBUG3, "Clearing msn_index: value = %p, email = %p\n",
644  mdata->msn_index[msn - 1], e);
645  mdata->msn_index[msn - 1] = NULL;
646  edata->msn = 0;
647 }
648 
658 {
659  struct ImapAccountData *adata = imap_adata_get(m);
660  struct ImapMboxData *mdata = imap_mdata_get(m);
661  if (!adata || !mdata)
662  return;
663 
664  struct Email *e = NULL;
665 
666 #ifdef USE_HCACHE
667  imap_hcache_open(adata, mdata);
668 #endif
669 
670  for (int i = 0; i < m->msg_count; i++)
671  {
672  e = m->emails[i];
673  if (!e)
674  break;
675 
676  if (e->index == INT_MAX)
677  {
678  mutt_debug(LL_DEBUG2, "Expunging message UID %u\n", imap_edata_get(e)->uid);
679 
680  e->deleted = true;
681 
682  imap_cache_del(m, e);
683 #ifdef USE_HCACHE
684  imap_hcache_del(mdata, imap_edata_get(e)->uid);
685 #endif
686 
687  mutt_hash_int_delete(mdata->uid_hash, imap_edata_get(e)->uid, e);
688 
689  imap_edata_free((void **) &e->edata);
690  }
691  else
692  {
693  e->index = i;
694  /* NeoMutt has several places where it turns off e->active as a
695  * hack. For example to avoid FLAG updates, or to exclude from
696  * imap_exec_msgset.
697  *
698  * Unfortunately, when a reopen is allowed and the IMAP_EXPUNGE_PENDING
699  * flag becomes set (e.g. a flag update to a modified header),
700  * this function will be called by imap_cmd_finish().
701  *
702  * The ctx_update_tables() will free and remove these "inactive" headers,
703  * despite that an EXPUNGE was not received for them.
704  * This would result in memory leaks and segfaults due to dangling
705  * pointers in the msn_index and uid_hash.
706  *
707  * So this is another hack to work around the hacks. We don't want to
708  * remove the messages, so make sure active is on. */
709  e->active = true;
710  }
711  }
712 
713 #ifdef USE_HCACHE
714  imap_hcache_close(mdata);
715 #endif
716 
719 }
720 
728 {
729  if (mutt_socket_open(adata->conn) < 0)
730  return -1;
731 
732  adata->state = IMAP_CONNECTED;
733 
734  if (imap_cmd_step(adata) != IMAP_RES_OK)
735  {
736  imap_close_connection(adata);
737  return -1;
738  }
739 
740  if (mutt_istr_startswith(adata->buf, "* OK"))
741  {
742  if (!mutt_istr_startswith(adata->buf, "* OK [CAPABILITY") && check_capabilities(adata))
743  {
744  goto bail;
745  }
746 #ifdef USE_SSL
747  /* Attempt STARTTLS if available and desired. */
748  if ((adata->conn->ssf == 0) && (C_SslForceTls || (adata->capabilities & IMAP_CAP_STARTTLS)))
749  {
750  enum QuadOption ans;
751 
752  if (C_SslForceTls)
753  ans = MUTT_YES;
754  else if ((ans = query_quadoption(C_SslStarttls,
755  _("Secure connection with TLS?"))) == MUTT_ABORT)
756  {
757  goto err_close_conn;
758  }
759  if (ans == MUTT_YES)
760  {
761  enum ImapExecResult rc = imap_exec(adata, "STARTTLS", IMAP_CMD_SINGLE);
762  // Clear any data after the STARTTLS acknowledgement
763  mutt_socket_empty(adata->conn);
764 
765  if (rc == IMAP_EXEC_FATAL)
766  goto bail;
767  if (rc != IMAP_EXEC_ERROR)
768  {
769  if (mutt_ssl_starttls(adata->conn))
770  {
771  mutt_error(_("Could not negotiate TLS connection"));
772  goto err_close_conn;
773  }
774  else
775  {
776  /* RFC2595 demands we recheck CAPABILITY after TLS completes. */
777  if (imap_exec(adata, "CAPABILITY", IMAP_CMD_NO_FLAGS))
778  goto bail;
779  }
780  }
781  }
782  }
783 
784  if (C_SslForceTls && (adata->conn->ssf == 0))
785  {
786  mutt_error(_("Encrypted connection unavailable"));
787  goto err_close_conn;
788  }
789 #endif
790  }
791  else if (mutt_istr_startswith(adata->buf, "* PREAUTH"))
792  {
793 #ifdef USE_SSL
794  /* Unless using a secure $tunnel, an unencrypted PREAUTH response may be a
795  * MITM attack. The only way to stop "STARTTLS" MITM attacks is via
796  * $ssl_force_tls: an attacker can easily spoof "* OK" and strip the
797  * STARTTLS capability. So consult $ssl_force_tls, not $ssl_starttls, to
798  * decide whether to abort. Note that if using $tunnel and
799  * $tunnel_is_secure, adata->conn->ssf will be set to 1. */
800  if ((adata->conn->ssf == 0) && C_SslForceTls)
801  {
802  mutt_error(_("Encrypted connection unavailable"));
803  goto err_close_conn;
804  }
805 #endif
806 
807  adata->state = IMAP_AUTHENTICATED;
808  if (check_capabilities(adata) != 0)
809  goto bail;
810  FREE(&adata->capstr);
811  }
812  else
813  {
814  imap_error("imap_open_connection()", adata->buf);
815  goto bail;
816  }
817 
818  return 0;
819 
820 #ifdef USE_SSL
821 err_close_conn:
822  imap_close_connection(adata);
823 #endif
824 bail:
825  FREE(&adata->capstr);
826  return -1;
827 }
828 
834 {
835  if (adata->state != IMAP_DISCONNECTED)
836  {
837  mutt_socket_close(adata->conn);
838  adata->state = IMAP_DISCONNECTED;
839  }
840  adata->seqno = 0;
841  adata->nextcmd = 0;
842  adata->lastcmd = 0;
843  adata->status = 0;
844  memset(adata->cmds, 0, sizeof(struct ImapCommand) * adata->cmdslots);
845 }
846 
858 bool imap_has_flag(struct ListHead *flag_list, const char *flag)
859 {
860  if (STAILQ_EMPTY(flag_list))
861  return false;
862 
863  const size_t flaglen = mutt_str_len(flag);
864  struct ListNode *np = NULL;
865  STAILQ_FOREACH(np, flag_list, entries)
866  {
867  const size_t nplen = strlen(np->data);
868  if ((flaglen >= nplen) && ((flag[nplen] == '\0') || (flag[nplen] == ' ')) &&
869  mutt_istrn_equal(np->data, flag, nplen))
870  {
871  return true;
872  }
873 
874  if (mutt_str_equal(np->data, "\\*"))
875  return true;
876  }
877 
878  return false;
879 }
880 
884 static int compare_uid(const void *a, const void *b)
885 {
886  const struct Email *ea = *(struct Email const *const *) a;
887  const struct Email *eb = *(struct Email const *const *) b;
888  return imap_edata_get((struct Email *) ea)->uid -
889  imap_edata_get((struct Email *) eb)->uid;
890 }
891 
907 int imap_exec_msgset(struct Mailbox *m, const char *pre, const char *post,
908  int flag, bool changed, bool invert)
909 {
910  struct ImapAccountData *adata = imap_adata_get(m);
911  if (!adata || (adata->mailbox != m))
912  return -1;
913 
914  struct Email **emails = NULL;
915  short oldsort;
916  int pos;
917  int rc;
918  int count = 0;
919 
920  struct Buffer cmd = mutt_buffer_make(0);
921 
922  /* We make a copy of the headers just in case resorting doesn't give
923  exactly the original order (duplicate messages?), because other parts of
924  the ctx are tied to the header order. This may be overkill. */
925  oldsort = C_Sort;
926  if (C_Sort != SORT_ORDER)
927  {
928  emails = m->emails;
929  // We overcommit here, just in case new mail arrives whilst we're sync-ing
930  m->emails = mutt_mem_malloc(m->email_max * sizeof(struct Email *));
931  memcpy(m->emails, emails, m->email_max * sizeof(struct Email *));
932 
933  C_Sort = SORT_ORDER;
934  qsort(m->emails, m->msg_count, sizeof(struct Email *), compare_uid);
935  }
936 
937  pos = 0;
938 
939  do
940  {
941  mutt_buffer_reset(&cmd);
942  mutt_buffer_add_printf(&cmd, "%s ", pre);
943  rc = make_msg_set(m, &cmd, flag, changed, invert, &pos);
944  if (rc > 0)
945  {
946  mutt_buffer_add_printf(&cmd, " %s", post);
947  if (imap_exec(adata, cmd.data, IMAP_CMD_QUEUE) != IMAP_EXEC_SUCCESS)
948  {
949  rc = -1;
950  goto out;
951  }
952  count += rc;
953  }
954  } while (rc > 0);
955 
956  rc = count;
957 
958 out:
959  mutt_buffer_dealloc(&cmd);
960  if (oldsort != C_Sort)
961  {
962  C_Sort = oldsort;
963  FREE(&m->emails);
964  m->emails = emails;
965  }
966 
967  return rc;
968 }
969 
985 int imap_sync_message_for_copy(struct Mailbox *m, struct Email *e,
986  struct Buffer *cmd, enum QuadOption *err_continue)
987 {
988  struct ImapAccountData *adata = imap_adata_get(m);
989  if (!adata || (adata->mailbox != m))
990  return -1;
991 
992  char flags[1024];
993  char *tags = NULL;
994  char uid[11];
995 
996  if (!compare_flags_for_copy(e))
997  {
998  if (e->deleted == imap_edata_get(e)->deleted)
999  e->changed = false;
1000  return 0;
1001  }
1002 
1003  snprintf(uid, sizeof(uid), "%u", imap_edata_get(e)->uid);
1004  mutt_buffer_reset(cmd);
1005  mutt_buffer_addstr(cmd, "UID STORE ");
1006  mutt_buffer_addstr(cmd, uid);
1007 
1008  flags[0] = '\0';
1009 
1010  set_flag(m, MUTT_ACL_SEEN, e->read, "\\Seen ", flags, sizeof(flags));
1011  set_flag(m, MUTT_ACL_WRITE, e->old, "Old ", flags, sizeof(flags));
1012  set_flag(m, MUTT_ACL_WRITE, e->flagged, "\\Flagged ", flags, sizeof(flags));
1013  set_flag(m, MUTT_ACL_WRITE, e->replied, "\\Answered ", flags, sizeof(flags));
1014  set_flag(m, MUTT_ACL_DELETE, imap_edata_get(e)->deleted, "\\Deleted ", flags,
1015  sizeof(flags));
1016 
1017  if (m->rights & MUTT_ACL_WRITE)
1018  {
1019  /* restore system flags */
1020  if (imap_edata_get(e)->flags_system)
1021  mutt_str_cat(flags, sizeof(flags), imap_edata_get(e)->flags_system);
1022  /* set custom flags */
1023  tags = driver_tags_get_with_hidden(&e->tags);
1024  if (tags)
1025  {
1026  mutt_str_cat(flags, sizeof(flags), tags);
1027  FREE(&tags);
1028  }
1029  }
1030 
1032 
1033  /* UW-IMAP is OK with null flags, Cyrus isn't. The only solution is to
1034  * explicitly revoke all system flags (if we have permission) */
1035  if (*flags == '\0')
1036  {
1037  set_flag(m, MUTT_ACL_SEEN, 1, "\\Seen ", flags, sizeof(flags));
1038  set_flag(m, MUTT_ACL_WRITE, 1, "Old ", flags, sizeof(flags));
1039  set_flag(m, MUTT_ACL_WRITE, 1, "\\Flagged ", flags, sizeof(flags));
1040  set_flag(m, MUTT_ACL_WRITE, 1, "\\Answered ", flags, sizeof(flags));
1041  set_flag(m, MUTT_ACL_DELETE, !imap_edata_get(e)->deleted, "\\Deleted ",
1042  flags, sizeof(flags));
1043 
1044  /* erase custom flags */
1045  if ((m->rights & MUTT_ACL_WRITE) && imap_edata_get(e)->flags_remote)
1046  mutt_str_cat(flags, sizeof(flags), imap_edata_get(e)->flags_remote);
1047 
1049 
1050  mutt_buffer_addstr(cmd, " -FLAGS.SILENT (");
1051  }
1052  else
1053  mutt_buffer_addstr(cmd, " FLAGS.SILENT (");
1054 
1055  mutt_buffer_addstr(cmd, flags);
1056  mutt_buffer_addstr(cmd, ")");
1057 
1058  /* after all this it's still possible to have no flags, if you
1059  * have no ACL rights */
1060  if (*flags && (imap_exec(adata, cmd->data, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS) &&
1061  err_continue && (*err_continue != MUTT_YES))
1062  {
1063  *err_continue = imap_continue("imap_sync_message: STORE failed", adata->buf);
1064  if (*err_continue != MUTT_YES)
1065  return -1;
1066  }
1067 
1068  /* server have now the updated flags */
1069  FREE(&imap_edata_get(e)->flags_remote);
1071 
1072  if (e->deleted == imap_edata_get(e)->deleted)
1073  e->changed = false;
1074 
1075  return 0;
1076 }
1077 
1087 int imap_check_mailbox(struct Mailbox *m, bool force)
1088 {
1089  if (!m || !m->account)
1090  return -1;
1091 
1092  struct ImapAccountData *adata = imap_adata_get(m);
1093  struct ImapMboxData *mdata = imap_mdata_get(m);
1094 
1095  /* overload keyboard timeout to avoid many mailbox checks in a row.
1096  * Most users don't like having to wait exactly when they press a key. */
1097  int rc = 0;
1098 
1099  /* try IDLE first, unless force is set */
1100  if (!force && C_ImapIdle && (adata->capabilities & IMAP_CAP_IDLE) &&
1101  ((adata->state != IMAP_IDLE) || (mutt_date_epoch() >= adata->lastread + C_ImapKeepalive)))
1102  {
1103  if (imap_cmd_idle(adata) < 0)
1104  return -1;
1105  }
1106  if (adata->state == IMAP_IDLE)
1107  {
1108  while ((rc = mutt_socket_poll(adata->conn, 0)) > 0)
1109  {
1110  if (imap_cmd_step(adata) != IMAP_RES_CONTINUE)
1111  {
1112  mutt_debug(LL_DEBUG1, "Error reading IDLE response\n");
1113  return -1;
1114  }
1115  }
1116  if (rc < 0)
1117  {
1118  mutt_debug(LL_DEBUG1, "Poll failed, disabling IDLE\n");
1119  adata->capabilities &= ~IMAP_CAP_IDLE; // Clear the flag
1120  }
1121  }
1122 
1123  if ((force || ((adata->state != IMAP_IDLE) &&
1124  (mutt_date_epoch() >= adata->lastread + C_Timeout))) &&
1125  (imap_exec(adata, "NOOP", IMAP_CMD_POLL) != IMAP_EXEC_SUCCESS))
1126  {
1127  return -1;
1128  }
1129 
1130  /* We call this even when we haven't run NOOP in case we have pending
1131  * changes to process, since we can reopen here. */
1132  imap_cmd_finish(adata);
1133 
1134  if (mdata->check_status & IMAP_EXPUNGE_PENDING)
1135  rc = MUTT_REOPENED;
1136  else if (mdata->check_status & IMAP_NEWMAIL_PENDING)
1137  rc = MUTT_NEW_MAIL;
1138  else if (mdata->check_status & IMAP_FLAGS_PENDING)
1139  rc = MUTT_FLAGS;
1140 
1142 
1143  return rc;
1144 }
1145 
1153 static int imap_status(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool queue)
1154 {
1155  char *uidvalidity_flag = NULL;
1156  char cmd[2048];
1157 
1158  if (!adata || !mdata)
1159  return -1;
1160 
1161  /* Don't issue STATUS on the selected mailbox, it will be NOOPed or
1162  * IDLEd elsewhere.
1163  * adata->mailbox may be NULL for connections other than the current
1164  * mailbox's. */
1165  if (adata->mailbox && (adata->mailbox->mdata == mdata))
1166  {
1167  adata->mailbox->has_new = false;
1168  return mdata->messages;
1169  }
1170 
1171  if (adata->capabilities & IMAP_CAP_IMAP4REV1)
1172  uidvalidity_flag = "UIDVALIDITY";
1173  else if (adata->capabilities & IMAP_CAP_STATUS)
1174  uidvalidity_flag = "UID-VALIDITY";
1175  else
1176  {
1177  mutt_debug(LL_DEBUG2, "Server doesn't support STATUS\n");
1178  return -1;
1179  }
1180 
1181  snprintf(cmd, sizeof(cmd), "STATUS %s (UIDNEXT %s UNSEEN RECENT MESSAGES)",
1182  mdata->munge_name, uidvalidity_flag);
1183 
1184  int rc = imap_exec(adata, cmd, queue ? IMAP_CMD_QUEUE : IMAP_CMD_NO_FLAGS | IMAP_CMD_POLL);
1185  if (rc < 0)
1186  {
1187  mutt_debug(LL_DEBUG1, "Error queueing command\n");
1188  return rc;
1189  }
1190  return mdata->messages;
1191 }
1192 
1196 static int imap_mbox_check_stats(struct Mailbox *m, int flags)
1197 {
1198  return imap_mailbox_status(m, true);
1199 }
1200 
1207 int imap_path_status(const char *path, bool queue)
1208 {
1209  struct Mailbox *m = mx_mbox_find2(path);
1210 
1211  const bool is_temp = !m;
1212  if (is_temp)
1213  {
1214  m = mx_path_resolve(path);
1215  if (!mx_mbox_ac_link(m))
1216  {
1217  mailbox_free(&m);
1218  return 0;
1219  }
1220  }
1221 
1222  int rc = imap_mailbox_status(m, queue);
1223 
1224  if (is_temp)
1225  {
1226  mx_ac_remove(m);
1227  }
1228 
1229  return rc;
1230 }
1231 
1241 int imap_mailbox_status(struct Mailbox *m, bool queue)
1242 {
1243  struct ImapAccountData *adata = imap_adata_get(m);
1244  struct ImapMboxData *mdata = imap_mdata_get(m);
1245  if (!adata || !mdata)
1246  return -1;
1247  return imap_status(adata, mdata, queue);
1248 }
1249 
1257 int imap_subscribe(char *path, bool subscribe)
1258 {
1259  struct ImapAccountData *adata = NULL;
1260  struct ImapMboxData *mdata = NULL;
1261  char buf[2048];
1262  struct Buffer err;
1263 
1264  if (imap_adata_find(path, &adata, &mdata) < 0)
1265  return -1;
1266 
1268  {
1269  char mbox[1024];
1270  mutt_buffer_init(&err);
1271  err.dsize = 256;
1272  err.data = mutt_mem_malloc(err.dsize);
1273  size_t len = snprintf(mbox, sizeof(mbox), "%smailboxes ", subscribe ? "" : "un");
1274  imap_quote_string(mbox + len, sizeof(mbox) - len, path, true);
1275  if (mutt_parse_rc_line(mbox, &err))
1276  mutt_debug(LL_DEBUG1, "Error adding subscribed mailbox: %s\n", err.data);
1277  FREE(&err.data);
1278  }
1279 
1280  if (subscribe)
1281  mutt_message(_("Subscribing to %s..."), mdata->name);
1282  else
1283  mutt_message(_("Unsubscribing from %s..."), mdata->name);
1284 
1285  snprintf(buf, sizeof(buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mdata->munge_name);
1286 
1287  if (imap_exec(adata, buf, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1288  {
1289  imap_mdata_free((void *) &mdata);
1290  return -1;
1291  }
1292 
1293  if (subscribe)
1294  mutt_message(_("Subscribed to %s"), mdata->name);
1295  else
1296  mutt_message(_("Unsubscribed from %s"), mdata->name);
1297  imap_mdata_free((void *) &mdata);
1298  return 0;
1299 }
1300 
1312 int imap_complete(char *buf, size_t buflen, const char *path)
1313 {
1314  struct ImapAccountData *adata = NULL;
1315  struct ImapMboxData *mdata = NULL;
1316  char tmp[2048];
1317  struct ImapList listresp = { 0 };
1318  char completion[1024];
1319  int clen;
1320  size_t matchlen = 0;
1321  int completions = 0;
1322  int rc;
1323 
1324  if (imap_adata_find(path, &adata, &mdata) < 0)
1325  {
1326  mutt_str_copy(buf, path, buflen);
1327  return complete_hosts(buf, buflen);
1328  }
1329 
1330  /* fire off command */
1331  snprintf(tmp, sizeof(tmp), "%s \"\" \"%s%%\"",
1332  C_ImapListSubscribed ? "LSUB" : "LIST", mdata->real_name);
1333 
1334  imap_cmd_start(adata, tmp);
1335 
1336  /* and see what the results are */
1337  mutt_str_copy(completion, mdata->name, sizeof(completion));
1338  imap_mdata_free((void *) &mdata);
1339 
1340  adata->cmdresult = &listresp;
1341  do
1342  {
1343  listresp.name = NULL;
1344  rc = imap_cmd_step(adata);
1345 
1346  if ((rc == IMAP_RES_CONTINUE) && listresp.name)
1347  {
1348  /* if the folder isn't selectable, append delimiter to force browse
1349  * to enter it on second tab. */
1350  if (listresp.noselect)
1351  {
1352  clen = strlen(listresp.name);
1353  listresp.name[clen++] = listresp.delim;
1354  listresp.name[clen] = '\0';
1355  }
1356  /* copy in first word */
1357  if (!completions)
1358  {
1359  mutt_str_copy(completion, listresp.name, sizeof(completion));
1360  matchlen = strlen(completion);
1361  completions++;
1362  continue;
1363  }
1364 
1365  matchlen = longest_common_prefix(completion, listresp.name, 0, matchlen);
1366  completions++;
1367  }
1368  } while (rc == IMAP_RES_CONTINUE);
1369  adata->cmdresult = NULL;
1370 
1371  if (completions)
1372  {
1373  /* reformat output */
1374  imap_qualify_path(buf, buflen, &adata->conn->account, completion);
1375  mutt_pretty_mailbox(buf, buflen);
1376  return 0;
1377  }
1378 
1379  return -1;
1380 }
1381 
1390 int imap_fast_trash(struct Mailbox *m, char *dest)
1391 {
1392  char prompt[1024];
1393  int rc = -1;
1394  bool triedcreate = false;
1395  enum QuadOption err_continue = MUTT_NO;
1396 
1397  struct ImapAccountData *adata = imap_adata_get(m);
1398  struct ImapAccountData *dest_adata = NULL;
1399  struct ImapMboxData *dest_mdata = NULL;
1400 
1401  if (imap_adata_find(dest, &dest_adata, &dest_mdata) < 0)
1402  return -1;
1403 
1404  struct Buffer sync_cmd = mutt_buffer_make(0);
1405 
1406  /* check that the save-to folder is in the same account */
1407  if (!imap_account_match(&(adata->conn->account), &(dest_adata->conn->account)))
1408  {
1409  mutt_debug(LL_DEBUG3, "%s not same server as %s\n", dest, mailbox_path(m));
1410  goto out;
1411  }
1412 
1413  for (int i = 0; i < m->msg_count; i++)
1414  {
1415  struct Email *e = m->emails[i];
1416  if (!e)
1417  break;
1418  if (e->active && e->changed && e->deleted && !e->purge)
1419  {
1420  rc = imap_sync_message_for_copy(m, e, &sync_cmd, &err_continue);
1421  if (rc < 0)
1422  {
1423  mutt_debug(LL_DEBUG1, "could not sync\n");
1424  goto out;
1425  }
1426  }
1427  }
1428 
1429  /* loop in case of TRYCREATE */
1430  do
1431  {
1432  rc = imap_exec_msgset(m, "UID COPY", dest_mdata->munge_name, MUTT_TRASH, false, false);
1433  if (rc == 0)
1434  {
1435  mutt_debug(LL_DEBUG1, "No messages to trash\n");
1436  rc = -1;
1437  goto out;
1438  }
1439  else if (rc < 0)
1440  {
1441  mutt_debug(LL_DEBUG1, "could not queue copy\n");
1442  goto out;
1443  }
1444  else if (m->verbose)
1445  {
1446  mutt_message(ngettext("Copying %d message to %s...", "Copying %d messages to %s...", rc),
1447  rc, dest_mdata->name);
1448  }
1449 
1450  /* let's get it on */
1451  rc = imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1452  if (rc == IMAP_EXEC_ERROR)
1453  {
1454  if (triedcreate)
1455  {
1456  mutt_debug(LL_DEBUG1, "Already tried to create mailbox %s\n", dest_mdata->name);
1457  break;
1458  }
1459  /* bail out if command failed for reasons other than nonexistent target */
1460  if (!mutt_istr_startswith(imap_get_qualifier(adata->buf), "[TRYCREATE]"))
1461  break;
1462  mutt_debug(LL_DEBUG3, "server suggests TRYCREATE\n");
1463  snprintf(prompt, sizeof(prompt), _("Create %s?"), dest_mdata->name);
1464  if (C_Confirmcreate && (mutt_yesorno(prompt, MUTT_YES) != MUTT_YES))
1465  {
1466  mutt_clear_error();
1467  goto out;
1468  }
1469  if (imap_create_mailbox(adata, dest_mdata->name) < 0)
1470  break;
1471  triedcreate = true;
1472  }
1473  } while (rc == IMAP_EXEC_ERROR);
1474 
1475  if (rc != IMAP_EXEC_SUCCESS)
1476  {
1477  imap_error("imap_fast_trash", adata->buf);
1478  goto out;
1479  }
1480 
1481  rc = IMAP_EXEC_SUCCESS;
1482 
1483 out:
1484  mutt_buffer_dealloc(&sync_cmd);
1485  imap_mdata_free((void *) &dest_mdata);
1486 
1487  return ((rc == IMAP_EXEC_SUCCESS) ? 0 : -1);
1488 }
1489 
1502 int imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
1503 {
1504  if (!m)
1505  return -1;
1506 
1507  struct Email **emails = NULL;
1508  int oldsort;
1509  int rc;
1510  int check;
1511 
1512  struct ImapAccountData *adata = imap_adata_get(m);
1513  struct ImapMboxData *mdata = imap_mdata_get(m);
1514 
1515  if (adata->state < IMAP_SELECTED)
1516  {
1517  mutt_debug(LL_DEBUG2, "no mailbox selected\n");
1518  return -1;
1519  }
1520 
1521  /* This function is only called when the calling code expects the context
1522  * to be changed. */
1523  imap_allow_reopen(m);
1524 
1525  check = imap_check_mailbox(m, false);
1526  if (check < 0)
1527  return check;
1528 
1529  /* if we are expunging anyway, we can do deleted messages very quickly... */
1530  if (expunge && (m->rights & MUTT_ACL_DELETE))
1531  {
1532  rc = imap_exec_msgset(m, "UID STORE", "+FLAGS.SILENT (\\Deleted)",
1533  MUTT_DELETED, true, false);
1534  if (rc < 0)
1535  {
1536  mutt_error(_("Expunge failed"));
1537  return rc;
1538  }
1539 
1540  if (rc > 0)
1541  {
1542  /* mark these messages as unchanged so second pass ignores them. Done
1543  * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */
1544  for (int i = 0; i < m->msg_count; i++)
1545  {
1546  struct Email *e = m->emails[i];
1547  if (!e)
1548  break;
1549  if (e->deleted && e->changed)
1550  e->active = false;
1551  }
1552  if (m->verbose)
1553  {
1554  mutt_message(ngettext("Marking %d message deleted...",
1555  "Marking %d messages deleted...", rc),
1556  rc);
1557  }
1558  }
1559  }
1560 
1561 #ifdef USE_HCACHE
1562  imap_hcache_open(adata, mdata);
1563 #endif
1564 
1565  /* save messages with real (non-flag) changes */
1566  for (int i = 0; i < m->msg_count; i++)
1567  {
1568  struct Email *e = m->emails[i];
1569  if (!e)
1570  break;
1571 
1572  if (e->deleted)
1573  {
1574  imap_cache_del(m, e);
1575 #ifdef USE_HCACHE
1576  imap_hcache_del(mdata, imap_edata_get(e)->uid);
1577 #endif
1578  }
1579 
1580  if (e->active && e->changed)
1581  {
1582 #ifdef USE_HCACHE
1583  imap_hcache_put(mdata, e);
1584 #endif
1585  /* if the message has been rethreaded or attachments have been deleted
1586  * we delete the message and reupload it.
1587  * This works better if we're expunging, of course. */
1588  /* TODO: why the e->env check? */
1589  if ((e->env && e->env->changed) || e->attach_del)
1590  {
1591  /* L10N: The plural is chosen by the last %d, i.e. the total number */
1592  if (m->verbose)
1593  {
1594  mutt_message(ngettext("Saving changed message... [%d/%d]",
1595  "Saving changed messages... [%d/%d]", m->msg_count),
1596  i + 1, m->msg_count);
1597  }
1598  bool save_append = m->append;
1599  m->append = true;
1600  mutt_save_message_ctx(e, true, false, false, m);
1601  m->append = save_append;
1602  /* TODO: why the check for e->env? Is this possible? */
1603  if (e->env)
1604  e->env->changed = 0;
1605  }
1606  }
1607  }
1608 
1609 #ifdef USE_HCACHE
1610  imap_hcache_close(mdata);
1611 #endif
1612 
1613  /* presort here to avoid doing 10 resorts in imap_exec_msgset */
1614  oldsort = C_Sort;
1615  if (C_Sort != SORT_ORDER)
1616  {
1617  emails = m->emails;
1618  m->emails = mutt_mem_malloc(m->msg_count * sizeof(struct Email *));
1619  memcpy(m->emails, emails, m->msg_count * sizeof(struct Email *));
1620 
1621  C_Sort = SORT_ORDER;
1622  qsort(m->emails, m->msg_count, sizeof(struct Email *), mutt_get_sort_func(SORT_ORDER));
1623  }
1624 
1625  rc = sync_helper(m, MUTT_ACL_DELETE, MUTT_DELETED, "\\Deleted");
1626  if (rc >= 0)
1627  rc |= sync_helper(m, MUTT_ACL_WRITE, MUTT_FLAG, "\\Flagged");
1628  if (rc >= 0)
1629  rc |= sync_helper(m, MUTT_ACL_WRITE, MUTT_OLD, "Old");
1630  if (rc >= 0)
1631  rc |= sync_helper(m, MUTT_ACL_SEEN, MUTT_READ, "\\Seen");
1632  if (rc >= 0)
1633  rc |= sync_helper(m, MUTT_ACL_WRITE, MUTT_REPLIED, "\\Answered");
1634 
1635  if (oldsort != C_Sort)
1636  {
1637  C_Sort = oldsort;
1638  FREE(&m->emails);
1639  m->emails = emails;
1640  }
1641 
1642  /* Flush the queued flags if any were changed in sync_helper. */
1643  if (rc > 0)
1644  if (imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1645  rc = -1;
1646 
1647  if (rc < 0)
1648  {
1649  if (close)
1650  {
1651  if (mutt_yesorno(_("Error saving flags. Close anyway?"), MUTT_NO) == MUTT_YES)
1652  {
1653  adata->state = IMAP_AUTHENTICATED;
1654  return 0;
1655  }
1656  }
1657  else
1658  mutt_error(_("Error saving flags"));
1659  return -1;
1660  }
1661 
1662  /* Update local record of server state to reflect the synchronization just
1663  * completed. imap_read_headers always overwrites hcache-origin flags, so
1664  * there is no need to mutate the hcache after flag-only changes. */
1665  for (int i = 0; i < m->msg_count; i++)
1666  {
1667  struct Email *e = m->emails[i];
1668  if (!e)
1669  break;
1670  struct ImapEmailData *edata = imap_edata_get(e);
1671  edata->deleted = e->deleted;
1672  edata->flagged = e->flagged;
1673  edata->old = e->old;
1674  edata->read = e->read;
1675  edata->replied = e->replied;
1676  e->changed = false;
1677  }
1678  m->changed = false;
1679 
1680  /* We must send an EXPUNGE command if we're not closing. */
1681  if (expunge && !close && (m->rights & MUTT_ACL_DELETE))
1682  {
1683  if (m->verbose)
1684  mutt_message(_("Expunging messages from server..."));
1685  /* Set expunge bit so we don't get spurious reopened messages */
1686  mdata->reopen |= IMAP_EXPUNGE_EXPECTED;
1687  if (imap_exec(adata, "EXPUNGE", IMAP_CMD_NO_FLAGS) != IMAP_EXEC_SUCCESS)
1688  {
1689  mdata->reopen &= ~IMAP_EXPUNGE_EXPECTED;
1690  imap_error(_("imap_sync_mailbox: EXPUNGE failed"), adata->buf);
1691  return -1;
1692  }
1693  mdata->reopen &= ~IMAP_EXPUNGE_EXPECTED;
1694  }
1695 
1696  if (expunge && close)
1697  {
1698  adata->closing = true;
1699  imap_exec(adata, "CLOSE", IMAP_CMD_QUEUE);
1700  adata->state = IMAP_AUTHENTICATED;
1701  }
1702 
1703  if (C_MessageCacheClean)
1704  imap_cache_clean(m);
1705 
1706  return check;
1707 }
1708 
1712 static struct Account *imap_ac_find(struct Account *a, const char *path)
1713 {
1714  if (!a || (a->type != MUTT_IMAP) || !path)
1715  return NULL;
1716 
1717  struct Url *url = url_parse(path);
1718  if (!url)
1719  return NULL;
1720 
1721  struct ImapAccountData *adata = a->adata;
1722  struct ConnAccount *cac = &adata->conn->account;
1723 
1724  if (!mutt_istr_equal(url->host, cac->host))
1725  a = NULL;
1726  else if (url->user && !mutt_istr_equal(url->user, cac->user))
1727  a = NULL;
1728 
1729  url_free(&url);
1730  return a;
1731 }
1732 
1736 static int imap_ac_add(struct Account *a, struct Mailbox *m)
1737 {
1738  if (!a || !m || (m->type != MUTT_IMAP))
1739  return -1;
1740 
1741  struct ImapAccountData *adata = a->adata;
1742 
1743  if (!adata)
1744  {
1745  struct ConnAccount cac = { { 0 } };
1746  char mailbox[PATH_MAX];
1747 
1748  if (imap_parse_path(mailbox_path(m), &cac, mailbox, sizeof(mailbox)) < 0)
1749  return -1;
1750 
1751  adata = imap_adata_new(a);
1752  adata->conn = mutt_conn_new(&cac);
1753  if (!adata->conn)
1754  {
1755  imap_adata_free((void **) &adata);
1756  return -1;
1757  }
1758 
1760 
1761  if (imap_login(adata) < 0)
1762  {
1763  imap_adata_free((void **) &adata);
1764  return -1;
1765  }
1766 
1767  a->adata = adata;
1769  }
1770 
1771  if (!m->mdata)
1772  {
1773  struct Url *url = url_parse(mailbox_path(m));
1774  struct ImapMboxData *mdata = imap_mdata_new(adata, url->path);
1775 
1776  /* fixup path and realpath, mainly to replace / by /INBOX */
1777  char buf[1024];
1778  imap_qualify_path(buf, sizeof(buf), &adata->conn->account, mdata->name);
1779  mutt_buffer_strcpy(&m->pathbuf, buf);
1781 
1782  m->mdata = mdata;
1784  url_free(&url);
1785  }
1786  return 0;
1787 }
1788 
1793 static void imap_mbox_select(struct Mailbox *m)
1794 {
1795  struct ImapAccountData *adata = imap_adata_get(m);
1796  struct ImapMboxData *mdata = imap_mdata_get(m);
1797  if (!adata || !mdata)
1798  return;
1799 
1800  const char *condstore = NULL;
1801 #ifdef USE_HCACHE
1803  condstore = " (CONDSTORE)";
1804  else
1805 #endif
1806  condstore = "";
1807 
1808  char buf[PATH_MAX];
1809  snprintf(buf, sizeof(buf), "%s %s%s", m->readonly ? "EXAMINE" : "SELECT",
1810  mdata->munge_name, condstore);
1811 
1812  adata->state = IMAP_SELECTED;
1813 
1814  imap_cmd_start(adata, buf);
1815 }
1816 
1825 int imap_login(struct ImapAccountData *adata)
1826 {
1827  if (!adata)
1828  return -1;
1829 
1830  if (adata->state == IMAP_DISCONNECTED)
1831  {
1832  mutt_buffer_reset(&adata->cmdbuf); // purge outstanding queued commands
1833  imap_open_connection(adata);
1834  }
1835  if (adata->state == IMAP_CONNECTED)
1836  {
1837  if (imap_authenticate(adata) == IMAP_AUTH_SUCCESS)
1838  {
1839  adata->state = IMAP_AUTHENTICATED;
1840  FREE(&adata->capstr);
1841  if (adata->conn->ssf != 0)
1842  {
1843  mutt_debug(LL_DEBUG2, "Communication encrypted at %d bits\n",
1844  adata->conn->ssf);
1845  }
1846  }
1847  else
1849  }
1850  if (adata->state == IMAP_AUTHENTICATED)
1851  {
1852  /* capabilities may have changed */
1853  imap_exec(adata, "CAPABILITY", IMAP_CMD_PASS);
1854 
1855 #ifdef USE_ZLIB
1856  /* RFC4978 */
1857  if ((adata->capabilities & IMAP_CAP_COMPRESS) && C_ImapDeflate &&
1858  (imap_exec(adata, "COMPRESS DEFLATE", IMAP_CMD_PASS) == IMAP_EXEC_SUCCESS))
1859  {
1860  mutt_debug(LL_DEBUG2, "IMAP compression is enabled on connection to %s\n",
1861  adata->conn->account.host);
1862  mutt_zstrm_wrap_conn(adata->conn);
1863  }
1864 #endif
1865 
1866  /* enable RFC6855, if the server supports that */
1867  if (C_ImapRfc5161 && (adata->capabilities & IMAP_CAP_ENABLE))
1868  imap_exec(adata, "ENABLE UTF8=ACCEPT", IMAP_CMD_QUEUE);
1869 
1870  /* enable QRESYNC. Advertising QRESYNC also means CONDSTORE
1871  * is supported (even if not advertised), so flip that bit. */
1872  if (adata->capabilities & IMAP_CAP_QRESYNC)
1873  {
1874  adata->capabilities |= IMAP_CAP_CONDSTORE;
1876  imap_exec(adata, "ENABLE QRESYNC", IMAP_CMD_QUEUE);
1877  }
1878 
1879  /* get root delimiter, '/' as default */
1880  adata->delim = '/';
1881  imap_exec(adata, "LIST \"\" \"\"", IMAP_CMD_QUEUE);
1882 
1883  /* we may need the root delimiter before we open a mailbox */
1884  imap_exec(adata, NULL, IMAP_CMD_NO_FLAGS);
1885 
1886  /* select the mailbox that used to be open before disconnect */
1887  if (adata->mailbox)
1888  {
1889  imap_mbox_select(adata->mailbox);
1890  }
1891  }
1892 
1893  if (adata->state < IMAP_AUTHENTICATED)
1894  return -1;
1895 
1896  return 0;
1897 }
1898 
1902 static int imap_mbox_open(struct Mailbox *m)
1903 {
1904  if (!m || !m->account || !m->mdata)
1905  return -1;
1906 
1907  char buf[PATH_MAX];
1908  int count = 0;
1909  int rc;
1910 
1911  struct ImapAccountData *adata = imap_adata_get(m);
1912  struct ImapMboxData *mdata = imap_mdata_get(m);
1913 
1914  mutt_debug(LL_DEBUG3, "opening %s, saving %s\n", m->pathbuf.data,
1915  (adata->mailbox ? adata->mailbox->pathbuf.data : "(none)"));
1916  adata->prev_mailbox = adata->mailbox;
1917  adata->mailbox = m;
1918 
1919  /* clear mailbox status */
1920  adata->status = 0;
1921  m->rights = 0;
1922  mdata->new_mail_count = 0;
1923 
1924  if (m->verbose)
1925  mutt_message(_("Selecting %s..."), mdata->name);
1926 
1927  /* pipeline ACL test */
1928  if (adata->capabilities & IMAP_CAP_ACL)
1929  {
1930  snprintf(buf, sizeof(buf), "MYRIGHTS %s", mdata->munge_name);
1931  imap_exec(adata, buf, IMAP_CMD_QUEUE);
1932  }
1933  /* assume we have all rights if ACL is unavailable */
1934  else
1935  {
1938  }
1939 
1940  /* pipeline the postponed count if possible */
1941  struct Mailbox *m_postponed = mx_mbox_find2(C_Postponed);
1942  struct ImapAccountData *postponed_adata = imap_adata_get(m_postponed);
1943  if (postponed_adata &&
1944  imap_account_match(&postponed_adata->conn->account, &adata->conn->account))
1945  {
1946  imap_mailbox_status(m_postponed, true);
1947  }
1948 
1950  imap_exec(adata, "LSUB \"\" \"*\"", IMAP_CMD_QUEUE);
1951 
1952  imap_mbox_select(m);
1953 
1954  do
1955  {
1956  char *pc = NULL;
1957 
1958  rc = imap_cmd_step(adata);
1959  if (rc != IMAP_RES_CONTINUE)
1960  break;
1961 
1962  pc = adata->buf + 2;
1963 
1964  /* Obtain list of available flags here, may be overridden by a
1965  * PERMANENTFLAGS tag in the OK response */
1966  if (mutt_istr_startswith(pc, "FLAGS"))
1967  {
1968  /* don't override PERMANENTFLAGS */
1969  if (STAILQ_EMPTY(&mdata->flags))
1970  {
1971  mutt_debug(LL_DEBUG3, "Getting mailbox FLAGS\n");
1972  pc = get_flags(&mdata->flags, pc);
1973  if (!pc)
1974  goto fail;
1975  }
1976  }
1977  /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
1978  else if (mutt_istr_startswith(pc, "OK [PERMANENTFLAGS"))
1979  {
1980  mutt_debug(LL_DEBUG3, "Getting mailbox PERMANENTFLAGS\n");
1981  /* safe to call on NULL */
1982  mutt_list_free(&mdata->flags);
1983  /* skip "OK [PERMANENT" so syntax is the same as FLAGS */
1984  pc += 13;
1985  pc = get_flags(&(mdata->flags), pc);
1986  if (!pc)
1987  goto fail;
1988  }
1989  /* save UIDVALIDITY for the header cache */
1990  else if (mutt_istr_startswith(pc, "OK [UIDVALIDITY"))
1991  {
1992  mutt_debug(LL_DEBUG3, "Getting mailbox UIDVALIDITY\n");
1993  pc += 3;
1994  pc = imap_next_word(pc);
1995  if (mutt_str_atoui(pc, &mdata->uidvalidity) < 0)
1996  goto fail;
1997  }
1998  else if (mutt_istr_startswith(pc, "OK [UIDNEXT"))
1999  {
2000  mutt_debug(LL_DEBUG3, "Getting mailbox UIDNEXT\n");
2001  pc += 3;
2002  pc = imap_next_word(pc);
2003  if (mutt_str_atoui(pc, &mdata->uid_next) < 0)
2004  goto fail;
2005  }
2006  else if (mutt_istr_startswith(pc, "OK [HIGHESTMODSEQ"))
2007  {
2008  mutt_debug(LL_DEBUG3, "Getting mailbox HIGHESTMODSEQ\n");
2009  pc += 3;
2010  pc = imap_next_word(pc);
2011  if (mutt_str_atoull(pc, &mdata->modseq) < 0)
2012  goto fail;
2013  }
2014  else if (mutt_istr_startswith(pc, "OK [NOMODSEQ"))
2015  {
2016  mutt_debug(LL_DEBUG3, "Mailbox has NOMODSEQ set\n");
2017  mdata->modseq = 0;
2018  }
2019  else
2020  {
2021  pc = imap_next_word(pc);
2022  if (mutt_istr_startswith(pc, "EXISTS"))
2023  {
2024  count = mdata->new_mail_count;
2025  mdata->new_mail_count = 0;
2026  }
2027  }
2028  } while (rc == IMAP_RES_CONTINUE);
2029 
2030  if (rc == IMAP_RES_NO)
2031  {
2032  char *s = imap_next_word(adata->buf); /* skip seq */
2033  s = imap_next_word(s); /* Skip response */
2034  mutt_error("%s", s);
2035  goto fail;
2036  }
2037 
2038  if (rc != IMAP_RES_OK)
2039  goto fail;
2040 
2041  /* check for READ-ONLY notification */
2042  if (mutt_istr_startswith(imap_get_qualifier(adata->buf), "[READ-ONLY]") &&
2043  !(adata->capabilities & IMAP_CAP_ACL))
2044  {
2045  mutt_debug(LL_DEBUG2, "Mailbox is read-only\n");
2046  m->readonly = true;
2047  }
2048 
2049  /* dump the mailbox flags we've found */
2050  if (C_DebugLevel > LL_DEBUG2)
2051  {
2052  if (STAILQ_EMPTY(&mdata->flags))
2053  mutt_debug(LL_DEBUG3, "No folder flags found\n");
2054  else
2055  {
2056  struct ListNode *np = NULL;
2057  struct Buffer flag_buffer;
2058  mutt_buffer_init(&flag_buffer);
2059  mutt_buffer_printf(&flag_buffer, "Mailbox flags: ");
2060  STAILQ_FOREACH(np, &mdata->flags, entries)
2061  {
2062  mutt_buffer_add_printf(&flag_buffer, "[%s] ", np->data);
2063  }
2064  mutt_debug(LL_DEBUG3, "%s\n", flag_buffer.data);
2065  FREE(&flag_buffer.data);
2066  }
2067  }
2068 
2069  if (!((m->rights & MUTT_ACL_DELETE) || (m->rights & MUTT_ACL_SEEN) ||
2070  (m->rights & MUTT_ACL_WRITE) || (m->rights & MUTT_ACL_INSERT)))
2071  {
2072  m->readonly = true;
2073  }
2074 
2075  while (m->email_max < count)
2076  mx_alloc_memory(m);
2077 
2078  m->msg_count = 0;
2079  m->msg_unread = 0;
2080  m->msg_flagged = 0;
2081  m->msg_new = 0;
2082  m->msg_deleted = 0;
2083  m->size = 0;
2084  m->vcount = 0;
2085 
2086  if (count && (imap_read_headers(m, 1, count, true) < 0))
2087  {
2088  mutt_error(_("Error opening mailbox"));
2089  goto fail;
2090  }
2091 
2092  mutt_debug(LL_DEBUG2, "msg_count is %d\n", m->msg_count);
2093  return 0;
2094 
2095 fail:
2096  if (adata->state == IMAP_SELECTED)
2097  adata->state = IMAP_AUTHENTICATED;
2098  return -1;
2099 }
2100 
2104 static int imap_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
2105 {
2106  if (!m || !m->account)
2107  return -1;
2108 
2109  /* in APPEND mode, we appear to hijack an existing IMAP connection -
2110  * ctx is brand new and mostly empty */
2111  struct ImapAccountData *adata = imap_adata_get(m);
2112  struct ImapMboxData *mdata = imap_mdata_get(m);
2113 
2114  int rc = imap_mailbox_status(m, false);
2115  if (rc >= 0)
2116  return 0;
2117  if (rc == -1)
2118  return -1;
2119 
2120  char buf[PATH_MAX + 64];
2121  snprintf(buf, sizeof(buf), _("Create %s?"), mdata->name);
2122  if (C_Confirmcreate && (mutt_yesorno(buf, MUTT_YES) != MUTT_YES))
2123  return -1;
2124 
2125  if (imap_create_mailbox(adata, mdata->name) < 0)
2126  return -1;
2127 
2128  return 0;
2129 }
2130 
2137 static int imap_mbox_check(struct Mailbox *m)
2138 {
2139  if (!m)
2140  return -1;
2141 
2142  imap_allow_reopen(m);
2143  int rc = imap_check_mailbox(m, false);
2144  /* NOTE - ctx might have been changed at this point. In particular,
2145  * m could be NULL. Beware. */
2147 
2148  return rc;
2149 }
2150 
2154 static int imap_mbox_close(struct Mailbox *m)
2155 {
2156  if (!m)
2157  return -1;
2158 
2159  struct ImapAccountData *adata = imap_adata_get(m);
2160  struct ImapMboxData *mdata = imap_mdata_get(m);
2161 
2162  /* Check to see if the mailbox is actually open */
2163  if (!adata || !mdata)
2164  return 0;
2165 
2166  /* imap_mbox_open_append() borrows the struct ImapAccountData temporarily,
2167  * just for the connection.
2168  *
2169  * So when these are equal, it means we are actually closing the
2170  * mailbox and should clean up adata. Otherwise, we don't want to
2171  * touch adata - it's still being used. */
2172  if (m == adata->mailbox)
2173  {
2174  if ((adata->status != IMAP_FATAL) && (adata->state >= IMAP_SELECTED))
2175  {
2176  /* mx_mbox_close won't sync if there are no deleted messages
2177  * and the mailbox is unchanged, so we may have to close here */
2178  if (m->msg_deleted == 0)
2179  {
2180  adata->closing = true;
2181  imap_exec(adata, "CLOSE", IMAP_CMD_QUEUE);
2182  }
2183  adata->state = IMAP_AUTHENTICATED;
2184  }
2185 
2186  mutt_debug(LL_DEBUG3, "closing %s, restoring %s\n", m->pathbuf.data,
2187  (adata->prev_mailbox ? adata->prev_mailbox->pathbuf.data : "(none)"));
2188  adata->mailbox = adata->prev_mailbox;
2191  }
2192 
2193  return 0;
2194 }
2195 
2199 static int imap_msg_open_new(struct Mailbox *m, struct Message *msg, struct Email *e)
2200 {
2201  int rc = -1;
2202 
2203  struct Buffer *tmp = mutt_buffer_pool_get();
2204  mutt_buffer_mktemp(tmp);
2205 
2206  msg->fp = mutt_file_fopen(mutt_b2s(tmp), "w");
2207  if (!msg->fp)
2208  {
2209  mutt_perror(mutt_b2s(tmp));
2210  goto cleanup;
2211  }
2212 
2213  msg->path = mutt_buffer_strdup(tmp);
2214  rc = 0;
2215 
2216 cleanup:
2218  return rc;
2219 }
2220 
2224 static int imap_tags_edit(struct Mailbox *m, const char *tags, char *buf, size_t buflen)
2225 {
2226  struct ImapMboxData *mdata = imap_mdata_get(m);
2227  if (!mdata)
2228  return -1;
2229 
2230  char *new_tag = NULL;
2231  char *checker = NULL;
2232 
2233  /* Check for \* flags capability */
2234  if (!imap_has_flag(&mdata->flags, NULL))
2235  {
2236  mutt_error(_("IMAP server doesn't support custom flags"));
2237  return -1;
2238  }
2239 
2240  *buf = '\0';
2241  if (tags)
2242  mutt_str_copy(buf, tags, buflen);
2243 
2244  if (mutt_get_field("Tags: ", buf, buflen, MUTT_COMP_NO_FLAGS) != 0)
2245  return -1;
2246 
2247  /* each keyword must be atom defined by rfc822 as:
2248  *
2249  * atom = 1*<any CHAR except specials, SPACE and CTLs>
2250  * CHAR = ( 0.-127. )
2251  * specials = "(" / ")" / "<" / ">" / "@"
2252  * / "," / ";" / ":" / "\" / <">
2253  * / "." / "[" / "]"
2254  * SPACE = ( 32. )
2255  * CTLS = ( 0.-31., 127.)
2256  *
2257  * And must be separated by one space.
2258  */
2259 
2260  new_tag = buf;
2261  checker = buf;
2262  SKIPWS(checker);
2263  while (*checker != '\0')
2264  {
2265  if ((*checker < 32) || (*checker >= 127) || // We allow space because it's the separator
2266  (*checker == 40) || // (
2267  (*checker == 41) || // )
2268  (*checker == 60) || // <
2269  (*checker == 62) || // >
2270  (*checker == 64) || // @
2271  (*checker == 44) || // ,
2272  (*checker == 59) || // ;
2273  (*checker == 58) || // :
2274  (*checker == 92) || // backslash
2275  (*checker == 34) || // "
2276  (*checker == 46) || // .
2277  (*checker == 91) || // [
2278  (*checker == 93)) // ]
2279  {
2280  mutt_error(_("Invalid IMAP flags"));
2281  return 0;
2282  }
2283 
2284  /* Skip duplicate space */
2285  while ((checker[0] == ' ') && (checker[1] == ' '))
2286  checker++;
2287 
2288  /* copy char to new_tag and go the next one */
2289  *new_tag++ = *checker++;
2290  }
2291  *new_tag = '\0';
2292  new_tag = buf; /* rewind */
2293  mutt_str_remove_trailing_ws(new_tag);
2294 
2295  return !mutt_str_equal(tags, buf);
2296 }
2297 
2311 static int imap_tags_commit(struct Mailbox *m, struct Email *e, char *buf)
2312 {
2313  if (!m)
2314  return -1;
2315 
2316  char uid[11];
2317 
2318  struct ImapAccountData *adata = imap_adata_get(m);
2319 
2320  if (*buf == '\0')
2321  buf = NULL;
2322 
2323  if (!(adata->mailbox->rights & MUTT_ACL_WRITE))
2324  return 0;
2325 
2326  snprintf(uid, sizeof(uid), "%u", imap_edata_get(e)->uid);
2327 
2328  /* Remove old custom flags */
2329  if (imap_edata_get(e)->flags_remote)
2330  {
2331  struct Buffer cmd = mutt_buffer_make(128); // just a guess
2332  mutt_buffer_addstr(&cmd, "UID STORE ");
2333  mutt_buffer_addstr(&cmd, uid);
2334  mutt_buffer_addstr(&cmd, " -FLAGS.SILENT (");
2335  mutt_buffer_addstr(&cmd, imap_edata_get(e)->flags_remote);
2336  mutt_buffer_addstr(&cmd, ")");
2337 
2338  /* Should we return here, or we are fine and we could
2339  * continue to add new flags */
2340  int rc = imap_exec(adata, cmd.data, IMAP_CMD_NO_FLAGS);
2341  mutt_buffer_dealloc(&cmd);
2342  if (rc != IMAP_EXEC_SUCCESS)
2343  {
2344  return -1;
2345  }
2346  }
2347 
2348  /* Add new custom flags */
2349  if (buf)
2350  {
2351  struct Buffer cmd = mutt_buffer_make(128); // just a guess
2352  mutt_buffer_addstr(&cmd, "UID STORE ");
2353  mutt_buffer_addstr(&cmd, uid);
2354  mutt_buffer_addstr(&cmd, " +FLAGS.SILENT (");
2355  mutt_buffer_addstr(&cmd, buf);
2356  mutt_buffer_addstr(&cmd, ")");
2357 
2358  int rc = imap_exec(adata, cmd.data, IMAP_CMD_NO_FLAGS);
2359  mutt_buffer_dealloc(&cmd);
2360  if (rc != IMAP_EXEC_SUCCESS)
2361  {
2362  mutt_debug(LL_DEBUG1, "fail to add new flags\n");
2363  return -1;
2364  }
2365  }
2366 
2367  /* We are good sync them */
2368  mutt_debug(LL_DEBUG1, "NEW TAGS: %s\n", buf);
2369  driver_tags_replace(&e->tags, buf);
2370  FREE(&imap_edata_get(e)->flags_remote);
2372  return 0;
2373 }
2374 
2378 enum MailboxType imap_path_probe(const char *path, const struct stat *st)
2379 {
2380  if (!path)
2381  return MUTT_UNKNOWN;
2382 
2383  if (mutt_istr_startswith(path, "imap://"))
2384  return MUTT_IMAP;
2385 
2386  if (mutt_istr_startswith(path, "imaps://"))
2387  return MUTT_IMAP;
2388 
2389  return MUTT_UNKNOWN;
2390 }
2391 
2395 int imap_path_canon(char *buf, size_t buflen)
2396 {
2397  if (!buf)
2398  return -1;
2399 
2400  struct Url *url = url_parse(buf);
2401  if (!url)
2402  return 0;
2403 
2404  char tmp[PATH_MAX];
2405  char tmp2[PATH_MAX];
2406 
2407  imap_fix_path('\0', url->path, tmp, sizeof(tmp));
2408  url->path = tmp;
2409  url_tostring(url, tmp2, sizeof(tmp2), 0);
2410  mutt_str_copy(buf, tmp2, buflen);
2411  url_free(&url);
2412 
2413  return 0;
2414 }
2415 
2424 int imap_expand_path(struct Buffer *buf)
2425 {
2427  return imap_path_canon(buf->data, PATH_MAX);
2428 }
2429 
2433 static int imap_path_pretty(char *buf, size_t buflen, const char *folder)
2434 {
2435  if (!buf || !folder)
2436  return -1;
2437 
2438  imap_pretty_mailbox(buf, buflen, folder);
2439  return 0;
2440 }
2441 
2445 static int imap_path_parent(char *buf, size_t buflen)
2446 {
2447  char tmp[PATH_MAX] = { 0 };
2448 
2449  imap_get_parent_path(buf, tmp, sizeof(tmp));
2450  mutt_str_copy(buf, tmp, buflen);
2451  return 0;
2452 }
2453 
2454 // clang-format off
2458 struct MxOps MxImapOps = {
2459  .type = MUTT_IMAP,
2460  .name = "imap",
2461  .is_local = false,
2462  .ac_find = imap_ac_find,
2463  .ac_add = imap_ac_add,
2464  .mbox_open = imap_mbox_open,
2465  .mbox_open_append = imap_mbox_open_append,
2466  .mbox_check = imap_mbox_check,
2467  .mbox_check_stats = imap_mbox_check_stats,
2468  .mbox_sync = NULL, /* imap syncing is handled by imap_sync_mailbox */
2469  .mbox_close = imap_mbox_close,
2470  .msg_open = imap_msg_open,
2471  .msg_open_new = imap_msg_open_new,
2472  .msg_commit = imap_msg_commit,
2473  .msg_close = imap_msg_close,
2474  .msg_padding_size = NULL,
2475  .msg_save_hcache = imap_msg_save_hcache,
2476  .tags_edit = imap_tags_edit,
2477  .tags_commit = imap_tags_commit,
2478  .path_probe = imap_path_probe,
2479  .path_canon = imap_path_canon,
2480  .path_pretty = imap_path_pretty,
2481  .path_parent = imap_path_parent,
2482 };
2483 // clang-format on
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
void imap_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: util.c:226
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
Convenience wrapper for the gui headers.
void imap_adata_free(void **ptr)
Free the private Account data - Implements Account::adata_free()
Definition: util.c:65
#define IMAP_CAP_COMPRESS
RFC4978: COMPRESS=DEFLATE.
Definition: private.h:139
int mutt_save_message_ctx(struct Email *e, bool delete_original, bool decode, bool decrypt, struct Mailbox *m)
Save a message to a given mailbox.
Definition: commands.c:998
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:416
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:787
Deleted messages.
Definition: mutt.h:101
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:201
void mutt_zstrm_wrap_conn(struct Connection *conn)
Wrap a compression layer around a Connection.
Definition: zstrm.c:288
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition: message.c:98
struct ImapCommand * cmds
Definition: private.h:199
void imap_qualify_path(char *buf, size_t buflen, struct ConnAccount *conn_account, char *path)
Make an absolute IMAP folder target.
Definition: util.c:954
#define IMAP_CAP_IMAP4
Server supports IMAP4.
Definition: private.h:122
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
int msg_count
Total number of messages.
Definition: mailbox.h:91
int imap_msg_save_hcache(struct Mailbox *m, struct Email *e)
Save message to the header cache - Implements MxOps::msg_save_hcache()
Definition: message.c:2107
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
void imap_disallow_reopen(struct Mailbox *m)
Disallow re-opening a folder upon expunge.
Definition: util.c:1163
off_t size
Size of the Mailbox.
Definition: mailbox.h:87
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:55
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
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
void imap_mdata_cache_reset(struct ImapMboxData *mdata)
Release and clear cache data of ImapMboxData structure.
Definition: util.c:214
int imap_path_status(const char *path, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1207
Logged out from server.
Definition: private.h:97
#define mutt_perror(...)
Definition: logging.h:85
if(!test_colorize_)
Definition: acutest.h:499
struct Email ** msn_index
look up headers by (MSN-1)
Definition: private.h:237
bool C_MessageCacheClean
Config: (imap/pop) Clean out obsolete entries from the message cache.
Definition: bcache.c:44
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2378
Config/command parsing.
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
uint32_t uidvalidity
Definition: private.h:228
Imap connection failure.
Definition: private.h:85
Update internal tables.
Definition: mailbox.h:174
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:96
unsigned int ssf
Security strength factor, in bits (see below)
Definition: connection.h:37
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
Structs that make up an email.
#define MUTT_ACL_READ
Read the mailbox.
Definition: mailbox.h:72
int imap_open_connection(struct ImapAccountData *adata)
Open an IMAP connection.
Definition: imap.c:727
static int imap_tags_edit(struct Mailbox *m, const char *tags, char *buf, size_t buflen)
Prompt and validate new messages tags - Implements MxOps::tags_edit()
Definition: imap.c:2224
WHERE short C_Timeout
Config: Time to wait for user input in menus.
Definition: mutt_globals.h:116
Connection is authenticated.
Definition: private.h:108
User aborted the question (with Ctrl-G)
Definition: quad.h:38
#define mutt_message(...)
Definition: logging.h:83
static int sync_helper(struct Mailbox *m, AclFlags right, int flag, const char *name)
Sync flag changes to the server.
Definition: imap.c:301
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:93
int imap_delete_mailbox(struct Mailbox *m, char *path)
Delete a mailbox.
Definition: imap.c:492
unsigned int seqno
tag sequence number, e.g. &#39;{seqid}0001&#39;
Definition: private.h:187
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:40
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:137
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
Unrecoverable error occurred.
Definition: private.h:96
int imap_login(struct ImapAccountData *adata)
Open an IMAP connection.
Definition: imap.c:1825
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:618
int imap_hcache_put(struct ImapMboxData *mdata, struct Email *e)
Add an entry to the header cache.
Definition: util.c:516
void imap_expunge_mailbox(struct Mailbox *m)
Purge messages from the server.
Definition: imap.c:657
#define IMAP_CAP_ENABLE
RFC5161.
Definition: private.h:135
#define MUTT_ACL_CREATE
Create a mailbox.
Definition: mailbox.h:65
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
Delete an item from the header cache.
Definition: util.c:534
static int imap_status(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1153
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:1045
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition: private.h:174
struct ImapAccountData * imap_adata_new(struct Account *a)
Allocate and initialise a new ImapAccountData structure.
Definition: util.c:91
#define IMAP_FLAGS_PENDING
Flags have changed on the server.
Definition: private.h:69
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
Match any Mailbox type.
Definition: mailbox.h:45
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:160
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition: private.h:222
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
char * mutt_buffer_strdup(struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
A group of associated Mailboxes.
Definition: account.h:36
int imap_cache_del(struct Mailbox *m, struct Email *e)
Delete an email from the body cache.
Definition: message.c:1773
bool C_ImapRfc5161
Config: (imap) Use the IMAP ENABLE extension to select capabilities.
Definition: config.c:56
An open network connection (socket)
Definition: connection.h:34
String manipulation buffer.
Definition: buffer.h:33
#define MUTT_ACL_INSERT
Add/copy into the mailbox (used when editing a message)
Definition: mailbox.h:69
static void imap_logout(struct ImapAccountData *adata)
Gracefully log out of server.
Definition: imap.c:512
#define IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition: private.h:75
char user[128]
Username.
Definition: connaccount.h:55
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:1041
static int imap_msg_open_new(struct Mailbox *m, struct Message *msg, struct Email *e)
Open a new message in a Mailbox - Implements MxOps::msg_open_new()
Definition: imap.c:2199
Flagged messages.
Definition: mutt.h:102
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1232
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
IMAP authenticator multiplexor.
int imap_rename_mailbox(struct ImapAccountData *adata, char *oldname, const char *newname)
Rename a mailbox.
Definition: imap.c:465
int imap_msg_close(struct Mailbox *m, struct Message *msg)
Close an email - Implements MxOps::msg_close()
Definition: message.c:2099
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
static int make_msg_set(struct Mailbox *m, struct Buffer *buf, int flag, bool changed, bool invert, int *pos)
Make a message set.
Definition: imap.c:176
struct Mailbox * mailbox
Current selected mailbox.
Definition: private.h:206
const char * imap_cmd_trailer(struct ImapAccountData *adata)
Extra information after tagged command response if any.
Definition: command.c:1210
bool changed
Email has been edited.
Definition: email.h:48
static int imap_path_parent(char *buf, size_t buflen)
Find the parent of a Mailbox path - Implements MxOps::path_parent()
Definition: imap.c:2445
void imap_close_connection(struct ImapAccountData *adata)
Close an IMAP connection.
Definition: imap.c:833
void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
Prettify an IMAP mailbox name.
Definition: util.c:725
char * capstr
Definition: private.h:184
static int imap_mbox_open(struct Mailbox *m)
Open a mailbox - Implements MxOps::mbox_open()
Definition: imap.c:1902
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition: util.c:245
Items in an IMAP browser.
Definition: private.h:147
ImapExecResult
imap_exec return code
Definition: private.h:81
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mx.h:51
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition: util.c:1178
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1062
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:38
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1669
int imap_read_literal(FILE *fp, struct ImapAccountData *adata, unsigned long bytes, struct Progress *pbar)
Read bytes bytes from server into file.
Definition: imap.c:573
char delim
Definition: private.h:150
unsigned int msn
Message Sequence Number.
Definition: message.h:45
#define IMAP_CAP_STARTTLS
RFC2595: STARTTLS.
Definition: private.h:131
Container for Accounts, Notifications.
Definition: neomutt.h:36
A progress bar.
Definition: progress.h:50
bool C_ImapCondstore
Config: (imap) Enable the CONDSTORE extension.
Definition: config.c:38
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:66
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
static char * get_flags(struct ListHead *hflags, char *s)
Make a simple list out of a FLAGS response.
Definition: imap.c:100
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
Messages that have been replied to.
Definition: mutt.h:95
int vcount
The number of virtual messages.
Definition: mailbox.h:102
unsigned int max_msn
the largest MSN fetched so far
Definition: private.h:239
Imap command executed or queued successfully.
Definition: private.h:83
Convenience wrapper for the config headers.
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:79
#define IMAP_MAX_CMDLEN
Maximum length of command lines before they must be split (for lazy servers)
Definition: private.h:61
int mutt_socket_readchar(struct Connection *conn, char *c)
simple read buffering to speed things up
Definition: socket.c:209
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
Definition: socket.c:75
unsigned int new_mail_count
Set when EXISTS notifies of new mail.
Definition: private.h:224
int imap_sync_mailbox(struct Mailbox *m, bool expunge, bool close)
Sync all the changes to the server.
Definition: imap.c:1502
bool flagged
Definition: message.h:39
void imap_logout_all(void)
close all open connections
Definition: imap.c:537
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
bool mutt_istrn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:626
char host[128]
Server to login to.
Definition: connaccount.h:53
void(* mdata_free)(void **ptr)
Free the private data attached to the Mailbox.
Definition: mailbox.h:142
Some miscellaneous functions.
Manage IMAP messages.
bool has_new
Mailbox has new mail.
Definition: mailbox.h:88
int imap_adata_find(const char *path, struct ImapAccountData **adata, struct ImapMboxData **mdata)
Find the Account data for this path.
Definition: util.c:128
bool C_ImapListSubscribed
Config: (imap) When browsing a mailbox, only display subscribed folders.
Definition: config.c:47
bool deleted
Definition: message.h:38
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:923
size_t dsize
Length of data.
Definition: buffer.h:37
bool tagged
Email is tagged.
Definition: email.h:44
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:191
bool read
Email is read.
Definition: email.h:51
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
static int complete_hosts(char *buf, size_t buflen)
Look for completion matches for mailboxes.
Definition: imap.c:362
static struct Account * imap_ac_find(struct Account *a, const char *path)
Find an Account that matches a Mailbox path - Implements MxOps::ac_find()
Definition: imap.c:1712
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:379
Disconnected from server.
Definition: private.h:106
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition: util.c:475
int imap_expand_path(struct Buffer *buf)
Buffer wrapper around imap_path_canon()
Definition: imap.c:2424
Parse and execute user-defined hooks.
Many unsorted constants and some structs.
Log at debug level 2.
Definition: logging.h:41
API for mailboxes.
void imap_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: message.c:72
bool old
Email is seen, but unread.
Definition: email.h:50
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:60
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:300
int imap_cmd_idle(struct ImapAccountData *adata)
Enter the IDLE state.
Definition: command.c:1374
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
bool imap_has_flag(struct ListHead *flag_list, const char *flag)
Does the flag exist in the list.
Definition: imap.c:858
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:55
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
int imap_read_headers(struct Mailbox *m, unsigned int msn_begin, unsigned int msn_end, bool initial_download)
Read headers from the server.
Definition: message.c:1284
static int imap_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Implements MxOps::ac_add()
Definition: imap.c:1736
struct Buffer cmdbuf
Definition: private.h:203
struct Envelope * env
Envelope information.
Definition: email.h:90
short C_ImapPollTimeout
Config: (imap) Maximum time to wait for a server response.
Definition: config.c:54
Convenience wrapper for the core headers.
void imap_notify_delete_email(struct Mailbox *m, struct Email *e)
Inform IMAP that an Email has been deleted.
Definition: imap.c:628
ImapOpenFlags check_status
Flags, e.g. IMAP_NEWMAIL_PENDING.
Definition: private.h:223
#define SKIPWS(ch)
Definition: string2.h:46
int imap_exec_msgset(struct Mailbox *m, const char *pre, const char *post, int flag, bool changed, bool invert)
Prepare commands for all messages matching conditions.
Definition: imap.c:907
bool C_ImapQresync
Config: (imap) Enable the QRESYNC extension.
Definition: config.c:55
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
Mailbox is selected.
Definition: private.h:109
struct Mailbox * prev_mailbox
Previously selected mailbox.
Definition: private.h:207
Connected to server.
Definition: private.h:107
IMAP command structure.
Definition: private.h:158
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:60
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
Progress bar.
void(* adata_free)(void **ptr)
Free the private data attached to the Account.
Definition: account.h:49
Shared constants/structs that are private to IMAP.
struct ImapMboxData * imap_mdata_new(struct ImapAccountData *adata, const char *name)
Allocate and initialise a new ImapMboxData structure.
Definition: util.c:164
#define MUTT_ACL_POST
Post (submit messages to the server)
Definition: mailbox.h:71
void * mdata
Driver specific data.
Definition: mailbox.h:136
uint16_t AclFlags
ACL Rights - These show permission to...
Definition: mailbox.h:62
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:74
struct TagList tags
For drivers that support server tagging.
Definition: email.h:107
unsigned long long modseq
Definition: private.h:230
int imap_exec(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Execute a command and wait for the response from the server.
Definition: command.c:1247
int imap_msg_open(struct Mailbox *m, struct Message *msg, int msgno)
Open an email message in a Mailbox - Implements MxOps::msg_open()
Definition: message.c:1881
enum MailboxType type
Mailbox type, e.g. MUTT_IMAP.
Definition: mx.h:107
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
Body Caching - local copies of email bodies.
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
char * flags_remote
Definition: message.h:48
int imap_sync_message_for_copy(struct Mailbox *m, struct Email *e, struct Buffer *cmd, enum QuadOption *err_continue)
Update server to reflect the flags of a single message.
Definition: imap.c:985
struct HashTable * uid_hash
Definition: private.h:236
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:705
Old messages.
Definition: mutt.h:94
Email list needs resorting.
Definition: mailbox.h:172
#define mutt_b2s(buf)
Definition: buffer.h:41
bool closing
If true, we are waiting for CLOSE completion.
Definition: private.h:173
void mutt_account_unsetpass(struct ConnAccount *cac)
Unset ConnAccount&#39;s password.
Definition: connaccount.c:141
void imap_error(const char *where, const char *msg)
show an error and abort
Definition: util.c:798
struct Connection * mutt_conn_new(const struct ConnAccount *cac)
Create a new Connection.
Definition: mutt_socket.c:46
#define IMAP_CAP_IMAP4REV1
Server supports IMAP4rev1.
Definition: private.h:123
bool active
Message is not to be removed.
Definition: email.h:59
short C_DebugLevel
Config: Logging level for debug logs.
Definition: mutt_logging.c:48
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:165
A local copy of an email.
Definition: mx.h:83
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
unsigned char C_SslStarttls
Config: (ssl) Use STARTTLS on servers advertising the capability.
Definition: config.c:46
unsigned int uid
32-bit Message UID
Definition: message.h:44
void mutt_account_hook(const char *url)
Perform an account hook.
Definition: hook.c:755
int imap_access(const char *path)
Check permissions on an IMAP mailbox with a new connection.
Definition: imap.c:450
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:44
char * user
Username.
Definition: url.h:69
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
struct ListHead flags
Definition: private.h:227
int fd
Socket file descriptor.
Definition: connection.h:40
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define IMAP_CMD_PASS
Command contains a password. Suppress logging.
Definition: private.h:73
char * name
Definition: private.h:149
Nondestructive flags change (IMAP)
Definition: mx.h:77
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
int imap_msg_commit(struct Mailbox *m, struct Message *msg)
Save changes to an email - Implements MxOps::msg_commit()
Definition: message.c:2085
Manage where the email is piped to external commands.
void mutt_hash_int_delete(struct HashTable *table, unsigned int intkey, const void *data)
Remove an element from a Hash Table.
Definition: hash.c:434
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition: private.h:175
Match patterns to emails.
Tagged messages.
Definition: mutt.h:103
char * data
Pointer to data.
Definition: buffer.h:35
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition: command.c:1311
#define IMAP_EXPUNGE_EXPECTED
Messages will be expunged from the server.
Definition: private.h:66
#define IMAP_CAP_STATUS
Server supports STATUS command.
Definition: private.h:124
Messages that have been read.
Definition: mutt.h:96
bool replied
Definition: message.h:40
char * name
Mailbox name.
Definition: private.h:218
bool old
Definition: message.h:37
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:113
static int imap_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check()
Definition: imap.c:2137
int mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: string.c:287
bool verbose
Display status messages?
Definition: mailbox.h:118
char * host
Host.
Definition: url.h:71
void imap_allow_reopen(struct Mailbox *m)
Allow re-opening a folder upon expunge.
Definition: util.c:1150
bool purge
Skip trash folder when deleting.
Definition: email.h:46
WHERE bool C_Confirmcreate
Config: Confirm before creating a new mailbox.
Definition: mutt_globals.h:144
int mutt_str_atoull(const char *str, unsigned long long *dst)
Convert ASCII string to an unsigned long long.
Definition: string.c:348
static int imap_mbox_check_stats(struct Mailbox *m, int flags)
Check the Mailbox statistics - Implements MxOps::mbox_check_stats()
Definition: imap.c:1196
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
int imap_mailbox_status(struct Mailbox *m, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1241
bool C_ImapCheckSubscribed
Config: (imap) When opening a mailbox, ask the server for a list of subscribed folders.
Definition: config.c:37
ImapCapFlags capabilities
Definition: private.h:185
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:522
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
#define IMAP_RES_NO
<tag> NO ...
Definition: private.h:53
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: private.h:72
#define IMAP_OPEN_NO_FLAGS
No flags are set.
Definition: private.h:64
time_t lastread
last time we read a command for the server
Definition: private.h:188
bool C_SslForceTls
Config: (ssl) Require TLS encryption for all connections.
Definition: config.c:45
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
int imap_create_mailbox(struct ImapAccountData *adata, char *mailbox)
Create a new mailbox.
Definition: imap.c:424
Login details for a remote server.
Definition: connaccount.h:51
Imap Account.
Definition: mutt_account.h:37
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:96
int imap_cache_clean(struct Mailbox *m)
Delete all the entries in the message cache.
Definition: message.c:1792
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
char * path
Path.
Definition: url.h:73
Connection is idle.
Definition: private.h:112
char * real_name
Original Mailbox name, e.g.: INBOX can be just \0.
Definition: private.h:220
short C_ImapKeepalive
Config: (imap) Time to wait before polling an open IMAP connection.
Definition: config.c:46
Imap command failure.
Definition: private.h:84
static void imap_mbox_select(struct Mailbox *m)
Select a Mailbox.
Definition: imap.c:1793
bool mutt_strn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:598
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:390
#define IS_SPACE(ch)
Definition: string2.h:38
void mutt_socket_empty(struct Connection *conn)
Clear out any queued data.
Definition: socket.c:312
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
int imap_complete(char *buf, size_t buflen, const char *path)
Try to complete an IMAP folder path.
Definition: imap.c:1312
int imap_check_mailbox(struct Mailbox *m, bool force)
use the NOOP or IDLE command to poll for new mail
Definition: imap.c:1087
IMAP-specific Account data -.
Definition: private.h:169
unsigned int uid_next
Definition: private.h:229
static size_t longest_common_prefix(char *dest, const char *src, size_t start, size_t dlen)
Find longest prefix common to two strings.
Definition: imap.c:341
char * driver_tags_get_with_hidden(struct TagList *list)
Get tags with hiddens.
Definition: tags.c:155
char * imap_get_qualifier(char *buf)
Get the qualifier from a tagged response.
Definition: util.c:906
static bool compare_flags_for_copy(struct Email *e)
Compare local flags against the server.
Definition: imap.c:276
char * data
String.
Definition: list.h:36
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
#define IMAP_CAP_CONDSTORE
RFC7162.
Definition: private.h:136
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:131
Log at debug level 1.
Definition: logging.h:40
int n
Definition: acutest.h:492
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: util.c:113
char * imap_fix_path(char delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition: util.c:820
bool flagged
Marked important?
Definition: email.h:43
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:721
IMAP-specific Mailbox data -.
Definition: private.h:216
char * buf
Definition: private.h:189
int msg_new
Number of new messages.
Definition: mailbox.h:95
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
static int imap_mbox_close(struct Mailbox *m)
Close a Mailbox - Implements MxOps::mbox_close()
Definition: imap.c:2154
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:109
bool C_ImapDeflate
Config: (imap) Compress network traffic.
Definition: config.c:40
#define mutt_error(...)
Definition: logging.h:84
bool replied
Email has been replied to.
Definition: email.h:54
#define IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition: private.h:68
#define IMAP_CAP_QRESYNC
RFC7162.
Definition: private.h:137
static int imap_tags_commit(struct Mailbox *m, struct Email *e, char *buf)
Save the tags to a message - Implements MxOps::tags_commit()
Definition: imap.c:2311
Connection Library.
FILE * fp
pointer to the message data
Definition: mx.h:85
static int imap_path_pretty(char *buf, size_t buflen, const char *folder)
Abbreviate a Mailbox path - Implements MxOps::path_pretty()
Definition: imap.c:2433
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1696
int url_tostring(struct Url *url, char *dest, size_t len, int flags)
Output the URL string for a given Url object.
Definition: url.c:418
bool read
Definition: message.h:36
bool mx_mbox_ac_link(struct Mailbox *m)
Link a Mailbox to an existing or new Account.
Definition: mx.c:266
#define MUTT_ACL_SEEN
Change the &#39;seen&#39; status of a message.
Definition: mailbox.h:73
#define STAILQ_EMPTY(head)
Definition: queue.h:345
int imap_authenticate(struct ImapAccountData *adata)
Authenticate to an IMAP server.
Definition: auth.c:82
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
int imap_path_canon(char *buf, size_t buflen)
Canonicalise a Mailbox path - Implements MxOps::path_canon()
Definition: imap.c:2395
static int check_capabilities(struct ImapAccountData *adata)
Make sure we can log in to this server.
Definition: imap.c:73
struct ImapList * cmdresult
Definition: private.h:196
List of Mailboxes.
Definition: mailbox.h:150
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
Hundreds of global variables to back the user variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition: private.h:74
IMAP-specific Email data -.
Definition: message.h:33
bool driver_tags_replace(struct TagList *head, char *tags)
Replace all tags.
Definition: tags.c:183
New mail received in Mailbox.
Definition: mx.h:74
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
NeoMutt connections.
int mx_ac_remove(struct Mailbox *m)
Remove a Mailbox from an Account and delete Account if empty.
Definition: mx.c:1799
sort_t mutt_get_sort_func(enum SortType method)
Get the sort function for a given sort id.
Definition: sort.c:324
struct Buffer pathbuf
Definition: mailbox.h:83
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
A List node for strings.
Definition: list.h:34
static int compare_uid(const void *a, const void *b)
Compare two Emails by UID - Implements sort_t.
Definition: imap.c:884
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:56
char * munge_name
Munged version of the mailbox name.
Definition: private.h:219
#define IMAP_CMD_SINGLE
Run a single command.
Definition: private.h:76
Mailbox was reopened.
Definition: mx.h:76
int mutt_ssl_starttls(struct Connection *conn)
Negotiate TLS over an already opened connection.
Definition: gnutls.c:1136
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
bool C_ImapIdle
Config: (imap) Use the IMAP IDLE extension to check for new mail.
Definition: config.c:45
int imap_fast_trash(struct Mailbox *m, char *dest)
Use server COPY command to copy deleted messages to trash.
Definition: imap.c:1390
void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata)
Open a header cache.
Definition: util.c:435
#define IMAP_CAP_IDLE
RFC2177: IDLE.
Definition: private.h:133
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:174
#define IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition: private.h:67
Trashed messages.
Definition: mutt.h:108
#define IMAP_CAP_ACL
RFC2086: IMAP4 ACL extension.
Definition: private.h:125
Authentication successful.
Definition: auth.h:38
Log at debug level 3.
Definition: logging.h:42
WHERE char * C_Postponed
Config: Folder to store postponed messages.
Definition: mutt_globals.h:102
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
bool noselect
Definition: private.h:151
#define MUTT_ACL_LOOKUP
Lookup mailbox (visible to &#39;list&#39;)
Definition: mailbox.h:70
unsigned int messages
Definition: private.h:231
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
quote string according to IMAP rules
Definition: util.c:971
bool unicode
If true, we can send UTF-8, and the server will use UTF8 rather than mUTF7.
Definition: private.h:192
char * path
path to temp file
Definition: mx.h:86
The Mailbox API.
Definition: mx.h:105
int imap_subscribe(char *path, bool subscribe)
Subscribe to a mailbox.
Definition: imap.c:1257
static int imap_mbox_open_append(struct Mailbox *m, OpenMailboxFlags flags)
Open a Mailbox for appending - Implements MxOps::mbox_open_append()
Definition: imap.c:2104
#define IMAP_LOG_LTRL
Definition: private.h:49
static void set_flag(struct Mailbox *m, AclFlags aclflag, int flag, const char *str, char *flags, size_t flsize)
append str to flags if we currently have permission according to aclflag
Definition: imap.c:155
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
struct Connection * conn
Definition: private.h:171
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:152
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234