NeoMutt  2020-09-25
Teaching an old dog new tricks
DOXYGEN
init.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <ctype.h>
32 #include <inttypes.h>
33 #include <pwd.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <sys/utsname.h>
40 #include <unistd.h>
41 #include "mutt/lib.h"
42 #include "address/lib.h"
43 #include "config/lib.h"
44 #include "email/lib.h"
45 #include "core/lib.h"
46 #include "alias/lib.h"
47 #include "conn/lib.h"
48 #include "gui/lib.h"
49 #include "mutt.h"
50 #include "init.h"
51 #include "compress/lib.h"
52 #include "hcache/lib.h"
53 #include "history/lib.h"
54 #include "notmuch/lib.h"
55 #include "store/lib.h"
56 #include "command_parse.h"
57 #include "context.h"
58 #include "functions.h"
59 #include "keymap.h"
60 #include "mutt_commands.h"
61 #include "mutt_globals.h"
62 #ifdef USE_LUA
63 #include "mutt_lua.h"
64 #endif
65 #include "mutt_menu.h"
66 #include "mutt_parse.h"
67 #include "muttlib.h"
68 #include "myvar.h"
69 #include "options.h"
70 #include "protos.h"
71 #include "sort.h"
72 #ifdef USE_SIDEBAR
73 #include "sidebar/lib.h"
74 #endif
75 #ifdef USE_COMP_MBOX
76 #include "compmbox/lib.h"
77 #endif
78 #ifdef USE_IMAP
79 #include "imap/lib.h"
80 #endif
81 
82 /* Initial string that starts completion. No telling how much the user has
83  * typed so far. Allocate 1024 just to be sure! */
84 static char UserTyped[1024] = { 0 };
85 
86 static int NumMatched = 0; /* Number of matches for completion */
87 static char Completed[256] = { 0 }; /* completed string (command or variable) */
88 static const char **Matches;
89 /* this is a lie until mutt_init runs: */
90 static int MatchesListsize = 512; // Enough space for all of the config items
91 
92 #ifdef USE_NOTMUCH
93 /* List of tags found in last call to mutt_nm_query_complete(). */
94 static char **nm_tags;
95 #endif
96 
97 bool config_init_main(struct ConfigSet *cs);
98 
103 static void matches_ensure_morespace(int current)
104 {
105  if (current <= (MatchesListsize - 2))
106  return;
107 
108  int base_space = 512; // Enough space for all of the config items
109  int extra_space = MatchesListsize - base_space;
110  extra_space *= 2;
111  const int space = base_space + extra_space;
112  mutt_mem_realloc(&Matches, space * sizeof(char *));
113  memset(&Matches[current + 1], 0, space - current);
114  MatchesListsize = space;
115 }
116 
126 static void candidate(char *user, const char *src, char *dest, size_t dlen)
127 {
128  if (!dest || !user || !src)
129  return;
130 
131  if (strstr(src, user) != src)
132  return;
133 
135  Matches[NumMatched++] = src;
136  if (dest[0] == '\0')
137  mutt_str_copy(dest, src, dlen);
138  else
139  {
140  int l;
141  for (l = 0; src[l] && src[l] == dest[l]; l++)
142  ; // do nothing
143 
144  dest[l] = '\0';
145  }
146 }
147 
148 #ifdef USE_NOTMUCH
149 
155 static int complete_all_nm_tags(const char *pt)
156 {
157  int tag_count_1 = 0;
158  int tag_count_2 = 0;
159 
160  NumMatched = 0;
161  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
162  memset(Matches, 0, MatchesListsize);
163  memset(Completed, 0, sizeof(Completed));
164 
166 
167  /* Work out how many tags there are. */
168  if (nm_get_all_tags(Context->mailbox, NULL, &tag_count_1) || (tag_count_1 == 0))
169  goto done;
170 
171  /* Free the old list, if any. */
172  if (nm_tags)
173  {
174  for (int i = 0; nm_tags[i]; i++)
175  FREE(&nm_tags[i]);
176  FREE(&nm_tags);
177  }
178  /* Allocate a new list, with sentinel. */
179  nm_tags = mutt_mem_malloc((tag_count_1 + 1) * sizeof(char *));
180  nm_tags[tag_count_1] = NULL;
181 
182  /* Get all the tags. */
183  if (nm_get_all_tags(Context->mailbox, nm_tags, &tag_count_2) || (tag_count_1 != tag_count_2))
184  {
185  FREE(&nm_tags);
186  nm_tags = NULL;
188  return -1;
189  }
190 
191  /* Put them into the completion machinery. */
192  for (int num = 0; num < tag_count_1; num++)
193  {
194  candidate(UserTyped, nm_tags[num], Completed, sizeof(Completed));
195  }
196 
199 
200 done:
202  return 0;
203 }
204 #endif
205 
212 static int execute_commands(struct ListHead *p)
213 {
214  int rc = 0;
215  struct Buffer *err = mutt_buffer_pool_get();
216 
217  struct ListNode *np = NULL;
218  STAILQ_FOREACH(np, p, entries)
219  {
220  enum CommandResult rc2 = mutt_parse_rc_line(np->data, err);
221  if (rc2 == MUTT_CMD_ERROR)
222  mutt_error(_("Error in command line: %s"), mutt_b2s(err));
223  else if (rc2 == MUTT_CMD_WARNING)
224  mutt_warning(_("Warning in command line: %s"), mutt_b2s(err));
225 
226  if ((rc2 == MUTT_CMD_ERROR) || (rc2 == MUTT_CMD_WARNING))
227  {
229  return -1;
230  }
231  }
233 
234  return rc;
235 }
236 
244 static char *find_cfg(const char *home, const char *xdg_cfg_home)
245 {
246  const char *names[] = {
247  "neomuttrc",
248  "muttrc",
249  NULL,
250  };
251 
252  const char *locations[][2] = {
253  { xdg_cfg_home, "neomutt/" },
254  { xdg_cfg_home, "mutt/" },
255  { home, ".neomutt/" },
256  { home, ".mutt/" },
257  { home, "." },
258  { NULL, NULL },
259  };
260 
261  for (int i = 0; locations[i][0] || locations[i][1]; i++)
262  {
263  if (!locations[i][0])
264  continue;
265 
266  for (int j = 0; names[j]; j++)
267  {
268  char buf[256];
269 
270  snprintf(buf, sizeof(buf), "%s/%s%s", locations[i][0], locations[i][1], names[j]);
271  if (access(buf, F_OK) == 0)
272  return mutt_str_dup(buf);
273  }
274  }
275 
276  return NULL;
277 }
278 
279 #ifndef DOMAIN
280 
285 static char *getmailname(void)
286 {
287  char *mailname = NULL;
288  static const char *mn_files[] = { "/etc/mailname", "/etc/mail/mailname" };
289 
290  for (size_t i = 0; i < mutt_array_size(mn_files); i++)
291  {
292  FILE *fp = mutt_file_fopen(mn_files[i], "r");
293  if (!fp)
294  continue;
295 
296  size_t len = 0;
297  mailname = mutt_file_read_line(NULL, &len, fp, NULL, 0);
298  mutt_file_fclose(&fp);
299  if (mailname && *mailname)
300  break;
301 
302  FREE(&mailname);
303  }
304 
305  return mailname;
306 }
307 #endif
308 
317 static bool get_hostname(struct ConfigSet *cs)
318 {
319  char *str = NULL;
320  struct utsname utsname;
321 
322  if (C_Hostname)
323  {
324  str = C_Hostname;
325  }
326  else
327  {
328  /* The call to uname() shouldn't fail, but if it does, the system is horribly
329  * broken, and the system's networking configuration is in an unreliable
330  * state. We should bail. */
331  if ((uname(&utsname)) == -1)
332  {
333  mutt_perror(_("unable to determine nodename via uname()"));
334  return false; // TEST09: can't test
335  }
336 
337  str = utsname.nodename;
338  }
339 
340  /* some systems report the FQDN instead of just the hostname */
341  char *dot = strchr(str, '.');
342  if (dot)
343  ShortHostname = mutt_strn_dup(str, dot - str);
344  else
346 
347  if (!C_Hostname)
348  {
349  /* now get FQDN. Use configured domain first, DNS next, then uname */
350 #ifdef DOMAIN
351  /* we have a compile-time domain name, use that for C_Hostname */
353  sprintf((char *) C_Hostname, "%s.%s", NONULL(ShortHostname), DOMAIN);
354 #else
355  C_Hostname = getmailname();
356  if (!C_Hostname)
357  {
358  struct Buffer *domain = mutt_buffer_pool_get();
359  if (getdnsdomainname(domain) == 0)
360  {
361  C_Hostname =
363  sprintf((char *) C_Hostname, "%s.%s", NONULL(ShortHostname), mutt_b2s(domain));
364  }
365  else
366  {
367  /* DNS failed, use the nodename. Whether or not the nodename had a '.'
368  * in it, we can use the nodename as the FQDN. On hosts where DNS is
369  * not being used, e.g. small network that relies on hosts files, a
370  * short host name is all that is required for SMTP to work correctly.
371  * It could be wrong, but we've done the best we can, at this point the
372  * onus is on the user to provide the correct hostname if the nodename
373  * won't work in their network. */
374  C_Hostname = mutt_str_dup(utsname.nodename);
375  }
376  mutt_buffer_pool_release(&domain);
377  }
378 #endif
379  }
380  if (C_Hostname)
381  cs_str_initial_set(cs, "hostname", C_Hostname, NULL);
382 
383  return true;
384 }
385 
394 int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
395 {
396  if (!dest || !tok)
397  return -1;
398 
399  char ch;
400  char qc = '\0'; /* quote char */
401  char *pc = NULL;
402 
403  mutt_buffer_reset(dest);
404 
405  SKIPWS(tok->dptr);
406  while ((ch = *tok->dptr))
407  {
408  if (qc == '\0')
409  {
410  if ((IS_SPACE(ch) && !(flags & MUTT_TOKEN_SPACE)) ||
411  ((ch == '#') && !(flags & MUTT_TOKEN_COMMENT)) ||
412  ((ch == '+') && (flags & MUTT_TOKEN_PLUS)) ||
413  ((ch == '-') && (flags & MUTT_TOKEN_MINUS)) ||
414  ((ch == '=') && (flags & MUTT_TOKEN_EQUAL)) ||
415  ((ch == '?') && (flags & MUTT_TOKEN_QUESTION)) ||
416  ((ch == ';') && !(flags & MUTT_TOKEN_SEMICOLON)) ||
417  ((flags & MUTT_TOKEN_PATTERN) && strchr("~%=!|", ch)))
418  {
419  break;
420  }
421  }
422 
423  tok->dptr++;
424 
425  if (ch == qc)
426  qc = 0; /* end of quote */
427  else if (!qc && ((ch == '\'') || (ch == '"')) && !(flags & MUTT_TOKEN_QUOTE))
428  qc = ch;
429  else if ((ch == '\\') && (qc != '\''))
430  {
431  if (tok->dptr[0] == '\0')
432  return -1; /* premature end of token */
433  switch (ch = *tok->dptr++)
434  {
435  case 'c':
436  case 'C':
437  if (tok->dptr[0] == '\0')
438  return -1; /* premature end of token */
439  mutt_buffer_addch(dest, (toupper((unsigned char) tok->dptr[0]) - '@') & 0x7f);
440  tok->dptr++;
441  break;
442  case 'e':
443  mutt_buffer_addch(dest, '\033'); // Escape
444  break;
445  case 'f':
446  mutt_buffer_addch(dest, '\f');
447  break;
448  case 'n':
449  mutt_buffer_addch(dest, '\n');
450  break;
451  case 'r':
452  mutt_buffer_addch(dest, '\r');
453  break;
454  case 't':
455  mutt_buffer_addch(dest, '\t');
456  break;
457  default:
458  if (isdigit((unsigned char) ch) && isdigit((unsigned char) tok->dptr[0]) &&
459  isdigit((unsigned char) tok->dptr[1]))
460  {
461  mutt_buffer_addch(dest, (ch << 6) + (tok->dptr[0] << 3) + tok->dptr[1] - 3504);
462  tok->dptr += 2;
463  }
464  else
465  mutt_buffer_addch(dest, ch);
466  }
467  }
468  else if ((ch == '^') && (flags & MUTT_TOKEN_CONDENSE))
469  {
470  if (tok->dptr[0] == '\0')
471  return -1; /* premature end of token */
472  ch = *tok->dptr++;
473  if (ch == '^')
474  mutt_buffer_addch(dest, ch);
475  else if (ch == '[')
476  mutt_buffer_addch(dest, '\033'); // Escape
477  else if (isalpha((unsigned char) ch))
478  mutt_buffer_addch(dest, toupper((unsigned char) ch) - '@');
479  else
480  {
481  mutt_buffer_addch(dest, '^');
482  mutt_buffer_addch(dest, ch);
483  }
484  }
485  else if ((ch == '`') && (!qc || (qc == '"')))
486  {
487  FILE *fp = NULL;
488  pid_t pid;
489 
490  pc = tok->dptr;
491  do
492  {
493  pc = strpbrk(pc, "\\`");
494  if (pc)
495  {
496  /* skip any quoted chars */
497  if (*pc == '\\')
498  pc += 2;
499  }
500  } while (pc && (pc[0] != '`'));
501  if (!pc)
502  {
503  mutt_debug(LL_DEBUG1, "mismatched backticks\n");
504  return -1;
505  }
506  struct Buffer cmd;
507  mutt_buffer_init(&cmd);
508  *pc = '\0';
509  if (flags & MUTT_TOKEN_BACKTICK_VARS)
510  {
511  /* recursively extract tokens to interpolate variables */
512  mutt_extract_token(&cmd, tok,
513  MUTT_TOKEN_QUOTE | MUTT_TOKEN_SPACE | MUTT_TOKEN_COMMENT |
515  }
516  else
517  {
518  cmd.data = mutt_str_dup(tok->dptr);
519  }
520  *pc = '`';
521  pid = filter_create(cmd.data, NULL, &fp, NULL);
522  if (pid < 0)
523  {
524  mutt_debug(LL_DEBUG1, "unable to fork command: %s\n", cmd.data);
525  FREE(&cmd.data);
526  return -1;
527  }
528  FREE(&cmd.data);
529 
530  tok->dptr = pc + 1;
531 
532  /* read line */
533  struct Buffer expn = mutt_buffer_make(0);
534  expn.data = mutt_file_read_line(NULL, &expn.dsize, fp, NULL, 0);
535  mutt_file_fclose(&fp);
536  filter_wait(pid);
537 
538  /* if we got output, make a new string consisting of the shell output
539  * plus whatever else was left on the original line */
540  /* BUT: If this is inside a quoted string, directly add output to
541  * the token */
542  if (expn.data)
543  {
544  if (qc)
545  {
546  mutt_buffer_addstr(dest, expn.data);
547  }
548  else
549  {
550  struct Buffer *copy = mutt_buffer_pool_get();
551  mutt_buffer_fix_dptr(&expn);
552  mutt_buffer_copy(copy, &expn);
553  mutt_buffer_addstr(copy, tok->dptr);
554  mutt_buffer_copy(tok, copy);
555  tok->dptr = tok->data;
557  }
558  FREE(&expn.data);
559  }
560  }
561  else if ((ch == '$') && (!qc || (qc == '"')) &&
562  ((tok->dptr[0] == '{') || isalpha((unsigned char) tok->dptr[0])))
563  {
564  const char *env = NULL;
565  char *var = NULL;
566 
567  if (tok->dptr[0] == '{')
568  {
569  pc = strchr(tok->dptr, '}');
570  if (pc)
571  {
572  var = mutt_strn_dup(tok->dptr + 1, pc - (tok->dptr + 1));
573  tok->dptr = pc + 1;
574 
575  if ((flags & MUTT_TOKEN_NOSHELL))
576  {
577  mutt_buffer_addch(dest, ch);
578  mutt_buffer_addch(dest, '{');
579  mutt_buffer_addstr(dest, var);
580  mutt_buffer_addch(dest, '}');
581  FREE(&var);
582  }
583  }
584  }
585  else
586  {
587  for (pc = tok->dptr; isalnum((unsigned char) *pc) || (pc[0] == '_'); pc++)
588  ; // do nothing
589 
590  var = mutt_strn_dup(tok->dptr, pc - tok->dptr);
591  tok->dptr = pc;
592  }
593  if (var)
594  {
595  struct Buffer result;
596  mutt_buffer_init(&result);
597  int rc = cs_subset_str_string_get(NeoMutt->sub, var, &result);
598 
599  if (CSR_RESULT(rc) == CSR_SUCCESS)
600  {
601  mutt_buffer_addstr(dest, result.data);
602  FREE(&result.data);
603  }
604  else if ((env = myvar_get(var)))
605  {
606  mutt_buffer_addstr(dest, env);
607  }
608  else if (!(flags & MUTT_TOKEN_NOSHELL) && (env = mutt_str_getenv(var)))
609  {
610  mutt_buffer_addstr(dest, env);
611  }
612  else
613  {
614  mutt_buffer_addch(dest, ch);
615  mutt_buffer_addstr(dest, var);
616  }
617  FREE(&var);
618  }
619  }
620  else
621  mutt_buffer_addch(dest, ch);
622  }
623  mutt_buffer_addch(dest, 0); /* terminate the string */
624  SKIPWS(tok->dptr);
625  return 0;
626 }
627 
631 void mutt_opts_free(void)
632 {
634 
635  alias_shutdown();
636 #ifdef USE_SIDEBAR
637  sb_shutdown();
638 #endif
639 
640  mutt_regexlist_free(&Alternates);
644  mutt_regexlist_free(&UnAlternates);
647 
651 
652  /* Lists of strings */
653  mutt_list_free(&AlternativeOrderList);
654  mutt_list_free(&AutoViewList);
655  mutt_list_free(&HeaderOrderList);
658  mutt_list_free(&MimeLookupList);
659  mutt_list_free(&Muttrc);
661  mutt_list_free(&UserHeader);
662 
663  /* Lists of AttachMatch */
665  mutt_list_free_type(&AttachExclude, (list_free_t) mutt_attachmatch_free);
666  mutt_list_free_type(&InlineAllow, (list_free_t) mutt_attachmatch_free);
667  mutt_list_free_type(&InlineExclude, (list_free_t) mutt_attachmatch_free);
668 
670 
672  FREE(&HomeDir);
673  FREE(&LastFolder);
675  FREE(&Username);
676 
679 
681 
682  mutt_hist_free();
683  mutt_keys_free();
684 
687 }
688 
695 HookFlags mutt_get_hook_type(const char *name)
696 {
697  struct Command *c = NULL;
698  for (size_t i = 0, size = mutt_commands_array(&c); i < size; i++)
699  {
700  if (((c[i].parse == mutt_parse_hook) || (c[i].parse == mutt_parse_idxfmt_hook)) &&
701  mutt_istr_equal(c[i].name, name))
702  {
703  return c[i].data;
704  }
705  }
706  return MUTT_HOOK_NO_FLAGS;
707 }
708 
717 int mutt_init(struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands)
718 {
719  int need_pause = 0;
720  int rc = 1;
721  struct Buffer err = mutt_buffer_make(256);
722  struct Buffer buf = mutt_buffer_make(256);
723 
725  alias_init();
727 #ifdef USE_COMP_MBOX
728  mutt_comp_init();
729 #endif
730 #ifdef USE_IMAP
731  imap_init();
732 #endif
733 #ifdef USE_LUA
734  mutt_lua_init();
735 #endif
738 
739  mutt_menu_init();
740 #ifdef USE_SIDEBAR
741  sb_init();
742 #endif
743 #ifdef USE_NOTMUCH
744  nm_init();
745 #endif
746 
747  snprintf(AttachmentMarker, sizeof(AttachmentMarker), "\033]9;%" PRIu64 "\a", // Escape
748  mutt_rand64());
749 
750  snprintf(ProtectedHeaderMarker, sizeof(ProtectedHeaderMarker), "\033]8;%lld\a", // Escape
751  (long long) mutt_date_epoch());
752 
753  /* "$spoolfile" precedence: config file, environment */
754  const char *p = mutt_str_getenv("MAIL");
755  if (!p)
756  p = mutt_str_getenv("MAILDIR");
757  if (!p)
758  {
759 #ifdef HOMESPOOL
760  mutt_buffer_concat_path(&buf, NONULL(HomeDir), MAILPATH);
761 #else
762  mutt_buffer_concat_path(&buf, MAILPATH, NONULL(Username));
763 #endif
764  p = mutt_b2s(&buf);
765  }
766  cs_str_initial_set(cs, "spoolfile", p, NULL);
767  cs_str_reset(cs, "spoolfile", NULL);
768 
769  p = mutt_str_getenv("REPLYTO");
770  if (p)
771  {
772  struct Buffer token;
773 
774  mutt_buffer_printf(&buf, "Reply-To: %s", p);
775  mutt_buffer_init(&token);
776  parse_my_hdr(&token, &buf, 0, &err); /* adds to UserHeader */
777  FREE(&token.data);
778  }
779 
780  p = mutt_str_getenv("EMAIL");
781  if (p)
782  {
783  cs_str_initial_set(cs, "from", p, NULL);
784  cs_str_reset(cs, "from", NULL);
785  }
786 
787  /* "$mailcap_path" precedence: config file, environment, code */
788  const char *env_mc = mutt_str_getenv("MAILCAPS");
789  if (env_mc)
790  cs_str_string_set(cs, "mailcap_path", env_mc, NULL);
791 
792  /* "$tmpdir" precedence: config file, environment, code */
793  const char *env_tmp = mutt_str_getenv("TMPDIR");
794  if (env_tmp)
795  cs_str_string_set(cs, "tmpdir", env_tmp, NULL);
796 
797  /* "$visual", "$editor" precedence: config file, environment, code */
798  const char *env_ed = mutt_str_getenv("VISUAL");
799  if (!env_ed)
800  env_ed = mutt_str_getenv("EDITOR");
801  if (env_ed)
802  {
803  cs_str_string_set(cs, "editor", env_ed, NULL);
804  cs_str_string_set(cs, "visual", env_ed, NULL);
805  }
806 
808  cs_str_initial_set(cs, "charset", C_Charset, NULL);
810 
811  Matches = mutt_mem_calloc(MatchesListsize, sizeof(char *));
812 
814 
815 #ifdef HAVE_GETSID
816  /* Unset suspend by default if we're the session leader */
817  if (getsid(0) == getpid())
818  C_Suspend = false;
819 #endif
820 
821  /* RFC2368, "4. Unsafe headers"
822  * The creator of a mailto URL can't expect the resolver of a URL to
823  * understand more than the "subject" and "body" headers. Clients that
824  * resolve mailto URLs into mail messages should be able to correctly
825  * create RFC822-compliant mail messages using the "subject" and "body"
826  * headers. */
827  add_to_stailq(&MailToAllow, "body");
828  add_to_stailq(&MailToAllow, "subject");
829  /* Cc, In-Reply-To, and References help with not breaking threading on
830  * mailing lists, see https://github.com/neomutt/neomutt/issues/115 */
831  add_to_stailq(&MailToAllow, "cc");
832  add_to_stailq(&MailToAllow, "in-reply-to");
833  add_to_stailq(&MailToAllow, "references");
834 
835  if (STAILQ_EMPTY(&Muttrc))
836  {
837  const char *xdg_cfg_home = mutt_str_getenv("XDG_CONFIG_HOME");
838 
839  if (!xdg_cfg_home && HomeDir)
840  {
841  mutt_buffer_printf(&buf, "%s/.config", HomeDir);
842  xdg_cfg_home = mutt_b2s(&buf);
843  }
844 
845  char *config = find_cfg(HomeDir, xdg_cfg_home);
846  if (config)
847  {
848  mutt_list_insert_tail(&Muttrc, config);
849  }
850  }
851  else
852  {
853  struct ListNode *np = NULL;
854  STAILQ_FOREACH(np, &Muttrc, entries)
855  {
856  mutt_buffer_strcpy(&buf, np->data);
857  FREE(&np->data);
859  np->data = mutt_buffer_strdup(&buf);
860  if (access(np->data, F_OK))
861  {
862  mutt_perror(np->data);
863  goto done; // TEST10: neomutt -F missing
864  }
865  }
866  }
867 
868  if (!STAILQ_EMPTY(&Muttrc))
869  {
870  cs_str_string_set(cs, "alias_file", STAILQ_FIRST(&Muttrc)->data, NULL);
871  }
872 
873  /* Process the global rc file if it exists and the user hasn't explicitly
874  * requested not to via "-n". */
875  if (!skip_sys_rc)
876  {
877  do
878  {
880  break;
881 
882  mutt_buffer_printf(&buf, "%s/neomuttrc", SYSCONFDIR);
883  if (access(mutt_b2s(&buf), F_OK) == 0)
884  break;
885 
886  mutt_buffer_printf(&buf, "%s/Muttrc", SYSCONFDIR);
887  if (access(mutt_b2s(&buf), F_OK) == 0)
888  break;
889 
890  mutt_buffer_printf(&buf, "%s/neomuttrc", PKGDATADIR);
891  if (access(mutt_b2s(&buf), F_OK) == 0)
892  break;
893 
894  mutt_buffer_printf(&buf, "%s/Muttrc", PKGDATADIR);
895  } while (false);
896 
897  if (access(mutt_b2s(&buf), F_OK) == 0)
898  {
899  if (source_rc(mutt_b2s(&buf), &err) != 0)
900  {
901  mutt_error("%s", err.data);
902  need_pause = 1; // TEST11: neomutt (error in /etc/neomuttrc)
903  }
904  }
905  }
906 
907  /* Read the user's initialization file. */
908  struct ListNode *np = NULL;
909  STAILQ_FOREACH(np, &Muttrc, entries)
910  {
911  if (np->data)
912  {
913  if (source_rc(np->data, &err) != 0)
914  {
915  mutt_error("%s", err.data);
916  need_pause = 1; // TEST12: neomutt (error in ~/.neomuttrc)
917  }
918  }
919  }
920 
921  if (execute_commands(commands) != 0)
922  need_pause = 1; // TEST13: neomutt -e broken
923 
924  if (!get_hostname(cs))
925  goto done;
926 
927  if (!C_Realname)
928  {
929  struct passwd *pw = getpwuid(getuid());
930  if (pw)
931  {
932  char name[256];
933  C_Realname = mutt_str_dup(mutt_gecos_name(name, sizeof(name), pw));
934  }
935  }
936  cs_str_initial_set(cs, "realname", C_Realname, NULL);
937 
938  if (need_pause && !OptNoCurses)
939  {
941  if (mutt_any_key_to_continue(NULL) == 'q')
942  goto done; // TEST14: neomutt -e broken (press 'q')
943  }
944 
945  mutt_file_mkdir(C_Tmpdir, S_IRWXU);
946 
947  mutt_hist_init();
949 
950 #ifdef USE_NOTMUCH
951  if (C_VirtualSpoolfile)
952  {
953  /* Find the first virtual folder and open it */
954  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
956  struct MailboxNode *mp = STAILQ_FIRST(&ml);
957  if (mp)
958  cs_str_string_set(cs, "spoolfile", mailbox_path(mp->mailbox), NULL);
960  }
961 #endif
962  rc = 0;
963 
964 done:
965  mutt_buffer_dealloc(&err);
966  mutt_buffer_dealloc(&buf);
967  return rc;
968 }
969 
982  struct Buffer *token, struct Buffer *err)
983 {
984  if (mutt_buffer_len(line) == 0)
985  return 0;
986 
988 
989  mutt_buffer_reset(err);
990 
991  /* Read from the beginning of line->data */
992  line->dptr = line->data;
993 
994  SKIPWS(line->dptr);
995  while (*line->dptr)
996  {
997  if (*line->dptr == '#')
998  break; /* rest of line is a comment */
999  if (*line->dptr == ';')
1000  {
1001  line->dptr++;
1002  continue;
1003  }
1005 
1006  struct Command *cmd = NULL;
1007  size_t size = mutt_commands_array(&cmd);
1008  size_t i;
1009  for (i = 0; i < size; i++)
1010  {
1011  if (mutt_str_equal(token->data, cmd[i].name))
1012  {
1013  rc = cmd[i].parse(token, line, cmd[i].data, err);
1014  if (rc != MUTT_CMD_SUCCESS)
1015  { /* -1 Error, +1 Finish */
1016  goto finish; /* Propagate return code */
1017  }
1018  notify_send(NeoMutt->notify, NT_COMMAND, i, (void *) cmd);
1019  break; /* Continue with next command */
1020  }
1021  }
1022  if (i == size)
1023  {
1024  mutt_buffer_printf(err, _("%s: unknown command"), NONULL(token->data));
1025  rc = MUTT_CMD_ERROR;
1026  break; /* Ignore the rest of the line */
1027  }
1028  }
1029 finish:
1030  return rc;
1031 }
1032 
1039 enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
1040 {
1041  if (!line || (*line == '\0'))
1042  return MUTT_CMD_ERROR;
1043 
1044  struct Buffer *line_buffer = mutt_buffer_pool_get();
1045  struct Buffer *token = mutt_buffer_pool_get();
1046 
1047  mutt_buffer_strcpy(line_buffer, line);
1048 
1049  enum CommandResult rc = mutt_parse_rc_buffer(line_buffer, token, err);
1050 
1051  mutt_buffer_pool_release(&line_buffer);
1052  mutt_buffer_pool_release(&token);
1053  return rc;
1054 }
1055 
1063 int mutt_query_variables(struct ListHead *queries, bool show_docs)
1064 {
1065  struct Buffer value = mutt_buffer_make(256);
1066  struct Buffer tmp = mutt_buffer_make(256);
1067  int rc = 0;
1068 
1069  struct ListNode *np = NULL;
1070  STAILQ_FOREACH(np, queries, entries)
1071  {
1072  mutt_buffer_reset(&value);
1073 
1074  struct HashElem *he = cs_subset_lookup(NeoMutt->sub, np->data);
1075  if (!he)
1076  {
1077  mutt_warning(_("No such variable: %s"), np->data);
1078  rc = 1;
1079  continue;
1080  }
1081 
1082  if (he->type & DT_DEPRECATED)
1083  {
1084  mutt_warning(_("Config variable '%s' is deprecated"), np->data);
1085  rc = 1;
1086  continue;
1087  }
1088 
1089  int rv = cs_subset_he_string_get(NeoMutt->sub, he, &value);
1090  if (CSR_RESULT(rv) != CSR_SUCCESS)
1091  {
1092  rc = 1;
1093  continue;
1094  }
1095 
1096  int type = DTYPE(he->type);
1097  if (type == DT_PATH)
1098  mutt_pretty_mailbox(value.data, value.dsize);
1099 
1100  if ((type != DT_BOOL) && (type != DT_NUMBER) && (type != DT_LONG) && (type != DT_QUAD))
1101  {
1102  mutt_buffer_reset(&tmp);
1103  pretty_var(value.data, &tmp);
1104  mutt_buffer_strcpy(&value, tmp.data);
1105  }
1106 
1107  dump_config_neo(NeoMutt->sub->cs, he, &value, NULL,
1108  show_docs ? CS_DUMP_SHOW_DOCS : CS_DUMP_NO_FLAGS, stdout);
1109  }
1110 
1111  mutt_buffer_dealloc(&value);
1112  mutt_buffer_dealloc(&tmp);
1113 
1114  return rc; // TEST16: neomutt -Q charset
1115 }
1116 
1126 int mutt_command_complete(char *buf, size_t buflen, int pos, int numtabs)
1127 {
1128  char *pt = buf;
1129  int spaces; /* keep track of the number of leading spaces on the line */
1130  struct MyVar *myv = NULL;
1131 
1132  SKIPWS(buf);
1133  spaces = buf - pt;
1134 
1135  pt = buf + pos - spaces;
1136  while ((pt > buf) && !isspace((unsigned char) *pt))
1137  pt--;
1138 
1139  if (pt == buf) /* complete cmd */
1140  {
1141  /* first TAB. Collect all the matches */
1142  if (numtabs == 1)
1143  {
1144  NumMatched = 0;
1145  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
1146  memset(Matches, 0, MatchesListsize);
1147  memset(Completed, 0, sizeof(Completed));
1148 
1149  struct Command *c = NULL;
1150  for (size_t num = 0, size = mutt_commands_array(&c); num < size; num++)
1151  candidate(UserTyped, c[num].name, Completed, sizeof(Completed));
1154 
1155  /* All matches are stored. Longest non-ambiguous string is ""
1156  * i.e. don't change 'buf'. Fake successful return this time */
1157  if (UserTyped[0] == '\0')
1158  return 1;
1159  }
1160 
1161  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1162  return 0;
1163 
1164  /* NumMatched will _always_ be at least 1 since the initial
1165  * user-typed string is always stored */
1166  if ((numtabs == 1) && (NumMatched == 2))
1167  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1168  else if ((numtabs > 1) && (NumMatched > 2))
1169  {
1170  /* cycle through all the matches */
1171  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1172  }
1173 
1174  /* return the completed command */
1175  strncpy(buf, Completed, buflen - spaces);
1176  }
1177  else if (mutt_str_startswith(buf, "set") || mutt_str_startswith(buf, "unset") ||
1178  mutt_str_startswith(buf, "reset") || mutt_str_startswith(buf, "toggle"))
1179  { /* complete variables */
1180  static const char *const prefixes[] = { "no", "inv", "?", "&", 0 };
1181 
1182  pt++;
1183  /* loop through all the possible prefixes (no, inv, ...) */
1184  if (mutt_str_startswith(buf, "set"))
1185  {
1186  for (int num = 0; prefixes[num]; num++)
1187  {
1188  if (mutt_str_startswith(pt, prefixes[num]))
1189  {
1190  pt += mutt_str_len(prefixes[num]);
1191  break;
1192  }
1193  }
1194  }
1195 
1196  /* first TAB. Collect all the matches */
1197  if (numtabs == 1)
1198  {
1199  NumMatched = 0;
1200  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
1201  memset(Matches, 0, MatchesListsize);
1202  memset(Completed, 0, sizeof(Completed));
1203 
1204  struct HashElem *he = NULL;
1205  struct HashElem **list = get_elem_list(NeoMutt->sub->cs);
1206  for (size_t i = 0; list[i]; i++)
1207  {
1208  he = list[i];
1209  const int type = DTYPE(he->type);
1210 
1211  if ((type == DT_SYNONYM) || (type & DT_DEPRECATED))
1212  continue;
1213 
1214  candidate(UserTyped, he->key.strkey, Completed, sizeof(Completed));
1215  }
1216  FREE(&list);
1217 
1218  TAILQ_FOREACH(myv, &MyVars, entries)
1219  {
1220  candidate(UserTyped, myv->name, Completed, sizeof(Completed));
1221  }
1224 
1225  /* All matches are stored. Longest non-ambiguous string is ""
1226  * i.e. don't change 'buf'. Fake successful return this time */
1227  if (UserTyped[0] == '\0')
1228  return 1;
1229  }
1230 
1231  if ((Completed[0] == 0) && UserTyped[0])
1232  return 0;
1233 
1234  /* NumMatched will _always_ be at least 1 since the initial
1235  * user-typed string is always stored */
1236  if ((numtabs == 1) && (NumMatched == 2))
1237  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1238  else if ((numtabs > 1) && (NumMatched > 2))
1239  {
1240  /* cycle through all the matches */
1241  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1242  }
1243 
1244  strncpy(pt, Completed, buf + buflen - pt - spaces);
1245  }
1246  else if (mutt_str_startswith(buf, "exec"))
1247  {
1248  const struct Binding *menu = km_get_table(CurrentMenu);
1249 
1250  if (!menu && (CurrentMenu != MENU_PAGER))
1251  menu = OpGeneric;
1252 
1253  pt++;
1254  /* first TAB. Collect all the matches */
1255  if (numtabs == 1)
1256  {
1257  NumMatched = 0;
1258  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
1259  memset(Matches, 0, MatchesListsize);
1260  memset(Completed, 0, sizeof(Completed));
1261  for (int num = 0; menu[num].name; num++)
1262  candidate(UserTyped, menu[num].name, Completed, sizeof(Completed));
1263  /* try the generic menu */
1264  if ((Completed[0] == '\0') && (CurrentMenu != MENU_PAGER))
1265  {
1266  menu = OpGeneric;
1267  for (int num = 0; menu[num].name; num++)
1268  candidate(UserTyped, menu[num].name, Completed, sizeof(Completed));
1269  }
1272 
1273  /* All matches are stored. Longest non-ambiguous string is ""
1274  * i.e. don't change 'buf'. Fake successful return this time */
1275  if (UserTyped[0] == '\0')
1276  return 1;
1277  }
1278 
1279  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1280  return 0;
1281 
1282  /* NumMatched will _always_ be at least 1 since the initial
1283  * user-typed string is always stored */
1284  if ((numtabs == 1) && (NumMatched == 2))
1285  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1286  else if ((numtabs > 1) && (NumMatched > 2))
1287  {
1288  /* cycle through all the matches */
1289  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1290  }
1291 
1292  strncpy(pt, Completed, buf + buflen - pt - spaces);
1293  }
1294  else
1295  return 0;
1296 
1297  return 1;
1298 }
1299 
1308 int mutt_label_complete(char *buf, size_t buflen, int numtabs)
1309 {
1310  char *pt = buf;
1311  int spaces; /* keep track of the number of leading spaces on the line */
1312 
1313  if (!Context || !Context->mailbox->label_hash)
1314  return 0;
1315 
1316  SKIPWS(buf);
1317  spaces = buf - pt;
1318 
1319  /* first TAB. Collect all the matches */
1320  if (numtabs == 1)
1321  {
1322  struct HashElem *entry = NULL;
1323  struct HashWalkState state = { 0 };
1324 
1325  NumMatched = 0;
1326  mutt_str_copy(UserTyped, buf, sizeof(UserTyped));
1327  memset(Matches, 0, MatchesListsize);
1328  memset(Completed, 0, sizeof(Completed));
1329  while ((entry = mutt_hash_walk(Context->mailbox->label_hash, &state)))
1330  candidate(UserTyped, entry->key.strkey, Completed, sizeof(Completed));
1332  qsort(Matches, NumMatched, sizeof(char *), (sort_t) mutt_istr_cmp);
1334 
1335  /* All matches are stored. Longest non-ambiguous string is ""
1336  * i.e. don't change 'buf'. Fake successful return this time */
1337  if (UserTyped[0] == '\0')
1338  return 1;
1339  }
1340 
1341  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1342  return 0;
1343 
1344  /* NumMatched will _always_ be at least 1 since the initial
1345  * user-typed string is always stored */
1346  if ((numtabs == 1) && (NumMatched == 2))
1347  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1348  else if ((numtabs > 1) && (NumMatched > 2))
1349  {
1350  /* cycle through all the matches */
1351  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1352  }
1353 
1354  /* return the completed label */
1355  strncpy(buf, Completed, buflen - spaces);
1356 
1357  return 1;
1358 }
1359 
1360 #ifdef USE_NOTMUCH
1361 
1372 bool mutt_nm_query_complete(char *buf, size_t buflen, int pos, int numtabs)
1373 {
1374  char *pt = buf;
1375  int spaces;
1376 
1377  SKIPWS(buf);
1378  spaces = buf - pt;
1379 
1380  pt = (char *) mutt_strn_rfind((char *) buf, pos, "tag:");
1381  if (pt)
1382  {
1383  pt += 4;
1384  if (numtabs == 1)
1385  {
1386  /* First TAB. Collect all the matches */
1388 
1389  /* All matches are stored. Longest non-ambiguous string is ""
1390  * i.e. don't change 'buf'. Fake successful return this time. */
1391  if (UserTyped[0] == '\0')
1392  return true;
1393  }
1394 
1395  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1396  return false;
1397 
1398  /* NumMatched will _always_ be at least 1 since the initial
1399  * user-typed string is always stored */
1400  if ((numtabs == 1) && (NumMatched == 2))
1401  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1402  else if ((numtabs > 1) && (NumMatched > 2))
1403  {
1404  /* cycle through all the matches */
1405  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1406  }
1407 
1408  /* return the completed query */
1409  strncpy(pt, Completed, buf + buflen - pt - spaces);
1410  }
1411  else
1412  return false;
1413 
1414  return true;
1415 }
1416 #endif
1417 
1418 #ifdef USE_NOTMUCH
1419 
1429 bool mutt_nm_tag_complete(char *buf, size_t buflen, int numtabs)
1430 {
1431  if (!buf)
1432  return false;
1433 
1434  char *pt = buf;
1435 
1436  /* Only examine the last token */
1437  char *last_space = strrchr(buf, ' ');
1438  if (last_space)
1439  pt = (last_space + 1);
1440 
1441  /* Skip the +/- */
1442  if ((pt[0] == '+') || (pt[0] == '-'))
1443  pt++;
1444 
1445  if (numtabs == 1)
1446  {
1447  /* First TAB. Collect all the matches */
1449 
1450  /* All matches are stored. Longest non-ambiguous string is ""
1451  * i.e. don't change 'buf'. Fake successful return this time. */
1452  if (UserTyped[0] == '\0')
1453  return true;
1454  }
1455 
1456  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1457  return false;
1458 
1459  /* NumMatched will _always_ be at least 1 since the initial
1460  * user-typed string is always stored */
1461  if ((numtabs == 1) && (NumMatched == 2))
1462  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1463  else if ((numtabs > 1) && (NumMatched > 2))
1464  {
1465  /* cycle through all the matches */
1466  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1467  }
1468 
1469  /* return the completed query */
1470  strncpy(pt, Completed, buf + buflen - pt);
1471 
1472  return true;
1473 }
1474 #endif
1475 
1482 int mutt_var_value_complete(char *buf, size_t buflen, int pos)
1483 {
1484  char *pt = buf;
1485 
1486  if (buf[0] == '\0')
1487  return 0;
1488 
1489  SKIPWS(buf);
1490  const int spaces = buf - pt;
1491 
1492  pt = buf + pos - spaces;
1493  while ((pt > buf) && !isspace((unsigned char) *pt))
1494  pt--;
1495  pt++; /* move past the space */
1496  if (*pt == '=') /* abort if no var before the '=' */
1497  return 0;
1498 
1499  if (mutt_str_startswith(buf, "set"))
1500  {
1501  const char *myvarval = NULL;
1502  char var[256];
1503  mutt_str_copy(var, pt, sizeof(var));
1504  /* ignore the trailing '=' when comparing */
1505  int vlen = mutt_str_len(var);
1506  if (vlen == 0)
1507  return 0;
1508 
1509  var[vlen - 1] = '\0';
1510 
1511  struct HashElem *he = cs_subset_lookup(NeoMutt->sub, var);
1512  if (!he)
1513  {
1514  myvarval = myvar_get(var);
1515  if (myvarval)
1516  {
1517  struct Buffer pretty = mutt_buffer_make(256);
1518  pretty_var(myvarval, &pretty);
1519  snprintf(pt, buflen - (pt - buf), "%s=%s", var, pretty.data);
1520  mutt_buffer_dealloc(&pretty);
1521  return 1;
1522  }
1523  return 0; /* no such variable. */
1524  }
1525  else
1526  {
1527  struct Buffer value = mutt_buffer_make(256);
1528  struct Buffer pretty = mutt_buffer_make(256);
1529  int rc = cs_subset_he_string_get(NeoMutt->sub, he, &value);
1530  if (CSR_RESULT(rc) == CSR_SUCCESS)
1531  {
1532  pretty_var(value.data, &pretty);
1533  snprintf(pt, buflen - (pt - buf), "%s=%s", var, pretty.data);
1534  mutt_buffer_dealloc(&value);
1535  mutt_buffer_dealloc(&pretty);
1536  return 0;
1537  }
1538  mutt_buffer_dealloc(&value);
1539  mutt_buffer_dealloc(&pretty);
1540  return 1;
1541  }
1542  }
1543  return 0;
1544 }
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
Convenience wrapper for the gui headers.
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:416
int source_rc(const char *rcfile_path, struct Buffer *err)
Read an initialization file.
int mutt_istr_cmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:580
#define mutt_warning(...)
Definition: logging.h:82
The "current" mailbox.
Definition: context.h:38
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:201
struct RegexList SubscribedLists
List of regexes to match subscribed mailing lists.
Definition: globals.c:52
union HashKey key
Key representing the data.
Definition: hash.h:46
void mutt_comp_init(void)
Setup feature commands.
Definition: compress.c:66
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:522
Container for lots of config items.
Definition: set.h:228
Manage keymappings.
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
Miscellaneous email parsing routines.
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
IMAP network mailbox.
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define DT_LONG
a number (long)
Definition: types.h:33
void mutt_ch_set_charset(const char *charset)
Update the records for a new character set.
Definition: charset.c:1003
intptr_t data
Data or flags to pass to the command.
Definition: mutt_commands.h:59
#define mutt_perror(...)
Definition: logging.h:85
CommandResult
Error codes for command_t parse functions.
Definition: mutt_commands.h:34
Config/command parsing.
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
Error: Can&#39;t help the user.
Definition: mutt_commands.h:36
struct ReplaceList SubjectRegexList
List of regexes to tidy the view of the email&#39;s subject.
Definition: globals.c:53
Structs that make up an email.
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer&#39;s contents to another Buffer.
Definition: buffer.c:445
The "currently-open" mailbox.
void mutt_lua_init(void)
Setup feature commands.
Definition: mutt_lua.c:452
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
static char * getmailname(void)
Try to retrieve the FQDN from mailname files.
Definition: init.c:285
static int NumMatched
Definition: init.c:86
struct HashTable * label_hash
Hash Table for x-labels.
Definition: mailbox.h:129
struct ListHead InlineAllow
List of inline types to counted.
Definition: mutt_parse.c:40
enum CommandResult mutt_parse_hook(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;hook&#39; family of commands - Implements Command::parse()
Definition: hook.c:85
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:447
int mutt_label_complete(char *buf, size_t buflen, int numtabs)
Complete a label name.
Definition: init.c:1308
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:137
size_t pretty_var(const char *str, struct Buffer *buf)
Escape and stringify a config item value.
Definition: dump.c:83
void mutt_list_free_type(struct ListHead *h, list_free_t fn)
Free a List of type.
Definition: list.c:144
Cursor to iterate through a Hash Table.
Definition: hash.h:119
int log_disp_terminal(time_t stamp, const char *file, int line, const char *function, enum LogLevel level,...)
Save a log line to the terminal - Implements log_dispatcher_t.
Definition: logging.c:441
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
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
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:76
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
HookFlags mutt_get_hook_type(const char *name)
Find a hook by name.
Definition: init.c:695
struct RegexList UnSubscribedLists
List of regexes to blacklist false matches in SubscribedLists.
Definition: globals.c:49
bool mutt_nm_tag_complete(char *buf, size_t buflen, int numtabs)
Complete to the nearest notmuch tag.
Definition: init.c:1429
String manipulation buffer.
Definition: buffer.h:33
static int execute_commands(struct ListHead *p)
Execute a set of NeoMutt commands.
Definition: init.c:212
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:1039
WHERE char * C_Realname
Config: Real name of the user.
Definition: mutt_globals.h:105
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
void alias_init(void)
Set up the Alias globals.
Definition: alias.c:650
#define _(a)
Definition: message.h:28
void mutt_delete_hooks(HookFlags type)
Delete matching hooks.
Definition: hook.c:307
int mutt_command_complete(char *buf, size_t buflen, int pos, int numtabs)
Complete a command name.
Definition: init.c:1126
struct RegexList MailLists
List of regexes to match mailing lists.
Definition: globals.c:50
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:667
void mutt_commands_init(void)
static char ** nm_tags
Definition: init.c:94
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:48
A user-callable command.
Definition: mutt_commands.h:45
const char * name
Name of the command.
Definition: mutt_commands.h:47
WHERE char * C_Hostname
Config: Fully-qualified domain name of this machine.
Definition: mutt_globals.h:91
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:289
int cs_str_string_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: set.c:613
Index panel (list of emails)
Definition: keymap.h:80
A Command has been executed, Command.
Definition: notify_type.h:36
void imap_init(void)
Setup feature commands.
Definition: imap.c:79
size_t mutt_commands_array(struct Command **first)
Get Commands array.
bool mutt_nm_query_complete(char *buf, size_t buflen, int pos, int numtabs)
Complete to the nearest notmuch tag.
Definition: init.c:1372
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition: subset.c:168
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
uint32_t HookFlags
Flags for mutt_parse_hook(), e.g. MUTT_FOLDER_HOOK.
Definition: hook.h:43
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:348
char * name
Name of user variable.
Definition: myvar.h:33
static char * find_cfg(const char *home, const char *xdg_cfg_home)
Find a config file.
Definition: init.c:244
#define DT_QUAD
quad-option (no/yes/ask-no/ask-yes)
Definition: types.h:37
void mutt_replacelist_free(struct ReplaceList *rl)
Free a ReplaceList object.
Definition: regex.c:446
Container for Accounts, Notifications.
Definition: neomutt.h:36
#define DTYPE(x)
Mask for the Data Type.
Definition: types.h:44
struct HashElem ** get_elem_list(struct ConfigSet *cs)
Create a sorted list of all config items.
Definition: subset.c:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
Integrated Lua scripting.
Convenience wrapper for the config headers.
enum CommandResult(* parse)(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Function to parse a command.
Definition: mutt_commands.h:57
#define CSR_RESULT(x)
Definition: set.h:52
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:49
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:991
Email Address Handling.
Assorted sorting methods.
WHERE char ProtectedHeaderMarker[256]
Unique ANSI string to mark protected headers in an email.
Definition: mutt_globals.h:47
API for the header cache compression.
WHERE char * Username
User&#39;s login name.
Definition: mutt_globals.h:52
Some miscellaneous functions.
#define mutt_array_size(x)
Definition: memory.h:33
#define MUTT_HASH_STRCASECMP
use strcasecmp() to compare keys
Definition: hash.h:98
Pager pager (email viewer)
Definition: keymap.h:81
size_t dsize
Length of data.
Definition: buffer.h:37
void mutt_hist_read_file(void)
Read the History from a file.
Definition: history.c:568
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
WHERE enum MenuType CurrentMenu
Current Menu, e.g. MENU_PAGER.
Definition: mutt_globals.h:77
Header cache multiplexor.
struct Mailbox * mailbox
Definition: context.h:50
Many unsorted constants and some structs.
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:548
void clear_source_stack(void)
Free memory from the stack used for the souce command.
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:875
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
const struct Binding OpGeneric[]
Key bindings for the generic menu.
Definition: functions.c:53
int cs_subset_he_string_get(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *result)
Get a config item as a string.
Definition: subset.c:341
Convenience wrapper for the core headers.
A user-set variable.
Definition: myvar.h:31
struct MyVarList MyVars
List of all the user&#39;s custom config variables.
Definition: myvar.c:34
const char * name
name of the function
Definition: keymap.h:122
#define SKIPWS(ch)
Definition: string2.h:46
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
static char Completed[256]
Definition: init.c:87
int cs_str_initial_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set the initial value of a config item.
Definition: set.c:473
#define MUTT_TOKEN_NOSHELL
Don&#39;t expand environment variables.
Definition: mutt.h:79
bool config_init_main(struct ConfigSet *cs)
Email Aliases.
void alias_shutdown(void)
Clean up the Alias globals.
Definition: alias.c:660
Compressed mbox local mailbox type.
struct ListHead Ignore
List of header patterns to ignore.
Definition: globals.c:45
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
int(* sort_t)(const void *a, const void *b)
Prototype for a function to compare two emails.
Definition: sort.h:50
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
#define mutt_b2s(buf)
Definition: buffer.h:41
Read/write command history from/to a file.
#define MUTT_TOKEN_QUOTE
Don&#39;t interpret quotes.
Definition: mutt.h:74
Prototypes for many functions.
void add_to_stailq(struct ListHead *head, const char *str)
Add a string to a list.
Definition: muttlib.c:1700
#define MUTT_TOKEN_CONDENSE
^(char) to control chars (macros)
Definition: mutt.h:72
int mutt_query_variables(struct ListHead *queries, bool show_docs)
Implement the -Q command line flag.
Definition: init.c:1063
struct ListHead InlineExclude
List of inline types to ignore.
Definition: mutt_parse.c:41
Notmuch virtual mailbox type.
int mutt_init(struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:717
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
WHERE bool C_Suspend
Config: Allow the user to suspend NeoMutt using &#39;^Z&#39;.
Definition: mutt_globals.h:164
#define DT_PATH
a path to a file/directory
Definition: types.h:36
void nm_init(void)
Setup feature commands.
Definition: notmuch.c:87
struct RegexList NoSpamList
List of regexes to whitelist non-spam emails.
Definition: globals.c:43
static int MatchesListsize
Definition: init.c:90
void mutt_grouplist_init(void)
Initialize the GroupList singleton.
Definition: group.c:45
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1698
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
static void matches_ensure_morespace(int current)
Allocate more space for auto-completion.
Definition: init.c:103
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:129
Functions to parse commands in a config file.
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:394
WHERE char AttachmentMarker[256]
Unique ANSI string to mark PGP messages in an email.
Definition: mutt_globals.h:46
#define DT_DEPRECATED
Config item shouldn&#39;t be used any more.
Definition: types.h:79
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define CS_DUMP_NO_FLAGS
No flags are set.
Definition: dump.h:35
char * dptr
Current read/write position.
Definition: buffer.h:36
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
#define MUTT_TOKEN_SPACE
Don&#39;t treat whitespace as a term.
Definition: mutt.h:73
struct ListHead MailToAllow
List of permitted fields in a mailto: url.
Definition: globals.c:47
char * data
Pointer to data.
Definition: buffer.h:35
static bool get_hostname(struct ConfigSet *cs)
Find the Fully-Qualified Domain Name.
Definition: init.c:317
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:304
Definitions of NeoMutt commands.
GUI present the user with a selectable list.
struct HashTable * TagTransforms
Lookup table of alternative tag names.
Definition: tags.c:38
#define CS_DUMP_SHOW_DOCS
Show one-liner documentation for the config item.
Definition: dump.h:45
int nm_get_all_tags(struct Mailbox *m, char **tag_list, int *tag_count)
Fill a list with all notmuch tags.
Definition: notmuch.c:2117
#define MUTT_TOKEN_PLUS
Treat &#39;+&#39; as a special.
Definition: mutt.h:81
enum CommandResult mutt_parse_rc_buffer(struct Buffer *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:981
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
int cs_subset_str_string_get(const struct ConfigSubset *sub, const char *name, struct Buffer *result)
Get a config item as a string.
Definition: subset.c:357
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
Definition: color.h:129
void mutt_hist_init(void)
Create a set of empty History ring buffers.
Definition: history.c:447
void mutt_opts_free(void)
clean up before quitting
Definition: init.c:631
WHERE char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
const char * myvar_get(const char *var)
Get the value of a "my_" variable.
Definition: myvar.c:73
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
int mutt_set_xdg_path(enum XdgType type, struct Buffer *buf)
Find an XDG path or its fallback.
Definition: muttlib.c:1499
#define MUTT_TOKEN_SEMICOLON
Don&#39;t treat ; as special.
Definition: mutt.h:77
#define IS_SPACE(ch)
Definition: string2.h:38
void mutt_colors_free(struct Colors **ptr)
Free all the colours.
Definition: color.c:355
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:604
struct ReplaceList SpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:44
struct ListHead AttachExclude
List of attachment types to be ignored.
Definition: mutt_parse.c:39
static int complete_all_nm_tags(const char *pt)
Pass a list of Notmuch tags to the completion code.
Definition: init.c:155
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
Key value store.
Success: Command worked.
Definition: mutt_commands.h:38
char * data
String.
Definition: list.h:36
#define DT_SYNONYM
synonym for another variable
Definition: types.h:42
Definitions of user functions.
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
struct ListHead UnIgnore
List of header patterns to unignore (see)
Definition: globals.c:46
Log at debug level 1.
Definition: logging.h:40
Warning: Help given to the user.
Definition: mutt_commands.h:37
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user&#39;s real name in /etc/passwd.
Definition: muttlib.c:362
static char UserTyped[1024]
Definition: init.c:84
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:716
void dump_config_neo(struct ConfigSet *cs, struct HashElem *he, struct Buffer *value, struct Buffer *initial, ConfigDumpFlags flags, FILE *fp)
Dump the config in the style of NeoMutt.
Definition: dump.c:106
const char * strkey
String key.
Definition: hash.h:36
#define mutt_error(...)
Definition: logging.h:84
#define MUTT_TOKEN_MINUS
Treat &#39;-&#39; as a special.
Definition: mutt.h:82
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:56
static const char ** Matches
Definition: init.c:88
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
Connection Library.
struct RegexList UnMailLists
List of regexes to blacklist false matches in MailLists.
Definition: globals.c:51
const struct Binding * km_get_table(enum MenuType menu)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1306
#define MUTT_TOKEN_BACKTICK_VARS
Expand variables within backticks.
Definition: mutt.h:78
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition: hash.h:45
#define FREE(x)
Definition: memory.h:40
enum CommandResult parse_my_hdr(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;my_hdr&#39; command - Implements Command::parse()
size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:374
enum CommandResult mutt_parse_idxfmt_hook(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;index-format-hook&#39; command - Implements Command::parse()
Definition: hook.c:351
#define MUTT_HOOK_NO_FLAGS
No flags are set.
Definition: hook.h:44
#define STAILQ_EMPTY(head)
Definition: queue.h:345
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
struct HashElem * mutt_hash_walk(const struct HashTable *table, struct HashWalkState *state)
Iterate through all the HashElem&#39;s in a Hash Table.
Definition: hash.c:479
The item stored in a Hash Table.
Definition: hash.h:43
#define MUTT_TOKEN_EQUAL
Treat &#39;=&#39; as a special.
Definition: mutt.h:71
List of Mailboxes.
Definition: mailbox.h:150
int cs_str_reset(const struct ConfigSet *cs, const char *name, struct Buffer *err)
Reset a config item to its initial value.
Definition: set.c:408
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
void mutt_attachmatch_free(struct AttachMatch **ptr)
Free an AttachMatch - Implements list_free_t.
Definition: mutt_parse.c:240
uint16_t TokenFlags
Flags for mutt_extract_token(), e.g. MUTT_TOKEN_EQUAL.
Definition: mutt.h:69
void mutt_commands_free(void)
Free Commands array.
void mutt_grouplist_free(void)
Free GroupList singleton resource.
Definition: group.c:55
int getdnsdomainname(struct Buffer *domain)
Lookup the host&#39;s name using DNS.
Definition: getdomain.c:44
const char * mutt_strn_rfind(const char *haystack, size_t haystack_length, const char *needle)
Find last instance of a substring.
Definition: string.c:920
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
WHERE struct HashTable * TagFormats
Hash Table of tag-formats (tag -> format string)
Definition: mutt_globals.h:59
A List node for strings.
Definition: list.h:34
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
XDG system dir: /etc/xdg.
Definition: protos.h:48
Handling of personal config (&#39;my&#39; variables)
struct ListHead AttachAllow
List of attachment types to be counted.
Definition: mutt_parse.c:38
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:251
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:53
char * mutt_ch_get_langinfo_charset(void)
Get the user&#39;s choice of character set.
Definition: charset.c:462
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:75
#define STAILQ_FIRST(head)
Definition: queue.h:347
void mutt_hist_free(void)
Free all the history lists.
Definition: history.c:424
#define MUTT_HASH_NO_FLAGS
No flags are set.
Definition: hash.h:97
Mapping between a user key and a function.
Definition: keymap.h:120
#define DT_NUMBER
a number
Definition: types.h:35
#define DT_BOOL
boolean option
Definition: types.h:30
void mutt_regexlist_free(struct RegexList *rl)
Free a RegexList object.
Definition: regex.c:169
static void candidate(char *user, const char *src, char *dest, size_t dlen)
helper function for completion
Definition: init.c:126
bool C_VirtualSpoolfile
Config: (notmuch) Use the first virtual mailbox as a spool file.
Definition: config.c:51
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:70
#define MUTT_TOKEN_QUESTION
Treat &#39;?&#39; as a special.
Definition: mutt.h:80
void(* list_free_t)(void **ptr)
Prototype for a function to free List data.
Definition: list.h:45
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:152
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:152
int mutt_var_value_complete(char *buf, size_t buflen, int pos)
Complete a variable/value.
Definition: init.c:1482