NeoMutt  2021-10-22-8-g9cb437
Teaching an old dog new tricks
DOXYGEN
init.c File Reference

Config/command parsing. More...

#include "config.h"
#include <ctype.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "conn/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "init.h"
#include "color/lib.h"
#include "history/lib.h"
#include "notmuch/lib.h"
#include "command_parse.h"
#include "context.h"
#include "functions.h"
#include "keymap.h"
#include "mutt_commands.h"
#include "mutt_globals.h"
#include "mutt_lua.h"
#include "menu/lib.h"
#include "muttlib.h"
#include "myvar.h"
#include "options.h"
#include "protos.h"
#include "sort.h"
#include "sidebar/lib.h"
#include "compmbox/lib.h"
#include "imap/lib.h"
+ Include dependency graph for init.c:

Go to the source code of this file.

Functions

static void matches_ensure_morespace (int current)
 Allocate more space for auto-completion. More...
 
static void candidate (char *user, const char *src, char *dest, size_t dlen)
 Helper function for completion. More...
 
static int complete_all_nm_tags (const char *pt)
 Pass a list of Notmuch tags to the completion code. More...
 
static int execute_commands (struct ListHead *p)
 Execute a set of NeoMutt commands. More...
 
static char * find_cfg (const char *home, const char *xdg_cfg_home)
 Find a config file. More...
 
static char * getmailname (void)
 Try to retrieve the FQDN from mailname files. More...
 
static bool get_hostname (struct ConfigSet *cs)
 Find the Fully-Qualified Domain Name. More...
 
int mutt_extract_token (struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
 Extract one token from a string. More...
 
void mutt_opts_free (void)
 Clean up before quitting. 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...
 
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_command_complete (char *buf, size_t buflen, int pos, int numtabs)
 Complete a command name. 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...
 
int mutt_var_value_complete (char *buf, size_t buflen, int pos)
 Complete a variable/value. More...
 

Variables

static char UserTyped [1024] = { 0 }
 
static int NumMatched = 0
 
static char Completed [256] = { 0 }
 
static const char ** Matches
 
static int MatchesListsize = 512
 
static char ** nm_tags
 

Detailed Description

Config/command parsing.

Authors
  • Michael R. Elkins
  • Pietro Cerutti

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.c.

Function Documentation

◆ matches_ensure_morespace()

static void matches_ensure_morespace ( int  current)
static

Allocate more space for auto-completion.

Parameters
currentCurrent allocation

Definition at line 97 of file init.c.

98 {
99  if (current <= (MatchesListsize - 2))
100  return;
101 
102  int base_space = 512; // Enough space for all of the config items
103  int extra_space = MatchesListsize - base_space;
104  extra_space *= 2;
105  const int space = base_space + extra_space;
106  mutt_mem_realloc(&Matches, space * sizeof(char *));
107  memset(&Matches[current + 1], 0, space - current);
108  MatchesListsize = space;
109 }
static int MatchesListsize
Definition: init.c:86
static const char ** Matches
Definition: init.c:84
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ candidate()

static void candidate ( char *  user,
const char *  src,
char *  dest,
size_t  dlen 
)
static

Helper function for completion.

Parameters
userUser entered data for completion
srcCandidate for completion
destCompletion result gets here
dlenLength of dest buffer

Changes the dest buffer if necessary/possible to aid completion.

Definition at line 120 of file init.c.

121 {
122  if (!dest || !user || !src)
123  return;
124 
125  if (strstr(src, user) != src)
126  return;
127 
129  Matches[NumMatched++] = src;
130  if (dest[0] == '\0')
131  mutt_str_copy(dest, src, dlen);
132  else
133  {
134  int l;
135  for (l = 0; src[l] && src[l] == dest[l]; l++)
136  ; // do nothing
137 
138  dest[l] = '\0';
139  }
140 }
static void matches_ensure_morespace(int current)
Allocate more space for auto-completion.
Definition: init.c:97
static int NumMatched
Definition: init.c:82
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:749
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ complete_all_nm_tags()

static int complete_all_nm_tags ( const char *  pt)
static

Pass a list of Notmuch tags to the completion code.

Parameters
ptList of all Notmuch tags
Return values
0Success
-1Error

Definition at line 149 of file init.c.

150 {
151  struct Mailbox *m = ctx_mailbox(Context);
152  int tag_count_1 = 0;
153  int tag_count_2 = 0;
154 
155  NumMatched = 0;
156  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
157  memset(Matches, 0, MatchesListsize);
158  memset(Completed, 0, sizeof(Completed));
159 
160  nm_db_longrun_init(m, false);
161 
162  /* Work out how many tags there are. */
163  if (nm_get_all_tags(m, NULL, &tag_count_1) || (tag_count_1 == 0))
164  goto done;
165 
166  /* Free the old list, if any. */
167  if (nm_tags)
168  {
169  for (int i = 0; nm_tags[i]; i++)
170  FREE(&nm_tags[i]);
171  FREE(&nm_tags);
172  }
173  /* Allocate a new list, with sentinel. */
174  nm_tags = mutt_mem_malloc((tag_count_1 + 1) * sizeof(char *));
175  nm_tags[tag_count_1] = NULL;
176 
177  /* Get all the tags. */
178  if (nm_get_all_tags(m, nm_tags, &tag_count_2) || (tag_count_1 != tag_count_2))
179  {
180  FREE(&nm_tags);
181  nm_tags = NULL;
183  return -1;
184  }
185 
186  /* Put them into the completion machinery. */
187  for (int num = 0; num < tag_count_1; num++)
188  {
189  candidate(UserTyped, nm_tags[num], Completed, sizeof(Completed));
190  }
191 
194 
195 done:
197  return 0;
198 }
struct Mailbox * ctx_mailbox(struct Context *ctx)
Wrapper to get the mailbox in a Context, or NULL.
Definition: context.c:444
static void candidate(char *user, const char *src, char *dest, size_t dlen)
Helper function for completion.
Definition: init.c:120
static char Completed[256]
Definition: init.c:83
static char ** nm_tags
Definition: init.c:90
static char UserTyped[1024]
Definition: init.c:80
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:40
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:345
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:330
int nm_get_all_tags(struct Mailbox *m, char **tag_list, int *tag_count)
Fill a list with all notmuch tags.
Definition: notmuch.c:1967
The "current" mailbox.
Definition: context.h:38
A mailbox.
Definition: mailbox.h:82
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ execute_commands()

static int execute_commands ( struct ListHead *  p)
static

Execute a set of NeoMutt commands.

Parameters
pList of command strings
Return values
0Success, all the commands succeeded
-1Error

Definition at line 207 of file init.c.

208 {
209  int rc = 0;
210  struct Buffer *err = mutt_buffer_pool_get();
211 
212  struct ListNode *np = NULL;
213  STAILQ_FOREACH(np, p, entries)
214  {
215  enum CommandResult rc2 = mutt_parse_rc_line(np->data, err);
216  if (rc2 == MUTT_CMD_ERROR)
217  mutt_error(_("Error in command line: %s"), mutt_buffer_string(err));
218  else if (rc2 == MUTT_CMD_WARNING)
219  mutt_warning(_("Warning in command line: %s"), mutt_buffer_string(err));
220 
221  if ((rc2 == MUTT_CMD_ERROR) || (rc2 == MUTT_CMD_WARNING))
222  {
224  return -1;
225  }
226  }
228 
229  return rc;
230 }
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
CommandResult
Error codes for command_t parse functions.
Definition: command.h:34
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:35
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition: command.h:36
#define mutt_warning(...)
Definition: logging.h:85
#define mutt_error(...)
Definition: logging.h:87
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:1043
#define _(a)
Definition: message.h:28
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 STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
String manipulation buffer.
Definition: buffer.h:34
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_cfg()

static char* find_cfg ( const char *  home,
const char *  xdg_cfg_home 
)
static

Find a config file.

Parameters
homeUser's home directory
xdg_cfg_homeXDG home directory
Return values
ptrSuccess, first matching directory
NULLError, no matching directories

Definition at line 239 of file init.c.

240 {
241  const char *names[] = {
242  "neomuttrc",
243  "muttrc",
244  NULL,
245  };
246 
247  const char *locations[][2] = {
248  { xdg_cfg_home, "neomutt/" },
249  { xdg_cfg_home, "mutt/" },
250  { home, ".neomutt/" },
251  { home, ".mutt/" },
252  { home, "." },
253  { NULL, NULL },
254  };
255 
256  for (int i = 0; locations[i][0] || locations[i][1]; i++)
257  {
258  if (!locations[i][0])
259  continue;
260 
261  for (int j = 0; names[j]; j++)
262  {
263  char buf[256];
264 
265  snprintf(buf, sizeof(buf), "%s/%s%s", locations[i][0], locations[i][1], names[j]);
266  if (access(buf, F_OK) == 0)
267  return mutt_str_dup(buf);
268  }
269  }
270 
271  return NULL;
272 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getmailname()

static char* getmailname ( void  )
static

Try to retrieve the FQDN from mailname files.

Return values
ptrHeap allocated string with the FQDN
NULLNo valid mailname file could be read

Definition at line 280 of file init.c.

281 {
282  char *mailname = NULL;
283  static const char *mn_files[] = { "/etc/mailname", "/etc/mail/mailname" };
284 
285  for (size_t i = 0; i < mutt_array_size(mn_files); i++)
286  {
287  FILE *fp = mutt_file_fopen(mn_files[i], "r");
288  if (!fp)
289  continue;
290 
291  size_t len = 0;
292  mailname = mutt_file_read_line(NULL, &len, fp, NULL, MUTT_RL_NO_FLAGS);
293  mutt_file_fclose(&fp);
294  if (mailname && *mailname)
295  break;
296 
297  FREE(&mailname);
298  }
299 
300  return mailname;
301 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
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:671
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:593
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
#define mutt_array_size(x)
Definition: memory.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_hostname()

static bool get_hostname ( struct ConfigSet cs)
static

Find the Fully-Qualified Domain Name.

Return values
trueSuccess
falseError, failed to find any name

Use several methods to try to find the Fully-Qualified domain name of this host. If the user has already configured a hostname, this function will use it.

Definition at line 312 of file init.c.

313 {
314  const char *short_host = NULL;
315  struct utsname utsname;
316 
317  const char *const c_hostname = cs_subset_string(NeoMutt->sub, "hostname");
318  if (c_hostname)
319  {
320  short_host = c_hostname;
321  }
322  else
323  {
324  /* The call to uname() shouldn't fail, but if it does, the system is horribly
325  * broken, and the system's networking configuration is in an unreliable
326  * state. We should bail. */
327  if ((uname(&utsname)) == -1)
328  {
329  mutt_perror(_("unable to determine nodename via uname()"));
330  return false; // TEST09: can't test
331  }
332 
333  short_host = utsname.nodename;
334  }
335 
336  /* some systems report the FQDN instead of just the hostname */
337  char *dot = strchr(short_host, '.');
338  if (dot)
339  ShortHostname = mutt_strn_dup(short_host, dot - short_host);
340  else
341  ShortHostname = mutt_str_dup(short_host);
342 
343  // All the code paths from here alloc memory for the fqdn
344  char *fqdn = mutt_str_dup(c_hostname);
345  if (!fqdn)
346  {
347  mutt_debug(LL_DEBUG1, "Setting $hostname\n");
348  /* now get FQDN. Use configured domain first, DNS next, then uname */
349 #ifdef DOMAIN
350  /* we have a compile-time domain name, use that for `$hostname` */
352  sprintf((char *) fqdn, "%s.%s", NONULL(ShortHostname), DOMAIN);
353 #else
354  fqdn = getmailname();
355  if (!fqdn)
356  {
357  struct Buffer *domain = mutt_buffer_pool_get();
358  if (getdnsdomainname(domain) == 0)
359  {
361  sprintf((char *) fqdn, "%s.%s", NONULL(ShortHostname), mutt_buffer_string(domain));
362  }
363  else
364  {
365  /* DNS failed, use the nodename. Whether or not the nodename had a '.'
366  * in it, we can use the nodename as the FQDN. On hosts where DNS is
367  * not being used, e.g. small network that relies on hosts files, a
368  * short host name is all that is required for SMTP to work correctly.
369  * It could be wrong, but we've done the best we can, at this point the
370  * onus is on the user to provide the correct hostname if the nodename
371  * won't work in their network. */
372  fqdn = mutt_str_dup(utsname.nodename);
373  }
374  mutt_buffer_pool_release(&domain);
375  mutt_debug(LL_DEBUG1, "Hostname: %s\n", NONULL(fqdn));
376  }
377 #endif
378  }
379 
380  if (fqdn)
381  {
382  cs_str_initial_set(cs, "hostname", fqdn, NULL);
383  cs_str_reset(cs, "hostname", NULL);
384  FREE(&fqdn);
385  }
386 
387  return true;
388 }
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
int getdnsdomainname(struct Buffer *result)
Lookup the host's name using DNS.
Definition: getdomain.c:118
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#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
static char * getmailname(void)
Try to retrieve the FQDN from mailname files.
Definition: init.c:280
@ 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:548
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:52
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
#define NONULL(x)
Definition: string2.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ 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, cmd);
548  FREE(&cmd.data);
549 
550  /* if we got output, make a new string consisting of the shell output
551  * plus whatever else was left on the original line */
552  /* BUT: If this is inside a quoted string, directly add output to
553  * the token */
554  if (expn.data)
555  {
556  if (qc)
557  {
558  mutt_buffer_addstr(dest, expn.data);
559  }
560  else
561  {
562  struct Buffer *copy = mutt_buffer_pool_get();
563  mutt_buffer_fix_dptr(&expn);
564  mutt_buffer_copy(copy, &expn);
565  mutt_buffer_addstr(copy, tok->dptr);
566  mutt_buffer_copy(tok, copy);
567  mutt_buffer_seek(tok, 0);
569  }
570  FREE(&expn.data);
571  }
572  }
573  else if ((ch == '$') && (!qc || (qc == '"')) &&
574  ((tok->dptr[0] == '{') || isalpha((unsigned char) tok->dptr[0])))
575  {
576  const char *env = NULL;
577  char *var = NULL;
578 
579  if (tok->dptr[0] == '{')
580  {
581  pc = strchr(tok->dptr, '}');
582  if (pc)
583  {
584  var = mutt_strn_dup(tok->dptr + 1, pc - (tok->dptr + 1));
585  tok->dptr = pc + 1;
586 
587  if ((flags & MUTT_TOKEN_NOSHELL))
588  {
589  mutt_buffer_addch(dest, ch);
590  mutt_buffer_addch(dest, '{');
591  mutt_buffer_addstr(dest, var);
592  mutt_buffer_addch(dest, '}');
593  FREE(&var);
594  }
595  }
596  }
597  else
598  {
599  for (pc = tok->dptr; isalnum((unsigned char) *pc) || (pc[0] == '_'); pc++)
600  ; // do nothing
601 
602  var = mutt_strn_dup(tok->dptr, pc - tok->dptr);
603  tok->dptr = pc;
604  }
605  if (var)
606  {
607  struct Buffer result;
608  mutt_buffer_init(&result);
609  int rc = cs_subset_str_string_get(NeoMutt->sub, var, &result);
610 
611  if (CSR_RESULT(rc) == CSR_SUCCESS)
612  {
613  mutt_buffer_addstr(dest, result.data);
614  FREE(&result.data);
615  }
616  else if ((env = myvar_get(var)))
617  {
618  mutt_buffer_addstr(dest, env);
619  }
620  else if (!(flags & MUTT_TOKEN_NOSHELL) && (env = mutt_str_getenv(var)))
621  {
622  mutt_buffer_addstr(dest, env);
623  }
624  else
625  {
626  mutt_buffer_addch(dest, ch);
627  mutt_buffer_addstr(dest, var);
628  }
629  FREE(&var);
630  }
631  }
632  else
633  mutt_buffer_addch(dest, ch);
634  }
635  mutt_buffer_addch(dest, 0); /* terminate the string */
636  SKIPWS(tok->dptr);
637  return 0;
638 }
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:466
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:445
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
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
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:398
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:1024
#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
#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
#define SKIPWS(ch)
Definition: string2.h:46
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_opts_free()

void mutt_opts_free ( void  )

Clean up before quitting.

Definition at line 643 of file init.c.

644 {
646 
647  alias_shutdown();
648 #ifdef USE_SIDEBAR
649  sb_shutdown();
650 #endif
651 
657 
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:672
void mutt_colors_cleanup(void)
Cleanup all the colours.
Definition: color.c:163
void clear_source_stack(void)
Free memory from the stack used for the source command.
char * HomeDir
User's home directory.
Definition: mutt_globals.h:51
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 MailToAllow
List of permitted fields in a mailto: url.
Definition: globals.c:37
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_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:449
void mutt_hist_free(void)
Free all the history lists.
Definition: history.c:441
void mutt_delete_hooks(HookFlags type)
Delete matching hooks.
Definition: hook.c:327
#define MUTT_HOOK_NO_FLAGS
No flags are set.
Definition: hook.h:37
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1731
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:171
void mutt_replacelist_free(struct ReplaceList *rl)
Free a ReplaceList object.
Definition: regex.c:448
void mutt_commands_free(void)
Free Commands array.
char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:57
struct ListHead MimeLookupList
List of mime types that that shouldn't use the mailcap entry.
Definition: mutt_globals.h:67
struct ListHead AlternativeOrderList
List of preferred mime types to display.
Definition: mutt_globals.h:64
struct ListHead AutoViewList
List of mime types to auto view.
Definition: mutt_globals.h:65
struct HashTable * TagFormats
Hash Table of tag-formats (tag -> format string)
Definition: mutt_globals.h:61
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:56
struct ListHead UserHeader
List of custom headers to add to outgoing emails.
Definition: mutt_globals.h:70
struct ListHead Muttrc
List of config files to read.
Definition: mutt_globals.h:68
char * Username
User's login name.
Definition: mutt_globals.h:54
struct ListHead HeaderOrderList
List of header fields in the order they should be displayed.
Definition: mutt_globals.h:66
void sb_shutdown(void)
Clean up the Sidebar.
Definition: sidebar.c:210
struct HashTable * TagTransforms
Lookup table of alternative tag names.
Definition: tags.c:37
+ 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:371
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:81
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
size_t mutt_commands_array(struct Command **first)
Get Commands array.
enum CommandResult(* parse)(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Definition: command.h:61
intptr_t data
Data or flags to pass to the command.
Definition: command.h:63
const char * name
Name of the command.
Definition: command.h:48
+ 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
741 
742  menu_init();
743 #ifdef USE_SIDEBAR
744  sb_init();
745 #endif
746 #ifdef USE_NOTMUCH
747  nm_init();
748 #endif
749 
750  /* "$spool_file" precedence: config file, environment */
751  const char *p = mutt_str_getenv("MAIL");
752  if (!p)
753  p = mutt_str_getenv("MAILDIR");
754  if (!p)
755  {
756 #ifdef HOMESPOOL
757  mutt_buffer_concat_path(&buf, NONULL(HomeDir), MAILPATH);
758 #else
759  mutt_buffer_concat_path(&buf, MAILPATH, NONULL(Username));
760 #endif
761  p = mutt_buffer_string(&buf);
762  }
763  cs_str_initial_set(cs, "spool_file", p, NULL);
764  cs_str_reset(cs, "spool_file", NULL);
765 
766  p = mutt_str_getenv("REPLYTO");
767  if (p)
768  {
769  struct Buffer token;
770 
771  mutt_buffer_printf(&buf, "Reply-To: %s", p);
772  mutt_buffer_init(&token);
773  parse_my_hdr(&token, &buf, 0, &err); /* adds to UserHeader */
774  FREE(&token.data);
775  }
776 
777  p = mutt_str_getenv("EMAIL");
778  if (p)
779  {
780  cs_str_initial_set(cs, "from", p, NULL);
781  cs_str_reset(cs, "from", NULL);
782  }
783 
784  /* "$mailcap_path" precedence: config file, environment, code */
785  const char *env_mc = mutt_str_getenv("MAILCAPS");
786  if (env_mc)
787  cs_str_string_set(cs, "mailcap_path", env_mc, NULL);
788 
789  /* "$tmpdir" precedence: config file, environment, code */
790  const char *env_tmp = mutt_str_getenv("TMPDIR");
791  if (env_tmp)
792  cs_str_string_set(cs, "tmpdir", env_tmp, NULL);
793 
794  /* "$visual", "$editor" precedence: config file, environment, code */
795  const char *env_ed = mutt_str_getenv("VISUAL");
796  if (!env_ed)
797  env_ed = mutt_str_getenv("EDITOR");
798  if (!env_ed)
799  env_ed = "vi";
800  cs_str_initial_set(cs, "editor", env_ed, NULL);
801 
802  const char *const c_editor = cs_subset_string(NeoMutt->sub, "editor");
803  if (!c_editor)
804  cs_str_reset(cs, "editor", NULL);
805 
806  const char *charset = mutt_ch_get_langinfo_charset();
807  cs_str_initial_set(cs, "charset", charset, NULL);
808  cs_str_reset(cs, "charset", NULL);
809  mutt_ch_set_charset(charset);
810  FREE(&charset);
811 
812  Matches = mutt_mem_calloc(MatchesListsize, sizeof(char *));
813 
814 #ifdef HAVE_GETSID
815  /* Unset suspend by default if we're the session leader */
816  if (getsid(0) == getpid())
817  cs_subset_str_native_set(NeoMutt->sub, "suspend", false, NULL);
818 #endif
819 
820  /* RFC2368, "4. Unsafe headers"
821  * The creator of a mailto URL can't expect the resolver of a URL to
822  * understand more than the "subject" and "body" headers. Clients that
823  * resolve mailto URLs into mail messages should be able to correctly
824  * create RFC822-compliant mail messages using the "subject" and "body"
825  * headers. */
826  add_to_stailq(&MailToAllow, "body");
827  add_to_stailq(&MailToAllow, "subject");
828  /* Cc, In-Reply-To, and References help with not breaking threading on
829  * mailing lists, see https://github.com/neomutt/neomutt/issues/115 */
830  add_to_stailq(&MailToAllow, "cc");
831  add_to_stailq(&MailToAllow, "in-reply-to");
832  add_to_stailq(&MailToAllow, "references");
833 
834  if (STAILQ_EMPTY(&Muttrc))
835  {
836  const char *xdg_cfg_home = mutt_str_getenv("XDG_CONFIG_HOME");
837 
838  if (!xdg_cfg_home && HomeDir)
839  {
840  mutt_buffer_printf(&buf, "%s/.config", HomeDir);
841  xdg_cfg_home = mutt_buffer_string(&buf);
842  }
843 
844  char *config = find_cfg(HomeDir, xdg_cfg_home);
845  if (config)
846  {
847  mutt_list_insert_tail(&Muttrc, config);
848  }
849  }
850  else
851  {
852  struct ListNode *np = NULL;
853  STAILQ_FOREACH(np, &Muttrc, entries)
854  {
855  mutt_buffer_strcpy(&buf, np->data);
856  FREE(&np->data);
858  np->data = mutt_buffer_strdup(&buf);
859  if (access(np->data, F_OK))
860  {
861  mutt_perror(np->data);
862  goto done; // TEST10: neomutt -F missing
863  }
864  }
865  }
866 
867  if (!STAILQ_EMPTY(&Muttrc))
868  {
869  cs_str_string_set(cs, "alias_file", STAILQ_FIRST(&Muttrc)->data, NULL);
870  }
871 
872  /* Process the global rc file if it exists and the user hasn't explicitly
873  * requested not to via "-n". */
874  if (!skip_sys_rc)
875  {
876  do
877  {
879  break;
880 
881  mutt_buffer_printf(&buf, "%s/neomuttrc", SYSCONFDIR);
882  if (access(mutt_buffer_string(&buf), F_OK) == 0)
883  break;
884 
885  mutt_buffer_printf(&buf, "%s/Muttrc", SYSCONFDIR);
886  if (access(mutt_buffer_string(&buf), F_OK) == 0)
887  break;
888 
889  mutt_buffer_printf(&buf, "%s/neomuttrc", PKGDATADIR);
890  if (access(mutt_buffer_string(&buf), F_OK) == 0)
891  break;
892 
893  mutt_buffer_printf(&buf, "%s/Muttrc", PKGDATADIR);
894  } while (false);
895 
896  if (access(mutt_buffer_string(&buf), F_OK) == 0)
897  {
898  if (source_rc(mutt_buffer_string(&buf), &err) != 0)
899  {
900  mutt_error("%s", err.data);
901  need_pause = 1; // TEST11: neomutt (error in /etc/neomuttrc)
902  }
903  }
904  }
905 
906  /* Read the user's initialization file. */
907  struct ListNode *np = NULL;
908  STAILQ_FOREACH(np, &Muttrc, entries)
909  {
910  if (np->data)
911  {
912  if (source_rc(np->data, &err) != 0)
913  {
914  mutt_error("%s", err.data);
915  need_pause = 1; // TEST12: neomutt (error in ~/.neomuttrc)
916  }
917  }
918  }
919 
920  if (execute_commands(commands) != 0)
921  need_pause = 1; // TEST13: neomutt -e broken
922 
923  if (!get_hostname(cs))
924  goto done;
925 
926  {
927  char name[256] = { 0 };
928  const char *c_real_name = cs_subset_string(NeoMutt->sub, "real_name");
929  if (!c_real_name)
930  {
931  struct passwd *pw = getpwuid(getuid());
932  if (pw)
933  c_real_name = mutt_gecos_name(name, sizeof(name), pw);
934  }
935  cs_str_initial_set(cs, "real_name", c_real_name, NULL);
936  cs_str_reset(cs, "real_name", NULL);
937  }
938 
939  if (need_pause && !OptNoCurses)
940  {
942  if (mutt_any_key_to_continue(NULL) == 'q')
943  goto done; // TEST14: neomutt -e broken (press 'q')
944  }
945 
946  const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
947  mutt_file_mkdir(c_tmpdir, S_IRWXU);
948 
949  mutt_hist_init();
951 
952 #ifdef USE_NOTMUCH
953  const bool c_virtual_spool_file =
954  cs_subset_bool(NeoMutt->sub, "virtual_spool_file");
955  if (c_virtual_spool_file)
956  {
957  /* Find the first virtual folder and open it */
958  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
960  struct MailboxNode *mp = STAILQ_FIRST(&ml);
961  if (mp)
962  cs_str_string_set(cs, "spool_file", mailbox_path(mp->mailbox), NULL);
964  }
965 #endif
966  rc = 0;
967 
968 done:
969  mutt_buffer_dealloc(&err);
970  mutt_buffer_dealloc(&buf);
971  return rc;
972 }
void alias_init(void)
Set up the Alias globals.
Definition: alias.c:664
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:69
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:455
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:881
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:441
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:251
#define MUTT_HASH_NO_FLAGS
No flags are set.
Definition: hash.h:109
#define MUTT_HASH_STRCASECMP
use strcasecmp() to compare keys
Definition: hash.h:110
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:599
void mutt_hist_init(void)
Create a set of empty History ring buffers.
Definition: history.c:468
void imap_init(void)
Setup feature commands.
Definition: imap.c:83
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:348
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:215
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:54
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:118
char * mutt_ch_get_langinfo_charset(void)
Get the user's choice of character set.
Definition: charset.c:473
void mutt_ch_set_charset(const char *charset)
Update the records for a new character set.
Definition: charset.c:1014
void mutt_commands_init(void)
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:322
void add_to_stailq(struct ListHead *head, const char *str)
Add a string to a list.
Definition: muttlib.c:1728
int mutt_set_xdg_path(enum XdgType type, struct Buffer *buf)
Find an XDG path or its fallback.
Definition: muttlib.c:1516
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user's real name in /etc/passwd.
Definition: muttlib.c:361
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:47
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_EMPTY(head)
Definition: queue.h:348
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:198
List of Mailboxes.
Definition: mailbox.h:157
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:158
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
+ 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.

987 {
988  if (mutt_buffer_len(line) == 0)
989  return 0;
990 
992 
993  mutt_buffer_reset(err);
994 
995  /* Read from the beginning of line->data */
996  mutt_buffer_seek(line, 0);
997 
998  SKIPWS(line->dptr);
999  while (*line->dptr)
1000  {
1001  if (*line->dptr == '#')
1002  break; /* rest of line is a comment */
1003  if (*line->dptr == ';')
1004  {
1005  line->dptr++;
1006  continue;
1007  }
1009 
1010  struct Command *cmd = NULL;
1011  size_t size = mutt_commands_array(&cmd);
1012  size_t i;
1013  for (i = 0; i < size; i++)
1014  {
1015  if (mutt_str_equal(token->data, cmd[i].name))
1016  {
1017  mutt_debug(LL_NOTIFY, "NT_COMMAND: %s\n", cmd[i].name);
1018  rc = cmd[i].parse(token, line, cmd[i].data, err);
1019  if ((rc == MUTT_CMD_ERROR) || (rc == MUTT_CMD_FINISH))
1020  goto finish; /* Propagate return code */
1021 
1022  notify_send(NeoMutt->notify, NT_COMMAND, i, (void *) cmd);
1023  break; /* Continue with next command */
1024  }
1025  }
1026  if (i == size)
1027  {
1028  mutt_buffer_printf(err, _("%s: unknown command"), NONULL(token->data));
1029  rc = MUTT_CMD_ERROR;
1030  break; /* Ignore the rest of the line */
1031  }
1032  }
1033 finish:
1034  return rc;
1035 }
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:37
@ MUTT_CMD_FINISH
Finish: Stop processing this file.
Definition: command.h:38
@ LL_NOTIFY
Log of notifications.
Definition: logging.h:45
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:904
#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:40
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.

1044 {
1045  if (!line || (*line == '\0'))
1046  return MUTT_CMD_ERROR;
1047 
1048  struct Buffer *line_buffer = mutt_buffer_pool_get();
1049  struct Buffer *token = mutt_buffer_pool_get();
1050 
1051  mutt_buffer_strcpy(line_buffer, line);
1052 
1053  enum CommandResult rc = mutt_parse_rc_buffer(line_buffer, token, err);
1054 
1055  mutt_buffer_pool_release(&line_buffer);
1056  mutt_buffer_pool_release(&token);
1057  return rc;
1058 }
enum CommandResult mutt_parse_rc_buffer(struct Buffer *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:985
+ 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 1067 of file init.c.

1068 {
1069  struct Buffer value = mutt_buffer_make(256);
1070  struct Buffer tmp = mutt_buffer_make(256);
1071  int rc = 0;
1072 
1073  struct ListNode *np = NULL;
1074  STAILQ_FOREACH(np, queries, entries)
1075  {
1076  mutt_buffer_reset(&value);
1077 
1078  struct HashElem *he = cs_subset_lookup(NeoMutt->sub, np->data);
1079  if (!he)
1080  {
1081  mutt_warning(_("No such variable: %s"), np->data);
1082  rc = 1;
1083  continue;
1084  }
1085 
1086  if (he->type & DT_DEPRECATED)
1087  {
1088  mutt_warning(_("Config variable '%s' is deprecated"), np->data);
1089  rc = 1;
1090  continue;
1091  }
1092 
1093  int rv = cs_subset_he_string_get(NeoMutt->sub, he, &value);
1094  if (CSR_RESULT(rv) != CSR_SUCCESS)
1095  {
1096  rc = 1;
1097  continue;
1098  }
1099 
1100  int type = DTYPE(he->type);
1101  if (type == DT_PATH)
1102  mutt_pretty_mailbox(value.data, value.dsize);
1103 
1104  if ((type != DT_BOOL) && (type != DT_NUMBER) && (type != DT_LONG) && (type != DT_QUAD))
1105  {
1106  mutt_buffer_reset(&tmp);
1107  pretty_var(value.data, &tmp);
1108  mutt_buffer_strcpy(&value, tmp.data);
1109  }
1110 
1111  dump_config_neo(NeoMutt->sub->cs, he, &value, NULL,
1112  show_docs ? CS_DUMP_SHOW_DOCS : CS_DUMP_NO_FLAGS, stdout);
1113  }
1114 
1115  mutt_buffer_dealloc(&value);
1116  mutt_buffer_dealloc(&tmp);
1117 
1118  return rc; // TEST16: neomutt -Q charset
1119 }
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:526
#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
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
The item stored in a Hash Table.
Definition: hash.h:44
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition: hash.h:45
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 DTYPE(x)
Mask for the Data Type.
Definition: types.h:44
#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_DEPRECATED
Config item shouldn't be used any more.
Definition: types.h:77
#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_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 1130 of file init.c.

1131 {
1132  char *pt = buf;
1133  int spaces; /* keep track of the number of leading spaces on the line */
1134  struct MyVar *myv = NULL;
1135 
1136  SKIPWS(buf);
1137  spaces = buf - pt;
1138 
1139  pt = buf + pos - spaces;
1140  while ((pt > buf) && !isspace((unsigned char) *pt))
1141  pt--;
1142 
1143  if (pt == buf) /* complete cmd */
1144  {
1145  /* first TAB. Collect all the matches */
1146  if (numtabs == 1)
1147  {
1148  NumMatched = 0;
1149  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
1150  memset(Matches, 0, MatchesListsize);
1151  memset(Completed, 0, sizeof(Completed));
1152 
1153  struct Command *c = NULL;
1154  for (size_t num = 0, size = mutt_commands_array(&c); num < size; num++)
1155  candidate(UserTyped, c[num].name, Completed, sizeof(Completed));
1158 
1159  /* All matches are stored. Longest non-ambiguous string is ""
1160  * i.e. don't change 'buf'. Fake successful return this time */
1161  if (UserTyped[0] == '\0')
1162  return 1;
1163  }
1164 
1165  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1166  return 0;
1167 
1168  /* NumMatched will _always_ be at least 1 since the initial
1169  * user-typed string is always stored */
1170  if ((numtabs == 1) && (NumMatched == 2))
1171  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1172  else if ((numtabs > 1) && (NumMatched > 2))
1173  {
1174  /* cycle through all the matches */
1175  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1176  }
1177 
1178  /* return the completed command */
1179  strncpy(buf, Completed, buflen - spaces);
1180  }
1181  else if (mutt_str_startswith(buf, "set") || mutt_str_startswith(buf, "unset") ||
1182  mutt_str_startswith(buf, "reset") || mutt_str_startswith(buf, "toggle"))
1183  { /* complete variables */
1184  static const char *const prefixes[] = { "no", "inv", "?", "&", 0 };
1185 
1186  pt++;
1187  /* loop through all the possible prefixes (no, inv, ...) */
1188  if (mutt_str_startswith(buf, "set"))
1189  {
1190  for (int num = 0; prefixes[num]; num++)
1191  {
1192  if (mutt_str_startswith(pt, prefixes[num]))
1193  {
1194  pt += mutt_str_len(prefixes[num]);
1195  break;
1196  }
1197  }
1198  }
1199 
1200  /* first TAB. Collect all the matches */
1201  if (numtabs == 1)
1202  {
1203  NumMatched = 0;
1204  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
1205  memset(Matches, 0, MatchesListsize);
1206  memset(Completed, 0, sizeof(Completed));
1207 
1208  struct HashElem *he = NULL;
1209  struct HashElem **list = get_elem_list(NeoMutt->sub->cs);
1210  for (size_t i = 0; list[i]; i++)
1211  {
1212  he = list[i];
1213  const int type = DTYPE(he->type);
1214 
1215  if ((type == DT_SYNONYM) || (type & DT_DEPRECATED))
1216  continue;
1217 
1218  candidate(UserTyped, he->key.strkey, Completed, sizeof(Completed));
1219  }
1220  FREE(&list);
1221 
1222  TAILQ_FOREACH(myv, &MyVars, entries)
1223  {
1224  candidate(UserTyped, myv->name, Completed, sizeof(Completed));
1225  }
1228 
1229  /* All matches are stored. Longest non-ambiguous string is ""
1230  * i.e. don't change 'buf'. Fake successful return this time */
1231  if (UserTyped[0] == '\0')
1232  return 1;
1233  }
1234 
1235  if ((Completed[0] == 0) && UserTyped[0])
1236  return 0;
1237 
1238  /* NumMatched will _always_ be at least 1 since the initial
1239  * user-typed string is always stored */
1240  if ((numtabs == 1) && (NumMatched == 2))
1241  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1242  else if ((numtabs > 1) && (NumMatched > 2))
1243  {
1244  /* cycle through all the matches */
1245  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1246  }
1247 
1248  strncpy(pt, Completed, buf + buflen - pt - spaces);
1249  }
1250  else if (mutt_str_startswith(buf, "exec"))
1251  {
1252  const enum MenuType mtype = menu_get_current_type();
1253  const struct Binding *menu = km_get_table(mtype);
1254  if (!menu && (mtype != MENU_PAGER))
1255  menu = OpGeneric;
1256 
1257  pt++;
1258  /* first TAB. Collect all the matches */
1259  if (numtabs == 1)
1260  {
1261  NumMatched = 0;
1262  mutt_str_copy(UserTyped, pt, sizeof(UserTyped));
1263  memset(Matches, 0, MatchesListsize);
1264  memset(Completed, 0, sizeof(Completed));
1265  for (int num = 0; menu[num].name; num++)
1266  candidate(UserTyped, menu[num].name, Completed, sizeof(Completed));
1267  /* try the generic menu */
1268  if ((Completed[0] == '\0') && (mtype != MENU_PAGER))
1269  {
1270  menu = OpGeneric;
1271  for (int num = 0; menu[num].name; num++)
1272  candidate(UserTyped, menu[num].name, Completed, sizeof(Completed));
1273  }
1276 
1277  /* All matches are stored. Longest non-ambiguous string is ""
1278  * i.e. don't change 'buf'. Fake successful return this time */
1279  if (UserTyped[0] == '\0')
1280  return 1;
1281  }
1282 
1283  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1284  return 0;
1285 
1286  /* NumMatched will _always_ be at least 1 since the initial
1287  * user-typed string is always stored */
1288  if ((numtabs == 1) && (NumMatched == 2))
1289  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1290  else if ((numtabs > 1) && (NumMatched > 2))
1291  {
1292  /* cycle through all the matches */
1293  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1294  }
1295 
1296  strncpy(pt, Completed, buf + buflen - pt - spaces);
1297  }
1298  else
1299  return 0;
1300 
1301  return 1;
1302 }
const struct Binding OpGeneric[]
Key bindings for the generic menu.
Definition: functions.c:53
const struct Binding * km_get_table(enum MenuType mtype)
Lookup a menu's keybindings.
Definition: keymap.c:1301
enum MenuType menu_get_current_type(void)
Get the type of the current Window.
Definition: menu.c:531
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
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
Mapping between a user key and a function.
Definition: keymap.h:92
const char * name
name of the function
Definition: keymap.h:93
union HashKey key
Key representing the data.
Definition: hash.h:46
A user-set variable.
Definition: myvar.h:32
char * name
Name of user variable.
Definition: myvar.h:33
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_PAGER
Pager pager (email viewer)
Definition: type.h:54
#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_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 1312 of file init.c.

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

1377 {
1378  char *pt = buf;
1379  int spaces;
1380 
1381  SKIPWS(buf);
1382  spaces = buf - pt;
1383 
1384  pt = (char *) mutt_strn_rfind((char *) buf, pos, "tag:");
1385  if (pt)
1386  {
1387  pt += 4;
1388  if (numtabs == 1)
1389  {
1390  /* First TAB. Collect all the matches */
1392 
1393  /* All matches are stored. Longest non-ambiguous string is ""
1394  * i.e. don't change 'buf'. Fake successful return this time. */
1395  if (UserTyped[0] == '\0')
1396  return true;
1397  }
1398 
1399  if ((Completed[0] == '\0') && (UserTyped[0] != '\0'))
1400  return false;
1401 
1402  /* NumMatched will _always_ be at least 1 since the initial
1403  * user-typed string is always stored */
1404  if ((numtabs == 1) && (NumMatched == 2))
1405  snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
1406  else if ((numtabs > 1) && (NumMatched > 2))
1407  {
1408  /* cycle through all the matches */
1409  snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % NumMatched]);
1410  }
1411 
1412  /* return the completed query */
1413  strncpy(pt, Completed, buf + buflen - pt - spaces);
1414  }
1415  else
1416  return false;
1417 
1418  return true;
1419 }
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:953
+ 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 1433 of file init.c.

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

Definition at line 1486 of file init.c.

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

Variable Documentation

◆ UserTyped

char UserTyped[1024] = { 0 }
static

Definition at line 80 of file init.c.

◆ NumMatched

int NumMatched = 0
static

Definition at line 82 of file init.c.

◆ Completed

char Completed[256] = { 0 }
static

Definition at line 83 of file init.c.

◆ Matches

const char** Matches
static

Definition at line 84 of file init.c.

◆ MatchesListsize

int MatchesListsize = 512
static

Definition at line 86 of file init.c.

◆ nm_tags

char** nm_tags
static

Definition at line 90 of file init.c.