NeoMutt  2022-04-29-81-g9c5a59
Teaching an old dog new tricks
DOXYGEN
init.h File Reference

Config/command parsing. More...

#include <stddef.h>
#include <stdbool.h>
#include "core/lib.h"
#include "mutt.h"
#include "hook.h"
+ Include dependency graph for init.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void init_config (struct ConfigSet *cs)
 Initialise the config system. More...
 
int mutt_command_complete (char *buf, size_t buflen, int pos, int numtabs)
 Complete a command name. More...
 
int mutt_extract_token (struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
 Extract one token from a string. More...
 
HookFlags mutt_get_hook_type (const char *name)
 Find a hook by name. More...
 
int mutt_init (struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands)
 Initialise NeoMutt. More...
 
int mutt_label_complete (char *buf, size_t buflen, int numtabs)
 Complete a label name. More...
 
bool mutt_nm_query_complete (char *buf, size_t buflen, int pos, int numtabs)
 Complete to the nearest notmuch tag. More...
 
bool mutt_nm_tag_complete (char *buf, size_t buflen, int numtabs)
 Complete to the nearest notmuch tag. More...
 
void mutt_opts_free (void)
 Clean up before quitting. More...
 
enum CommandResult mutt_parse_rc_buffer (struct Buffer *line, struct Buffer *token, struct Buffer *err)
 Parse a line of user config. More...
 
enum CommandResult mutt_parse_rc_line (const char *line, struct Buffer *err)
 Parse a line of user config. More...
 
int mutt_query_variables (struct ListHead *queries, bool show_docs)
 Implement the -Q command line flag. More...
 
int mutt_var_value_complete (char *buf, size_t buflen, int pos)
 Complete a variable/value. More...
 

Detailed Description

Config/command parsing.

Authors
  • Michael R. Elkins
  • g10 Code GmbH

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file init.h.

Function Documentation

◆ init_config()

void init_config ( struct ConfigSet cs)

Initialise the config system.

Parameters
csConfig items

Definition at line 785 of file mutt_config.c.

786 {
787  init_types(cs);
788  init_variables(cs);
789 }
static void init_types(struct ConfigSet *cs)
Create the config types.
Definition: mutt_config.c:720
static void init_variables(struct ConfigSet *cs)
Define the config variables.
Definition: mutt_config.c:740
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_command_complete()

int mutt_command_complete ( char *  buf,
size_t  buflen,
int  pos,
int  numtabs 
)

Complete a command name.

Parameters
bufBuffer for the result
buflenLength of the buffer
posCursor position in the buffer
numtabsNumber of times the user has hit 'tab'
Return values
1Success, a match
0Error, no match

Definition at line 1128 of file init.c.

1129 {
1130  char *pt = buf;
1131  int spaces; /* keep track of the number of leading spaces on the line */
1132  struct MyVar *myv = NULL;
1133 
1134  SKIPWS(buf);
1135  spaces = buf - pt;
1136 
1137  pt = buf + pos - spaces;
1138  while ((pt > buf) && !isspace((unsigned char) *pt))
1139  pt--;
1140 
1141  if (pt == buf) /* complete cmd */
1142  {
1143  /* first TAB. Collect all the matches */
1144  if (numtabs == 1)
1145  {
1146  NumMatched = 0;
1147  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
1148  memset(Matches, 0, MatchesListsize);
1149  memset(Completed, 0, sizeof(Completed));
1150 
1151  struct Command *c = NULL;
1152  for (size_t num = 0, size = mutt_commands_array(&c); num < size; num++)
1153  candidate(UserTyped, c[num].name, Completed, sizeof(Completed));
1156 
1157  /* All matches are stored. Longest non-ambiguous string is ""
1158  * i.e. don't change 'buf'. Fake successful return this time */
1159  if (UserTyped[0] == '\0')
1160  return 1;
1161  }
1162 
1163  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1164  return 0;
1165 
1166  /* NumMatched will _always_ be at least 1 since the initial
1167  * user-typed string is always stored */
1168  if ((numtabs == 1) && (NumMatched == 2))
1169  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1170  else if ((numtabs > 1) && (NumMatched > 2))
1171  {
1172  /* cycle through all the matches */
1173  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1174  }
1175 
1176  /* return the completed command */
1177  strncpy(buf, Completed, buflen - spaces);
1178  }
1179  else if (mutt_str_startswith(buf, "set") || mutt_str_startswith(buf, "unset") ||
1180  mutt_str_startswith(buf, "reset") || mutt_str_startswith(buf, "toggle"))
1181  { /* complete variables */
1182  static const char *const prefixes[] = { "no", "inv", "?", "&", 0 };
1183 
1184  pt++;
1185  /* loop through all the possible prefixes (no, inv, ...) */
1186  if (mutt_str_startswith(buf, "set"))
1187  {
1188  for (int num = 0; prefixes[num]; num++)
1189  {
1190  if (mutt_str_startswith(pt, prefixes[num]))
1191  {
1192  pt += mutt_str_len(prefixes[num]);
1193  break;
1194  }
1195  }
1196  }
1197 
1198  /* first TAB. Collect all the matches */
1199  if (numtabs == 1)
1200  {
1201  NumMatched = 0;
1202  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
1203  memset(Matches, 0, MatchesListsize);
1204  memset(Completed, 0, sizeof(Completed));
1205 
1206  struct HashElem *he = NULL;
1207  struct HashElem **list = get_elem_list(NeoMutt->sub->cs);
1208  for (size_t i = 0; list[i]; i++)
1209  {
1210  he = list[i];
1211  const int type = DTYPE(he->type);
1212 
1213  if ((type == DT_SYNONYM) || (type & DT_DEPRECATED))
1214  continue;
1215 
1216  candidate(UserTyped, he->key.strkey, Completed, sizeof(Completed));
1217  }
1218  FREE(&list);
1219 
1220  TAILQ_FOREACH(myv, &MyVars, entries)
1221  {
1222  candidate(UserTyped, myv->name, Completed, sizeof(Completed));
1223  }
1226 
1227  /* All matches are stored. Longest non-ambiguous string is ""
1228  * i.e. don't change 'buf'. Fake successful return this time */
1229  if (UserTyped[0] == '\0')
1230  return 1;
1231  }
1232 
1233  if ((Completed[0] == 0) && UserTyped[0])
1234  return 0;
1235 
1236  /* NumMatched will _always_ be at least 1 since the initial
1237  * user-typed string is always stored */
1238  if ((numtabs == 1) && (NumMatched == 2))
1239  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1240  else if ((numtabs > 1) && (NumMatched > 2))
1241  {
1242  /* cycle through all the matches */
1243  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1244  }
1245 
1246  strncpy(pt, Completed, buf + buflen - pt - spaces);
1247  }
1248  else if (mutt_str_startswith(buf, "exec"))
1249  {
1250  const enum MenuType mtype = menu_get_current_type();
1251  const struct MenuFuncOp *funcs = km_get_table(mtype);
1252  if (!funcs && (mtype != MENU_PAGER))
1253  funcs = OpGeneric;
1254 
1255  pt++;
1256  /* first TAB. Collect all the matches */
1257  if (numtabs == 1)
1258  {
1259  NumMatched = 0;
1260  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
1261  memset(Matches, 0, MatchesListsize);
1262  memset(Completed, 0, sizeof(Completed));
1263  for (int num = 0; funcs[num].name; num++)
1264  candidate(UserTyped, funcs[num].name, Completed, sizeof(Completed));
1265  /* try the generic menu */
1266  if ((mtype != MENU_PAGER) && (mtype != MENU_GENERIC))
1267  {
1268  funcs = OpGeneric;
1269  for (int num = 0; funcs[num].name; num++)
1270  candidate(UserTyped, funcs[num].name, Completed, sizeof(Completed));
1271  }
1274 
1275  /* All matches are stored. Longest non-ambiguous string is ""
1276  * i.e. don't change 'buf'. Fake successful return this time */
1277  if (UserTyped[0] == '\0')
1278  return 1;
1279  }
1280 
1281  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1282  return 0;
1283 
1284  /* NumMatched will _always_ be at least 1 since the initial
1285  * user-typed string is always stored */
1286  if ((numtabs == 1) && (NumMatched == 2))
1287  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1288  else if ((numtabs > 1) && (NumMatched > 2))
1289  {
1290  /* cycle through all the matches */
1291  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1292  }
1293 
1294  strncpy(pt, Completed, buf + buflen - pt - spaces);
1295  }
1296  else
1297  return 0;
1298 
1299  return 1;
1300 }
const struct MenuFuncOp OpGeneric[]
Functions for the Generic Menu.
Definition: functions.c:287
static void candidate(char *user, const char *src, char *dest, size_t dlen)
Helper function for completion.
Definition: init.c:120
static int MatchesListsize
Definition: init.c:86
static char Completed[256]
Definition: init.c:83
static void matches_ensure_morespace(int current)
Allocate more space for auto-completion.
Definition: init.c:97
static char UserTyped[1024]
Definition: init.c:80
static const char ** Matches
Definition: init.c:84
static int NumMatched
Definition: init.c:82
const struct MenuFuncOp * km_get_table(enum MenuType mtype)
Lookup a Menu's functions.
Definition: keymap.c:1231
#define FREE(x)
Definition: memory.h:40
enum MenuType menu_get_current_type(void)
Get the type of the current Window.
Definition: menu.c:84
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
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:629
size_t mutt_commands_array(struct Command **first)
Get Commands array.
struct MyVarList MyVars
List of all the user's custom config variables.
Definition: myvar.c:34
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define SKIPWS(ch)
Definition: string2.h:46
const char * name
Name of the command.
Definition: command.h:50
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
The item stored in a Hash Table.
Definition: hash.h:44
union HashKey key
Key representing the data.
Definition: hash.h:46
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition: hash.h:45
Mapping between a function and an operation.
Definition: keymap.h:92
const char * name
Name of the function.
Definition: keymap.h:93
A user-set variable.
Definition: myvar.h:32
char * name
Name of user variable.
Definition: myvar.h:33
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct HashElem ** get_elem_list(struct ConfigSet *cs)
Create a sorted list of all config items.
Definition: subset.c:75
MenuType
Types of GUI selections.
Definition: type.h:36
@ MENU_GENERIC
Generic selection list.
Definition: type.h:45
@ MENU_PAGER
Pager pager (email viewer)
Definition: type.h:54
#define DTYPE(x)
Mask for the Data Type.
Definition: types.h:44
#define DT_DEPRECATED
Config item shouldn't be used any more.
Definition: types.h:77
#define DT_SYNONYM
synonym for another variable
Definition: types.h:42
const char * strkey
String key.
Definition: hash.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_extract_token()

int mutt_extract_token ( struct Buffer dest,
struct Buffer tok,
TokenFlags  flags 
)

Extract one token from a string.

Parameters
destBuffer for the result
tokBuffer containing tokens
flagsFlags, see TokenFlags
Return values
0Success
-1Error

Definition at line 398 of file init.c.

399 {
400  if (!dest || !tok)
401  return -1;
402 
403  char ch;
404  char qc = '\0'; /* quote char */
405  char *pc = NULL;
406 
407  /* Some callers used to rely on the (bad) assumption that dest->data would be
408  * non-NULL after calling this function. Perhaps I've missed a few cases, or
409  * a future caller might make the same mistake. */
410  if (!dest->data)
411  mutt_buffer_alloc(dest, 256);
412 
413  mutt_buffer_reset(dest);
414 
415  SKIPWS(tok->dptr);
416  while ((ch = *tok->dptr))
417  {
418  if (qc == '\0')
419  {
420  if ((IS_SPACE(ch) && !(flags & MUTT_TOKEN_SPACE)) ||
421  ((ch == '#') && !(flags & MUTT_TOKEN_COMMENT)) ||
422  ((ch == '+') && (flags & MUTT_TOKEN_PLUS)) ||
423  ((ch == '-') && (flags & MUTT_TOKEN_MINUS)) ||
424  ((ch == '=') && (flags & MUTT_TOKEN_EQUAL)) ||
425  ((ch == '?') && (flags & MUTT_TOKEN_QUESTION)) ||
426  ((ch == ';') && !(flags & MUTT_TOKEN_SEMICOLON)) ||
427  ((flags & MUTT_TOKEN_PATTERN) && strchr("~%=!|", ch)))
428  {
429  break;
430  }
431  }
432 
433  tok->dptr++;
434 
435  if (ch == qc)
436  qc = 0; /* end of quote */
437  else if (!qc && ((ch == '\'') || (ch == '"')) && !(flags & MUTT_TOKEN_QUOTE))
438  qc = ch;
439  else if ((ch == '\\') && (qc != '\''))
440  {
441  if (tok->dptr[0] == '\0')
442  return -1; /* premature end of token */
443  switch (ch = *tok->dptr++)
444  {
445  case 'c':
446  case 'C':
447  if (tok->dptr[0] == '\0')
448  return -1; /* premature end of token */
449  mutt_buffer_addch(dest, (toupper((unsigned char) tok->dptr[0]) - '@') & 0x7f);
450  tok->dptr++;
451  break;
452  case 'e':
453  mutt_buffer_addch(dest, '\033'); // Escape
454  break;
455  case 'f':
456  mutt_buffer_addch(dest, '\f');
457  break;
458  case 'n':
459  mutt_buffer_addch(dest, '\n');
460  break;
461  case 'r':
462  mutt_buffer_addch(dest, '\r');
463  break;
464  case 't':
465  mutt_buffer_addch(dest, '\t');
466  break;
467  default:
468  if (isdigit((unsigned char) ch) && isdigit((unsigned char) tok->dptr[0]) &&
469  isdigit((unsigned char) tok->dptr[1]))
470  {
471  mutt_buffer_addch(dest, (ch << 6) + (tok->dptr[0] << 3) + tok->dptr[1] - 3504);
472  tok->dptr += 2;
473  }
474  else
475  mutt_buffer_addch(dest, ch);
476  }
477  }
478  else if ((ch == '^') && (flags & MUTT_TOKEN_CONDENSE))
479  {
480  if (tok->dptr[0] == '\0')
481  return -1; /* premature end of token */
482  ch = *tok->dptr++;
483  if (ch == '^')
484  mutt_buffer_addch(dest, ch);
485  else if (ch == '[')
486  mutt_buffer_addch(dest, '\033'); // Escape
487  else if (isalpha((unsigned char) ch))
488  mutt_buffer_addch(dest, toupper((unsigned char) ch) - '@');
489  else
490  {
491  mutt_buffer_addch(dest, '^');
492  mutt_buffer_addch(dest, ch);
493  }
494  }
495  else if ((ch == '`') && (!qc || (qc == '"')))
496  {
497  FILE *fp = NULL;
498  pid_t pid;
499 
500  pc = tok->dptr;
501  do
502  {
503  pc = strpbrk(pc, "\\`");
504  if (pc)
505  {
506  /* skip any quoted chars */
507  if (*pc == '\\')
508  pc += 2;
509  }
510  } while (pc && (pc[0] != '`'));
511  if (!pc)
512  {
513  mutt_debug(LL_DEBUG1, "mismatched backticks\n");
514  return -1;
515  }
516  struct Buffer cmd;
517  mutt_buffer_init(&cmd);
518  *pc = '\0';
519  if (flags & MUTT_TOKEN_BACKTICK_VARS)
520  {
521  /* recursively extract tokens to interpolate variables */
522  mutt_extract_token(&cmd, tok,
525  }
526  else
527  {
528  cmd.data = mutt_str_dup(tok->dptr);
529  }
530  *pc = '`';
531  pid = filter_create(cmd.data, NULL, &fp, NULL);
532  if (pid < 0)
533  {
534  mutt_debug(LL_DEBUG1, "unable to fork command: %s\n", cmd.data);
535  FREE(&cmd.data);
536  return -1;
537  }
538 
539  tok->dptr = pc + 1;
540 
541  /* read line */
542  struct Buffer expn = mutt_buffer_make(0);
543  expn.data = mutt_file_read_line(NULL, &expn.dsize, fp, NULL, MUTT_RL_NO_FLAGS);
544  mutt_file_fclose(&fp);
545  int rc = filter_wait(pid);
546  if (rc != 0)
547  mutt_debug(LL_DEBUG1, "backticks exited code %d for command: %s\n", rc,
548  mutt_buffer_string(&cmd));
549  FREE(&cmd.data);
550 
551  /* if we got output, make a new string consisting of the shell output
552  * plus whatever else was left on the original line */
553  /* BUT: If this is inside a quoted string, directly add output to
554  * the token */
555  if (expn.data)
556  {
557  if (qc)
558  {
559  mutt_buffer_addstr(dest, expn.data);
560  }
561  else
562  {
563  struct Buffer *copy = mutt_buffer_pool_get();
564  mutt_buffer_fix_dptr(&expn);
565  mutt_buffer_copy(copy, &expn);
566  mutt_buffer_addstr(copy, tok->dptr);
567  mutt_buffer_copy(tok, copy);
568  mutt_buffer_seek(tok, 0);
570  }
571  FREE(&expn.data);
572  }
573  }
574  else if ((ch == '$') && (!qc || (qc == '"')) &&
575  ((tok->dptr[0] == '{') || isalpha((unsigned char) tok->dptr[0])))
576  {
577  const char *env = NULL;
578  char *var = NULL;
579 
580  if (tok->dptr[0] == '{')
581  {
582  pc = strchr(tok->dptr, '}');
583  if (pc)
584  {
585  var = mutt_strn_dup(tok->dptr + 1, pc - (tok->dptr + 1));
586  tok->dptr = pc + 1;
587 
588  if ((flags & MUTT_TOKEN_NOSHELL))
589  {
590  mutt_buffer_addch(dest, ch);
591  mutt_buffer_addch(dest, '{');
592  mutt_buffer_addstr(dest, var);
593  mutt_buffer_addch(dest, '}');
594  FREE(&var);
595  }
596  }
597  }
598  else
599  {
600  for (pc = tok->dptr; isalnum((unsigned char) *pc) || (pc[0] == '_'); pc++)
601  ; // do nothing
602 
603  var = mutt_strn_dup(tok->dptr, pc - tok->dptr);
604  tok->dptr = pc;
605  }
606  if (var)
607  {
608  struct Buffer result;
609  mutt_buffer_init(&result);
610  int rc = cs_subset_str_string_get(NeoMutt->sub, var, &result);
611 
612  if (CSR_RESULT(rc) == CSR_SUCCESS)
613  {
614  mutt_buffer_addstr(dest, result.data);
615  FREE(&result.data);
616  }
617  else if ((env = myvar_get(var)))
618  {
619  mutt_buffer_addstr(dest, env);
620  }
621  else if (!(flags & MUTT_TOKEN_NOSHELL) && (env = mutt_str_getenv(var)))
622  {
623  mutt_buffer_addstr(dest, env);
624  }
625  else
626  {
627  mutt_buffer_addch(dest, ch);
628  mutt_buffer_addstr(dest, var);
629  }
630  FREE(&var);
631  }
632  }
633  else
634  mutt_buffer_addch(dest, ch);
635  }
636  mutt_buffer_addch(dest, 0); /* terminate the string */
637  SKIPWS(tok->dptr);
638  return 0;
639 }
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
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
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
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
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
void mutt_buffer_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:468
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:447
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:720
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:398
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:428
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:904
#define MUTT_TOKEN_CONDENSE
^(char) to control chars (macros)
Definition: mutt.h:68
#define MUTT_TOKEN_BACKTICK_VARS
Expand variables within backticks.
Definition: mutt.h:74
#define MUTT_TOKEN_MINUS
Treat '-' as a special.
Definition: mutt.h:78
#define MUTT_TOKEN_PLUS
Treat '+' as a special.
Definition: mutt.h:77
#define MUTT_TOKEN_COMMENT
Don't reap comments.
Definition: mutt.h:72
#define MUTT_TOKEN_QUOTE
Don't interpret quotes.
Definition: mutt.h:70
#define MUTT_TOKEN_NOSHELL
Don't expand environment variables.
Definition: mutt.h:75
#define MUTT_TOKEN_SPACE
Don't treat whitespace as a term.
Definition: mutt.h:69
#define MUTT_TOKEN_SEMICOLON
Don't treat ; as special.
Definition: mutt.h:73
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:71
#define MUTT_TOKEN_EQUAL
Treat '=' as a special.
Definition: mutt.h:67
#define MUTT_TOKEN_QUESTION
Treat '?' as a special.
Definition: mutt.h:76
const char * myvar_get(const char *var)
Get the value of a "my_" variable.
Definition: myvar.c:92
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
#define IS_SPACE(ch)
Definition: string2.h:38
String manipulation buffer.
Definition: buffer.h:34
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
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:370
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_get_hook_type()

HookFlags mutt_get_hook_type ( const char *  name)

Find a hook by name.

Parameters
nameName to find
Return values
numHook ID, e.g. MUTT_FOLDER_HOOK
MUTT_HOOK_NO_FLAGSError, no matching hook

Definition at line 698 of file init.c.

699 {
700  struct Command *c = NULL;
701  for (size_t i = 0, size = mutt_commands_array(&c); i < size; i++)
702  {
703  if (((c[i].parse == mutt_parse_hook) || (c[i].parse == mutt_parse_idxfmt_hook)) &&
704  mutt_istr_equal(c[i].name, name))
705  {
706  return c[i].data;
707  }
708  }
709  return MUTT_HOOK_NO_FLAGS;
710 }
enum CommandResult mutt_parse_idxfmt_hook(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'index-format-hook' command - Implements Command::parse() -.
Definition: hook.c:405
enum CommandResult mutt_parse_hook(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'hook' family of commands - Implements Command::parse() -.
Definition: hook.c:125
#define MUTT_HOOK_NO_FLAGS
No flags are set.
Definition: hook.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
enum CommandResult(* parse)(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Definition: command.h:63
intptr_t data
Data or flags to pass to the command.
Definition: command.h:65
+ Here is the call graph for this function:

◆ mutt_init()

int mutt_init ( struct ConfigSet cs,
bool  skip_sys_rc,
struct ListHead *  commands 
)

Initialise NeoMutt.

Parameters
csConfig Set
skip_sys_rcIf true, don't read the system config file
commandsList of config commands to execute
Return values
0Success
1Error

Definition at line 720 of file init.c.

721 {
722  int need_pause = 0;
723  int rc = 1;
724  struct Buffer err = mutt_buffer_make(256);
725  struct Buffer buf = mutt_buffer_make(256);
726 
728  alias_init();
730 #ifdef USE_COMP_MBOX
731  mutt_comp_init();
732 #endif
733 #ifdef USE_IMAP
734  imap_init();
735 #endif
736 #ifdef USE_LUA
737  mutt_lua_init();
738 #endif
740 
741  menu_init();
742 #ifdef USE_SIDEBAR
743  sb_init();
744 #endif
745 #ifdef USE_NOTMUCH
746  nm_init();
747 #endif
748 
749  /* "$spool_file" precedence: config file, environment */
750  const char *p = mutt_str_getenv("MAIL");
751  if (!p)
752  p = mutt_str_getenv("MAILDIR");
753  if (!p)
754  {
755 #ifdef HOMESPOOL
756  mutt_buffer_concat_path(&buf, NONULL(HomeDir), MAILPATH);
757 #else
758  mutt_buffer_concat_path(&buf, MAILPATH, NONULL(Username));
759 #endif
760  p = mutt_buffer_string(&buf);
761  }
762  cs_str_initial_set(cs, "spool_file", p, NULL);
763  cs_str_reset(cs, "spool_file", NULL);
764 
765  p = mutt_str_getenv("REPLYTO");
766  if (p)
767  {
768  struct Buffer token;
769 
770  mutt_buffer_printf(&buf, "Reply-To: %s", p);
771  mutt_buffer_init(&token);
772  parse_my_hdr(&token, &buf, 0, &err); /* adds to UserHeader */
773  FREE(&token.data);
774  }
775 
776  p = mutt_str_getenv("EMAIL");
777  if (p)
778  {
779  cs_str_initial_set(cs, "from", p, NULL);
780  cs_str_reset(cs, "from", NULL);
781  }
782 
783  /* "$mailcap_path" precedence: config file, environment, code */
784  const char *env_mc = mutt_str_getenv("MAILCAPS");
785  if (env_mc)
786  cs_str_string_set(cs, "mailcap_path", env_mc, NULL);
787 
788  /* "$tmpdir" precedence: config file, environment, code */
789  const char *env_tmp = mutt_str_getenv("TMPDIR");
790  if (env_tmp)
791  cs_str_string_set(cs, "tmpdir", env_tmp, NULL);
792 
793  /* "$visual", "$editor" precedence: config file, environment, code */
794  const char *env_ed = mutt_str_getenv("VISUAL");
795  if (!env_ed)
796  env_ed = mutt_str_getenv("EDITOR");
797  if (!env_ed)
798  env_ed = "vi";
799  cs_str_initial_set(cs, "editor", env_ed, NULL);
800 
801  const char *const c_editor = cs_subset_string(NeoMutt->sub, "editor");
802  if (!c_editor)
803  cs_str_reset(cs, "editor", NULL);
804 
805  const char *charset = mutt_ch_get_langinfo_charset();
806  cs_str_initial_set(cs, "charset", charset, NULL);
807  cs_str_reset(cs, "charset", NULL);
808  mutt_ch_set_charset(charset);
809  FREE(&charset);
810 
811  Matches = mutt_mem_calloc(MatchesListsize, sizeof(char *));
812 
813 #ifdef HAVE_GETSID
814  /* Unset suspend by default if we're the session leader */
815  if (getsid(0) == getpid())
816  cs_subset_str_native_set(NeoMutt->sub, "suspend", false, NULL);
817 #endif
818 
819  /* RFC2368, "4. Unsafe headers"
820  * The creator of a mailto URL can't expect the resolver of a URL to
821  * understand more than the "subject" and "body" headers. Clients that
822  * resolve mailto URLs into mail messages should be able to correctly
823  * create RFC822-compliant mail messages using the "subject" and "body"
824  * headers. */
825  add_to_stailq(&MailToAllow, "body");
826  add_to_stailq(&MailToAllow, "subject");
827  /* Cc, In-Reply-To, and References help with not breaking threading on
828  * mailing lists, see https://github.com/neomutt/neomutt/issues/115 */
829  add_to_stailq(&MailToAllow, "cc");
830  add_to_stailq(&MailToAllow, "in-reply-to");
831  add_to_stailq(&MailToAllow, "references");
832 
833  if (STAILQ_EMPTY(&Muttrc))
834  {
835  const char *xdg_cfg_home = mutt_str_getenv("XDG_CONFIG_HOME");
836 
837  if (!xdg_cfg_home && HomeDir)
838  {
839  mutt_buffer_printf(&buf, "%s/.config", HomeDir);
840  xdg_cfg_home = mutt_buffer_string(&buf);
841  }
842 
843  char *config = find_cfg(HomeDir, xdg_cfg_home);
844  if (config)
845  {
846  mutt_list_insert_tail(&Muttrc, config);
847  }
848  }
849  else
850  {
851  struct ListNode *np = NULL;
852  STAILQ_FOREACH(np, &Muttrc, entries)
853  {
854  mutt_buffer_strcpy(&buf, np->data);
855  FREE(&np->data);
857  np->data = mutt_buffer_strdup(&buf);
858  if (access(np->data, F_OK))
859  {
860  mutt_perror(np->data);
861  goto done; // TEST10: neomutt -F missing
862  }
863  }
864  }
865 
866  if (!STAILQ_EMPTY(&Muttrc))
867  {
868  cs_str_string_set(cs, "alias_file", STAILQ_FIRST(&Muttrc)->data, NULL);
869  }
870 
871  /* Process the global rc file if it exists and the user hasn't explicitly
872  * requested not to via "-n". */
873  if (!skip_sys_rc)
874  {
875  do
876  {
878  break;
879 
880  mutt_buffer_printf(&buf, "%s/neomuttrc", SYSCONFDIR);
881  if (access(mutt_buffer_string(&buf), F_OK) == 0)
882  break;
883 
884  mutt_buffer_printf(&buf, "%s/Muttrc", SYSCONFDIR);
885  if (access(mutt_buffer_string(&buf), F_OK) == 0)
886  break;
887 
888  mutt_buffer_printf(&buf, "%s/neomuttrc", PKGDATADIR);
889  if (access(mutt_buffer_string(&buf), F_OK) == 0)
890  break;
891 
892  mutt_buffer_printf(&buf, "%s/Muttrc", PKGDATADIR);
893  } while (false);
894 
895  if (access(mutt_buffer_string(&buf), F_OK) == 0)
896  {
897  if (source_rc(mutt_buffer_string(&buf), &err) != 0)
898  {
899  mutt_error("%s", err.data);
900  need_pause = 1; // TEST11: neomutt (error in /etc/neomuttrc)
901  }
902  }
903  }
904 
905  /* Read the user's initialization file. */
906  struct ListNode *np = NULL;
907  STAILQ_FOREACH(np, &Muttrc, entries)
908  {
909  if (np->data)
910  {
911  if (source_rc(np->data, &err) != 0)
912  {
913  mutt_error("%s", err.data);
914  need_pause = 1; // TEST12: neomutt (error in ~/.neomuttrc)
915  }
916  }
917  }
918 
919  if (execute_commands(commands) != 0)
920  need_pause = 1; // TEST13: neomutt -e broken
921 
922  if (!get_hostname(cs))
923  goto done;
924 
925  {
926  char name[256] = { 0 };
927  const char *c_real_name = cs_subset_string(NeoMutt->sub, "real_name");
928  if (!c_real_name)
929  {
930  struct passwd *pw = getpwuid(getuid());
931  if (pw)
932  c_real_name = mutt_gecos_name(name, sizeof(name), pw);
933  }
934  cs_str_initial_set(cs, "real_name", c_real_name, NULL);
935  cs_str_reset(cs, "real_name", NULL);
936  }
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  const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
946  mutt_file_mkdir(c_tmpdir, S_IRWXU);
947 
948  mutt_hist_init();
950 
951 #ifdef USE_NOTMUCH
952  const bool c_virtual_spool_file = cs_subset_bool(NeoMutt->sub, "virtual_spool_file");
953  if (c_virtual_spool_file)
954  {
955  /* Find the first virtual folder and open it */
956  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
958  struct MailboxNode *mp = STAILQ_FIRST(&ml);
959  if (mp)
960  cs_str_string_set(cs, "spool_file", mailbox_path(mp->mailbox), NULL);
962  }
963 #endif
964  rc = 0;
965 
966 done:
967  mutt_buffer_dealloc(&err);
968  mutt_buffer_dealloc(&buf);
969  return rc;
970 }
void alias_init(void)
Set up the Alias globals.
Definition: alias.c:678
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:432
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
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
int source_rc(const char *rcfile_path, struct Buffer *err)
Read an initialization file.
void mutt_comp_init(void)
Setup feature commands.
Definition: compress.c:70
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:498
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:930
struct ListHead MailToAllow
List of permitted fields in a mailto: url.
Definition: globals.c:37
void mutt_grouplist_init(void)
Initialize the GroupList singleton.
Definition: group.c:90
enum CommandResult parse_my_hdr(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'my_hdr' command - Implements Command::parse() -.
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:440
#define mutt_error(...)
Definition: logging.h:87
#define mutt_perror(...)
Definition: logging.h:88
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
void mutt_hist_read_file(void)
Read the History from a file.
Definition: history.c:593
void mutt_hist_init(void)
Create a set of empty History ring buffers.
Definition: history.c:465
void imap_init(void)
Setup feature commands.
Definition: imap.c:84
static int execute_commands(struct ListHead *p)
Execute a set of NeoMutt commands.
Definition: init.c:207
static bool get_hostname(struct ConfigSet *cs)
Find the Fully-Qualified Domain Name.
Definition: init.c:312
static char * find_cfg(const char *home, const char *xdg_cfg_home)
Find a config file.
Definition: init.c:239
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 log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:346
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:211
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void menu_init(void)
Initialise all the Menus.
Definition: menu.c:74
char * mutt_ch_get_langinfo_charset(void)
Get the user's choice of character set.
Definition: charset.c:461
void mutt_ch_set_charset(const char *charset)
Update the records for a new character set.
Definition: charset.c:1002
void mutt_commands_init(void)
Initialize commands array and register default commands.
struct CommandArray commands
struct ListHead Muttrc
List of config files to read.
Definition: mutt_globals.h:64
char * Username
User's login name.
Definition: mutt_globals.h:52
void mutt_lua_init(void)
Setup feature commands.
Definition: mutt_lua.c:469
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:321
void add_to_stailq(struct ListHead *head, const char *str)
Add a string to a list.
Definition: muttlib.c:1718
int mutt_set_xdg_path(enum XdgType type, struct Buffer *buf)
Find an XDG path or its fallback.
Definition: muttlib.c:1509
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user's real name in /etc/passwd.
Definition: muttlib.c:360
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:141
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:164
void nm_init(void)
Setup feature commands.
Definition: notmuch.c:99
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:53
@ XDG_CONFIG_DIRS
XDG system dir: /etc/xdg.
Definition: protos.h:45
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_EMPTY(head)
Definition: queue.h:348
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:458
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:393
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:595
void sb_init(void)
Set up the Sidebar.
Definition: sidebar.c:196
#define NONULL(x)
Definition: string2.h:37
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
List of Mailboxes.
Definition: mailbox.h:154
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:155
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
void driver_tags_init(void)
Initialize structures used for tags.
Definition: tags.c:218
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_label_complete()

int mutt_label_complete ( char *  buf,
size_t  buflen,
int  numtabs 
)

Complete a label name.

Parameters
bufBuffer for the result
buflenLength of the buffer
numtabsNumber of times the user has hit 'tab'
Return values
1Success, a match
0Error, no match

Definition at line 1310 of file init.c.

1311 {
1312  char *pt = buf;
1313  int spaces; /* keep track of the number of leading spaces on the line */
1314 
1315  struct Mailbox *m_cur = get_current_mailbox();
1316  if (!m_cur || !m_cur->label_hash)
1317  return 0;
1318 
1319  SKIPWS(buf);
1320  spaces = buf - pt;
1321 
1322  /* first TAB. Collect all the matches */
1323  if (numtabs == 1)
1324  {
1325  struct HashElem *entry = NULL;
1326  struct HashWalkState state = { 0 };
1327 
1328  NumMatched = 0;
1329  mutt_str_copy(UserTyped, buf, sizeof(UserTyped));
1330  memset(Matches, 0, MatchesListsize);
1331  memset(Completed, 0, sizeof(Completed));
1332  while ((entry = mutt_hash_walk(m_cur->label_hash, &state)))
1333  candidate(UserTyped, entry->key.strkey, Completed, sizeof(Completed));
1335  qsort(Matches, NumMatched, sizeof(char *), (sort_t) mutt_istr_cmp);
1337 
1338  /* All matches are stored. Longest non-ambiguous string is ""
1339  * i.e. don't change 'buf'. Fake successful return this time */
1340  if (UserTyped[0] == '\0')
1341  return 1;
1342  }
1343 
1344  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1345  return 0;
1346 
1347  /* NumMatched will _always_ be at least 1 since the initial
1348  * user-typed string is always stored */
1349  if ((numtabs == 1) && (NumMatched == 2))
1350  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1351  else if ((numtabs > 1) && (NumMatched > 2))
1352  {
1353  /* cycle through all the matches */
1354  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1355  }
1356 
1357  /* return the completed label */
1358  strncpy(buf, Completed, buflen - spaces);
1359 
1360  return 1;
1361 }
struct HashElem * mutt_hash_walk(const struct HashTable *table, struct HashWalkState *state)
Iterate through all the HashElem's in a Hash Table.
Definition: hash.c:489
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:606
int mutt_istr_cmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:460
int(* sort_t)(const void *a, const void *b)
Definition: sort.h:49
Cursor to iterate through a Hash Table.
Definition: hash.h:132
A mailbox.
Definition: mailbox.h:79
struct HashTable * label_hash
Hash Table for x-labels.
Definition: mailbox.h:126
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_nm_query_complete()

bool mutt_nm_query_complete ( char *  buf,
size_t  buflen,
int  pos,
int  numtabs 
)

Complete to the nearest notmuch tag.

Parameters
bufBuffer for the result
buflenLength of the buffer
posCursor position in the buffer
numtabsNumber of times the user has hit 'tab'
Return values
trueSuccess, a match
falseError, no match

Complete the nearest "tag:"-prefixed string previous to pos.

Definition at line 1375 of file init.c.

1376 {
1377  char *pt = buf;
1378  int spaces;
1379 
1380  SKIPWS(buf);
1381  spaces = buf - pt;
1382 
1383  pt = (char *) mutt_strn_rfind((char *) buf, pos, "tag:");
1384  if (pt)
1385  {
1386  pt += 4;
1387  if (numtabs == 1)
1388  {
1389  /* First TAB. Collect all the matches */
1391 
1392  /* All matches are stored. Longest non-ambiguous string is ""
1393  * i.e. don't change 'buf'. Fake successful return this time. */
1394  if (UserTyped[0] == '\0')
1395  return true;
1396  }
1397 
1398  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1399  return false;
1400 
1401  /* NumMatched will _always_ be at least 1 since the initial
1402  * user-typed string is always stored */
1403  if ((numtabs == 1) && (NumMatched == 2))
1404  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1405  else if ((numtabs > 1) && (NumMatched > 2))
1406  {
1407  /* cycle through all the matches */
1408  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1409  }
1410 
1411  /* return the completed query */
1412  strncpy(pt, Completed, buf + buflen - pt - spaces);
1413  }
1414  else
1415  return false;
1416 
1417  return true;
1418 }
static int complete_all_nm_tags(const char *pt)
Pass a list of Notmuch tags to the completion code.
Definition: init.c:149
const char * mutt_strn_rfind(const char *haystack, size_t haystack_length, const char *needle)
Find last instance of a substring.
Definition: string.c:833
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_nm_tag_complete()

bool mutt_nm_tag_complete ( char *  buf,
size_t  buflen,
int  numtabs 
)

Complete to the nearest notmuch tag.

Parameters
bufBuffer for the result
buflenLength of the buffer
numtabsNumber of times the user has hit 'tab'
Return values
trueSuccess, a match
falseError, no match

Complete the nearest "+" or "-" -prefixed string previous to pos.

Definition at line 1432 of file init.c.

1433 {
1434  if (!buf)
1435  return false;
1436 
1437  char *pt = buf;
1438 
1439  /* Only examine the last token */
1440  char *last_space = strrchr(buf, ' ');
1441  if (last_space)
1442  pt = (last_space + 1);
1443 
1444  /* Skip the +/- */
1445  if ((pt[0] == '+') || (pt[0] == '-'))
1446  pt++;
1447 
1448  if (numtabs == 1)
1449  {
1450  /* First TAB. Collect all the matches */
1452 
1453  /* All matches are stored. Longest non-ambiguous string is ""
1454  * i.e. don't change 'buf'. Fake successful return this time. */
1455  if (UserTyped[0] == '\0')
1456  return true;
1457  }
1458 
1459  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1460  return false;
1461 
1462  /* NumMatched will _always_ be at least 1 since the initial
1463  * user-typed string is always stored */
1464  if ((numtabs == 1) && (NumMatched == 2))
1465  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1466  else if ((numtabs > 1) && (NumMatched > 2))
1467  {
1468  /* cycle through all the matches */
1469  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1470  }
1471 
1472  /* return the completed query */
1473  strncpy(pt, Completed, buf + buflen - pt);
1474 
1475  return true;
1476 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_opts_free()

void mutt_opts_free ( void  )

Clean up before quitting.

Definition at line 644 of file init.c.

645 {
647 
648  alias_shutdown();
649 #ifdef USE_SIDEBAR
650  sb_shutdown();
651 #endif
652 
658 
661 
662  /* Lists of strings */
672 
674 
676  FREE(&HomeDir);
677  FREE(&LastFolder);
679  FREE(&Username);
680 
682 
684 
685  mutt_hist_free();
686  mutt_keys_free();
687 
690 }
void alias_shutdown(void)
Clean up the Alias globals.
Definition: alias.c:686
void mutt_colors_cleanup(void)
Cleanup all the colours.
Definition: color.c:70
void clear_source_stack(void)
Free memory from the stack used for the source command.
struct ReplaceList SpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:34
struct RegexList SubscribedLists
List of regexes to match subscribed mailing lists.
Definition: globals.c:43
struct RegexList UnSubscribedLists
List of regexes to blacklist false matches in SubscribedLists.
Definition: globals.c:40
struct RegexList UnMailLists
List of regexes to blacklist false matches in MailLists.
Definition: globals.c:42
struct RegexList MailLists
List of regexes to match mailing lists.
Definition: globals.c:41
struct ListHead Ignore
List of header patterns to ignore.
Definition: globals.c:35
struct RegexList NoSpamList
List of regexes to whitelist non-spam emails.
Definition: globals.c:33
struct ListHead UnIgnore
List of header patterns to unignore (see)
Definition: globals.c:36
void mutt_grouplist_free(void)
Free GroupList singleton resource.
Definition: group.c:102
void mutt_hist_free(void)
Free all the history lists.
Definition: history.c:438
void mutt_delete_hooks(HookFlags type)
Delete matching hooks.
Definition: hook.c:361
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1669
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
void mutt_regexlist_free(struct RegexList *rl)
Free a RegexList object.
Definition: regex.c:174
void mutt_replacelist_free(struct ReplaceList *rl)
Free a ReplaceList object.
Definition: regex.c:467
void mutt_commands_free(void)
Free Commands array.
char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
struct ListHead MimeLookupList
List of mime types that that shouldn't use the mailcap entry.
Definition: mutt_globals.h:63
struct ListHead AlternativeOrderList
List of preferred mime types to display.
Definition: mutt_globals.h:60
struct ListHead AutoViewList
List of mime types to auto view.
Definition: mutt_globals.h:61
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
struct ListHead UserHeader
List of custom headers to add to outgoing emails.
Definition: mutt_globals.h:66
struct ListHead HeaderOrderList
List of header fields in the order they should be displayed.
Definition: mutt_globals.h:62
void sb_shutdown(void)
Clean up the Sidebar.
Definition: sidebar.c:208
void driver_tags_cleanup(void)
Deinitialize structures used for tags.
Definition: tags.c:230
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_parse_rc_buffer()

enum CommandResult mutt_parse_rc_buffer ( struct Buffer line,
struct Buffer token,
struct Buffer err 
)

Parse a line of user config.

Parameters
lineconfig line to read
tokenscratch buffer to be used by parser
errwhere to write error messages
Return values
CommandResultResult e.g. MUTT_CMD_SUCCESS

The reason for token is to avoid having to allocate and deallocate a lot of memory if we are parsing many lines. the caller can pass in the memory to use, which avoids having to create new space for every call to this function.

Definition at line 720 of file init.c.

985 {
986  if (mutt_buffer_len(line) == 0)
987  return 0;
988 
990 
991  mutt_buffer_reset(err);
992 
993  /* Read from the beginning of line->data */
994  mutt_buffer_seek(line, 0);
995 
996  SKIPWS(line->dptr);
997  while (*line->dptr)
998  {
999  if (*line->dptr == '#')
1000  break; /* rest of line is a comment */
1001  if (*line->dptr == ';')
1002  {
1003  line->dptr++;
1004  continue;
1005  }
1007 
1008  struct Command *cmd = NULL;
1009  size_t size = mutt_commands_array(&cmd);
1010  size_t i;
1011  for (i = 0; i < size; i++)
1012  {
1013  if (mutt_str_equal(token->data, cmd[i].name))
1014  {
1015  mutt_debug(LL_DEBUG1, "NT_COMMAND: %s\n", cmd[i].name);
1016  rc = cmd[i].parse(token, line, cmd[i].data, err);
1017  if ((rc == MUTT_CMD_ERROR) || (rc == MUTT_CMD_FINISH))
1018  goto finish; /* Propagate return code */
1019 
1020  notify_send(NeoMutt->notify, NT_COMMAND, i, (void *) cmd);
1021  break; /* Continue with next command */
1022  }
1023  }
1024  if (i == size)
1025  {
1026  mutt_buffer_printf(err, _("%s: unknown command"), NONULL(token->data));
1027  rc = MUTT_CMD_ERROR;
1028  break; /* Ignore the rest of the line */
1029  }
1030  }
1031 finish:
1032  return rc;
1033 }
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
CommandResult
Error codes for command_t parse functions.
Definition: command.h:34
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:37
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:35
@ MUTT_CMD_FINISH
Finish: Stop processing this file.
Definition: command.h:38
#define _(a)
Definition: message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:66
@ NT_COMMAND
A Command has been executed, Command.
Definition: notify_type.h:42
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
+ Here is the caller graph for this function:

◆ mutt_parse_rc_line()

enum CommandResult mutt_parse_rc_line ( const char *  line,
struct Buffer err 
)

Parse a line of user config.

Parameters
lineConfig line to read
errWhere to write error messages
Return values
CommandResultResult e.g. MUTT_CMD_SUCCESS

Definition at line 720 of file init.c.

1042 {
1043  if (!line || (*line == '\0'))
1044  return MUTT_CMD_ERROR;
1045 
1046  struct Buffer *line_buffer = mutt_buffer_pool_get();
1047  struct Buffer *token = mutt_buffer_pool_get();
1048 
1049  mutt_buffer_strcpy(line_buffer, line);
1050 
1051  enum CommandResult rc = mutt_parse_rc_buffer(line_buffer, token, err);
1052 
1053  mutt_buffer_pool_release(&line_buffer);
1054  mutt_buffer_pool_release(&token);
1055  return rc;
1056 }
enum CommandResult mutt_parse_rc_buffer(struct Buffer *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:983
+ Here is the caller graph for this function:

◆ mutt_query_variables()

int mutt_query_variables ( struct ListHead *  queries,
bool  show_docs 
)

Implement the -Q command line flag.

Parameters
queriesList of query strings
show_docsIf true, show one-liner docs for the config item
Return values
0Success, all queries exist
1Error

Definition at line 1065 of file init.c.

1066 {
1067  struct Buffer value = mutt_buffer_make(256);
1068  struct Buffer tmp = mutt_buffer_make(256);
1069  int rc = 0;
1070 
1071  struct ListNode *np = NULL;
1072  STAILQ_FOREACH(np, queries, entries)
1073  {
1074  mutt_buffer_reset(&value);
1075 
1076  struct HashElem *he = cs_subset_lookup(NeoMutt->sub, np->data);
1077  if (!he)
1078  {
1079  mutt_warning(_("No such variable: %s"), np->data);
1080  rc = 1;
1081  continue;
1082  }
1083 
1084  if (he->type & DT_DEPRECATED)
1085  {
1086  mutt_warning(_("Config variable '%s' is deprecated"), np->data);
1087  rc = 1;
1088  continue;
1089  }
1090 
1091  int rv = cs_subset_he_string_get(NeoMutt->sub, he, &value);
1092  if (CSR_RESULT(rv) != CSR_SUCCESS)
1093  {
1094  rc = 1;
1095  continue;
1096  }
1097 
1098  int type = DTYPE(he->type);
1099  if (type == DT_PATH)
1100  mutt_pretty_mailbox(value.data, value.dsize);
1101 
1102  if ((type != DT_BOOL) && (type != DT_NUMBER) && (type != DT_LONG) && (type != DT_QUAD))
1103  {
1104  mutt_buffer_reset(&tmp);
1105  pretty_var(value.data, &tmp);
1106  mutt_buffer_strcpy(&value, tmp.data);
1107  }
1108 
1109  dump_config_neo(NeoMutt->sub->cs, he, &value, NULL,
1110  show_docs ? CS_DUMP_SHOW_DOCS : CS_DUMP_NO_FLAGS, stdout);
1111  }
1112 
1113  mutt_buffer_dealloc(&value);
1114  mutt_buffer_dealloc(&tmp);
1115 
1116  return rc; // TEST16: neomutt -Q charset
1117 }
size_t pretty_var(const char *str, struct Buffer *buf)
Escape and stringify a config item value.
Definition: dump.c:83
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
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:521
#define CS_DUMP_NO_FLAGS
No flags are set.
Definition: dump.h:35
#define CS_DUMP_SHOW_DOCS
Show one-liner documentation for the config item.
Definition: dump.h:45
#define mutt_warning(...)
Definition: logging.h:85
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:354
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition: subset.c:179
#define DT_QUAD
quad-option (no/yes/ask-no/ask-yes)
Definition: types.h:37
#define DT_LONG
a number (long)
Definition: types.h:33
#define DT_BOOL
boolean option
Definition: types.h:30
#define DT_PATH
a path to a file/directory
Definition: types.h:36
#define DT_NUMBER
a number
Definition: types.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_var_value_complete()

int mutt_var_value_complete ( char *  buf,
size_t  buflen,
int  pos 
)

Complete a variable/value.

Parameters
bufBuffer for the result
buflenLength of the buffer
posCursor position in the buffer
Return values
1Success
0Failure

Definition at line 1487 of file init.c.

1488 {
1489  char *pt = buf;
1490 
1491  if (buf[0] == '\0')
1492  return 0;
1493 
1494  SKIPWS(buf);
1495  const int spaces = buf - pt;
1496 
1497  pt = buf + pos - spaces;
1498  while ((pt > buf) && !isspace((unsigned char) *pt))
1499  pt--;
1500  pt++; /* move past the space */
1501  if (*pt == '=') /* abort if no var before the '=' */
1502  return 0;
1503 
1504  if (mutt_str_startswith(buf, "set"))
1505  {
1506  const char *myvarval = NULL;
1507  char var[256];
1508  mutt_str_copy(var, pt, sizeof(var));
1509  /* ignore the trailing '=' when comparing */
1510  int vlen = mutt_str_len(var);
1511  if (vlen == 0)
1512  return 0;
1513 
1514  var[vlen - 1] = '\0';
1515 
1516  struct HashElem *he = cs_subset_lookup(NeoMutt->sub, var);
1517  if (!he)
1518  {
1519  myvarval = myvar_get(var);
1520  if (myvarval)
1521  {
1522  struct Buffer pretty = mutt_buffer_make(256);
1523  pretty_var(myvarval, &pretty);
1524  snprintf(pt, buflen - (pt - buf), "%s=%s", var, pretty.data);
1525  mutt_buffer_dealloc(&pretty);
1526  return 1;
1527  }
1528  return 0; /* no such variable. */
1529  }
1530  else
1531  {
1532  struct Buffer value = mutt_buffer_make(256);
1533  struct Buffer pretty = mutt_buffer_make(256);
1534  int rc = cs_subset_he_string_get(NeoMutt->sub, he, &value);
1535  if (CSR_RESULT(rc) == CSR_SUCCESS)
1536  {
1537  pretty_var(value.data, &pretty);
1538  snprintf(pt, buflen - (pt - buf), "%s=%s", var, pretty.data);
1539  mutt_buffer_dealloc(&value);
1540  mutt_buffer_dealloc(&pretty);
1541  return 0;
1542  }
1543  mutt_buffer_dealloc(&value);
1544  mutt_buffer_dealloc(&pretty);
1545  return 1;
1546  }
1547  }
1548  return 0;
1549 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function: