NeoMutt  2022-04-29-323-g5fcc6c
Teaching an old dog new tricks
DOXYGEN
init.c
Go to the documentation of this file.
1
30#include "config.h"
31#include <ctype.h>
32#include <pwd.h>
33#include <stdbool.h>
34#include <stdio.h>
35#include <string.h>
36#include <sys/stat.h>
37#include <sys/utsname.h>
38#include <unistd.h>
39#include "mutt/lib.h"
40#include "address/lib.h"
41#include "config/lib.h"
42#include "email/lib.h"
43#include "core/lib.h"
44#include "alias/lib.h"
45#include "conn/lib.h" // IWYU pragma: keep
46#include "gui/lib.h"
47#include "mutt.h"
48#include "init.h"
49#include "color/lib.h"
50#include "history/lib.h"
51#include "notmuch/lib.h"
52#include "command_parse.h"
53#include "hook.h"
54#include "keymap.h"
55#include "mutt_commands.h"
56#include "mutt_globals.h"
57#ifdef USE_LUA
58#include "mutt_lua.h"
59#endif
60#include "menu/lib.h"
61#include "muttlib.h"
62#include "myvar.h"
63#include "options.h"
64#include "protos.h"
65#ifdef USE_SIDEBAR
66#include "sidebar/lib.h"
67#endif
68#ifdef USE_COMP_MBOX
69#include "compmbox/lib.h"
70#endif
71#ifdef USE_IMAP
72#include "imap/lib.h"
73#endif
74
81static int execute_commands(struct ListHead *p)
82{
83 int rc = 0;
84 struct Buffer *err = mutt_buffer_pool_get();
85
86 struct ListNode *np = NULL;
87 STAILQ_FOREACH(np, p, entries)
88 {
89 enum CommandResult rc2 = mutt_parse_rc_line(np->data, err);
90 if (rc2 == MUTT_CMD_ERROR)
91 mutt_error(_("Error in command line: %s"), mutt_buffer_string(err));
92 else if (rc2 == MUTT_CMD_WARNING)
93 mutt_warning(_("Warning in command line: %s"), mutt_buffer_string(err));
94
95 if ((rc2 == MUTT_CMD_ERROR) || (rc2 == MUTT_CMD_WARNING))
96 {
98 return -1;
99 }
100 }
102
103 return rc;
104}
105
113static char *find_cfg(const char *home, const char *xdg_cfg_home)
114{
115 const char *names[] = {
116 "neomuttrc",
117 "muttrc",
118 NULL,
119 };
120
121 const char *locations[][2] = {
122 { xdg_cfg_home, "neomutt/" },
123 { xdg_cfg_home, "mutt/" },
124 { home, ".neomutt/" },
125 { home, ".mutt/" },
126 { home, "." },
127 { NULL, NULL },
128 };
129
130 for (int i = 0; locations[i][0] || locations[i][1]; i++)
131 {
132 if (!locations[i][0])
133 continue;
134
135 for (int j = 0; names[j]; j++)
136 {
137 char buf[256] = { 0 };
138
139 snprintf(buf, sizeof(buf), "%s/%s%s", locations[i][0], locations[i][1], names[j]);
140 if (access(buf, F_OK) == 0)
141 return mutt_str_dup(buf);
142 }
143 }
144
145 return NULL;
146}
147
148#ifndef DOMAIN
154static char *getmailname(void)
155{
156 char *mailname = NULL;
157 static const char *mn_files[] = { "/etc/mailname", "/etc/mail/mailname" };
158
159 for (size_t i = 0; i < mutt_array_size(mn_files); i++)
160 {
161 FILE *fp = mutt_file_fopen(mn_files[i], "r");
162 if (!fp)
163 continue;
164
165 size_t len = 0;
166 mailname = mutt_file_read_line(NULL, &len, fp, NULL, MUTT_RL_NO_FLAGS);
167 mutt_file_fclose(&fp);
168 if (mailname && *mailname)
169 break;
170
171 FREE(&mailname);
172 }
173
174 return mailname;
175}
176#endif
177
186static bool get_hostname(struct ConfigSet *cs)
187{
188 const char *short_host = NULL;
189 struct utsname utsname = { 0 };
190
191 const char *const c_hostname = cs_subset_string(NeoMutt->sub, "hostname");
192 if (c_hostname)
193 {
194 short_host = c_hostname;
195 }
196 else
197 {
198 /* The call to uname() shouldn't fail, but if it does, the system is horribly
199 * broken, and the system's networking configuration is in an unreliable
200 * state. We should bail. */
201 if ((uname(&utsname)) == -1)
202 {
203 mutt_perror(_("unable to determine nodename via uname()"));
204 return false; // TEST09: can't test
205 }
206
207 short_host = utsname.nodename;
208 }
209
210 /* some systems report the FQDN instead of just the hostname */
211 char *dot = strchr(short_host, '.');
212 if (dot)
213 ShortHostname = mutt_strn_dup(short_host, dot - short_host);
214 else
215 ShortHostname = mutt_str_dup(short_host);
216
217 // All the code paths from here alloc memory for the fqdn
218 char *fqdn = mutt_str_dup(c_hostname);
219 if (!fqdn)
220 {
221 mutt_debug(LL_DEBUG1, "Setting $hostname\n");
222 /* now get FQDN. Use configured domain first, DNS next, then uname */
223#ifdef DOMAIN
224 /* we have a compile-time domain name, use that for `$hostname` */
226 sprintf((char *) fqdn, "%s.%s", NONULL(ShortHostname), DOMAIN);
227#else
228 fqdn = getmailname();
229 if (!fqdn)
230 {
231 struct Buffer *domain = mutt_buffer_pool_get();
232 if (getdnsdomainname(domain) == 0)
233 {
235 sprintf((char *) fqdn, "%s.%s", NONULL(ShortHostname), mutt_buffer_string(domain));
236 }
237 else
238 {
239 /* DNS failed, use the nodename. Whether or not the nodename had a '.'
240 * in it, we can use the nodename as the FQDN. On hosts where DNS is
241 * not being used, e.g. small network that relies on hosts files, a
242 * short host name is all that is required for SMTP to work correctly.
243 * It could be wrong, but we've done the best we can, at this point the
244 * onus is on the user to provide the correct hostname if the nodename
245 * won't work in their network. */
246 fqdn = mutt_str_dup(utsname.nodename);
247 }
249 mutt_debug(LL_DEBUG1, "Hostname: %s\n", NONULL(fqdn));
250 }
251#endif
252 }
253
254 if (fqdn)
255 {
256 cs_str_initial_set(cs, "hostname", fqdn, NULL);
257 cs_str_reset(cs, "hostname", NULL);
258 FREE(&fqdn);
259 }
260
261 return true;
262}
263
272int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
273{
274 if (!dest || !tok)
275 return -1;
276
277 char ch;
278 char qc = '\0'; /* quote char */
279 char *pc = NULL;
280
281 /* Some callers used to rely on the (bad) assumption that dest->data would be
282 * non-NULL after calling this function. Perhaps I've missed a few cases, or
283 * a future caller might make the same mistake. */
284 if (!dest->data)
285 mutt_buffer_alloc(dest, 256);
286
287 mutt_buffer_reset(dest);
288
289 SKIPWS(tok->dptr);
290 while ((ch = *tok->dptr))
291 {
292 if (qc == '\0')
293 {
294 if ((IS_SPACE(ch) && !(flags & MUTT_TOKEN_SPACE)) ||
295 ((ch == '#') && !(flags & MUTT_TOKEN_COMMENT)) ||
296 ((ch == '+') && (flags & MUTT_TOKEN_PLUS)) ||
297 ((ch == '-') && (flags & MUTT_TOKEN_MINUS)) ||
298 ((ch == '=') && (flags & MUTT_TOKEN_EQUAL)) ||
299 ((ch == '?') && (flags & MUTT_TOKEN_QUESTION)) ||
300 ((ch == ';') && !(flags & MUTT_TOKEN_SEMICOLON)) ||
301 ((flags & MUTT_TOKEN_PATTERN) && strchr("~%=!|", ch)))
302 {
303 break;
304 }
305 }
306
307 tok->dptr++;
308
309 if (ch == qc)
310 qc = 0; /* end of quote */
311 else if (!qc && ((ch == '\'') || (ch == '"')) && !(flags & MUTT_TOKEN_QUOTE))
312 qc = ch;
313 else if ((ch == '\\') && (qc != '\''))
314 {
315 if (tok->dptr[0] == '\0')
316 return -1; /* premature end of token */
317 switch (ch = *tok->dptr++)
318 {
319 case 'c':
320 case 'C':
321 if (tok->dptr[0] == '\0')
322 return -1; /* premature end of token */
323 mutt_buffer_addch(dest, (toupper((unsigned char) tok->dptr[0]) - '@') & 0x7f);
324 tok->dptr++;
325 break;
326 case 'e':
327 mutt_buffer_addch(dest, '\033'); // Escape
328 break;
329 case 'f':
330 mutt_buffer_addch(dest, '\f');
331 break;
332 case 'n':
333 mutt_buffer_addch(dest, '\n');
334 break;
335 case 'r':
336 mutt_buffer_addch(dest, '\r');
337 break;
338 case 't':
339 mutt_buffer_addch(dest, '\t');
340 break;
341 default:
342 if (isdigit((unsigned char) ch) && isdigit((unsigned char) tok->dptr[0]) &&
343 isdigit((unsigned char) tok->dptr[1]))
344 {
345 mutt_buffer_addch(dest, (ch << 6) + (tok->dptr[0] << 3) + tok->dptr[1] - 3504);
346 tok->dptr += 2;
347 }
348 else
349 mutt_buffer_addch(dest, ch);
350 }
351 }
352 else if ((ch == '^') && (flags & MUTT_TOKEN_CONDENSE))
353 {
354 if (tok->dptr[0] == '\0')
355 return -1; /* premature end of token */
356 ch = *tok->dptr++;
357 if (ch == '^')
358 mutt_buffer_addch(dest, ch);
359 else if (ch == '[')
360 mutt_buffer_addch(dest, '\033'); // Escape
361 else if (isalpha((unsigned char) ch))
362 mutt_buffer_addch(dest, toupper((unsigned char) ch) - '@');
363 else
364 {
365 mutt_buffer_addch(dest, '^');
366 mutt_buffer_addch(dest, ch);
367 }
368 }
369 else if ((ch == '`') && (!qc || (qc == '"')))
370 {
371 FILE *fp = NULL;
372 pid_t pid;
373
374 pc = tok->dptr;
375 do
376 {
377 pc = strpbrk(pc, "\\`");
378 if (pc)
379 {
380 /* skip any quoted chars */
381 if (*pc == '\\')
382 pc += 2;
383 }
384 } while (pc && (pc[0] != '`'));
385 if (!pc)
386 {
387 mutt_debug(LL_DEBUG1, "mismatched backticks\n");
388 return -1;
389 }
390 struct Buffer cmd;
391 mutt_buffer_init(&cmd);
392 *pc = '\0';
393 if (flags & MUTT_TOKEN_BACKTICK_VARS)
394 {
395 /* recursively extract tokens to interpolate variables */
396 mutt_extract_token(&cmd, tok,
399 }
400 else
401 {
402 cmd.data = mutt_str_dup(tok->dptr);
403 }
404 *pc = '`';
405 pid = filter_create(cmd.data, NULL, &fp, NULL);
406 if (pid < 0)
407 {
408 mutt_debug(LL_DEBUG1, "unable to fork command: %s\n", cmd.data);
409 FREE(&cmd.data);
410 return -1;
411 }
412
413 tok->dptr = pc + 1;
414
415 /* read line */
416 struct Buffer expn = mutt_buffer_make(0);
417 expn.data = mutt_file_read_line(NULL, &expn.dsize, fp, NULL, MUTT_RL_NO_FLAGS);
418 mutt_file_fclose(&fp);
419 int rc = filter_wait(pid);
420 if (rc != 0)
421 mutt_debug(LL_DEBUG1, "backticks exited code %d for command: %s\n", rc,
422 mutt_buffer_string(&cmd));
423 FREE(&cmd.data);
424
425 /* if we got output, make a new string consisting of the shell output
426 * plus whatever else was left on the original line */
427 /* BUT: If this is inside a quoted string, directly add output to
428 * the token */
429 if (expn.data)
430 {
431 if (qc)
432 {
433 mutt_buffer_addstr(dest, expn.data);
434 }
435 else
436 {
437 struct Buffer *copy = mutt_buffer_pool_get();
439 mutt_buffer_copy(copy, &expn);
440 mutt_buffer_addstr(copy, tok->dptr);
441 mutt_buffer_copy(tok, copy);
442 mutt_buffer_seek(tok, 0);
444 }
445 FREE(&expn.data);
446 }
447 }
448 else if ((ch == '$') && (!qc || (qc == '"')) &&
449 ((tok->dptr[0] == '{') || isalpha((unsigned char) tok->dptr[0])))
450 {
451 const char *env = NULL;
452 char *var = NULL;
453
454 if (tok->dptr[0] == '{')
455 {
456 pc = strchr(tok->dptr, '}');
457 if (pc)
458 {
459 var = mutt_strn_dup(tok->dptr + 1, pc - (tok->dptr + 1));
460 tok->dptr = pc + 1;
461
462 if ((flags & MUTT_TOKEN_NOSHELL))
463 {
464 mutt_buffer_addch(dest, ch);
465 mutt_buffer_addch(dest, '{');
466 mutt_buffer_addstr(dest, var);
467 mutt_buffer_addch(dest, '}');
468 FREE(&var);
469 }
470 }
471 }
472 else
473 {
474 for (pc = tok->dptr; isalnum((unsigned char) *pc) || (pc[0] == '_'); pc++)
475 ; // do nothing
476
477 var = mutt_strn_dup(tok->dptr, pc - tok->dptr);
478 tok->dptr = pc;
479 }
480 if (var)
481 {
482 struct Buffer result;
483 mutt_buffer_init(&result);
484 int rc = cs_subset_str_string_get(NeoMutt->sub, var, &result);
485
486 if (CSR_RESULT(rc) == CSR_SUCCESS)
487 {
488 mutt_buffer_addstr(dest, result.data);
489 FREE(&result.data);
490 }
491 else if ((env = myvar_get(var)))
492 {
493 mutt_buffer_addstr(dest, env);
494 }
495 else if (!(flags & MUTT_TOKEN_NOSHELL) && (env = mutt_str_getenv(var)))
496 {
497 mutt_buffer_addstr(dest, env);
498 }
499 else
500 {
501 mutt_buffer_addch(dest, ch);
502 mutt_buffer_addstr(dest, var);
503 }
504 FREE(&var);
505 }
506 }
507 else
508 mutt_buffer_addch(dest, ch);
509 }
510 mutt_buffer_addch(dest, 0); /* terminate the string */
511 SKIPWS(tok->dptr);
512 return 0;
513}
514
519{
521
523#ifdef USE_SIDEBAR
524 sb_shutdown();
525#endif
526
532
535
536 /* Lists of strings */
546
548
550 FREE(&HomeDir);
553 FREE(&Username);
554
556
558
561
564}
565
574int mutt_init(struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands)
575{
576 int need_pause = 0;
577 int rc = 1;
578 struct Buffer err = mutt_buffer_make(256);
579 struct Buffer buf = mutt_buffer_make(256);
580
582 alias_init();
584#ifdef USE_COMP_MBOX
586#endif
587#ifdef USE_IMAP
588 imap_init();
589#endif
590#ifdef USE_LUA
592#endif
594
595 menu_init();
596#ifdef USE_SIDEBAR
597 sb_init();
598#endif
599#ifdef USE_NOTMUCH
600 nm_init();
601#endif
602
603 /* "$spool_file" precedence: config file, environment */
604 const char *p = mutt_str_getenv("MAIL");
605 if (!p)
606 p = mutt_str_getenv("MAILDIR");
607 if (!p)
608 {
609#ifdef HOMESPOOL
610 mutt_buffer_concat_path(&buf, NONULL(HomeDir), MAILPATH);
611#else
612 mutt_buffer_concat_path(&buf, MAILPATH, NONULL(Username));
613#endif
614 p = mutt_buffer_string(&buf);
615 }
616 cs_str_initial_set(cs, "spool_file", p, NULL);
617 cs_str_reset(cs, "spool_file", NULL);
618
619 p = mutt_str_getenv("REPLYTO");
620 if (p)
621 {
622 struct Buffer token;
623
624 mutt_buffer_printf(&buf, "Reply-To: %s", p);
625 mutt_buffer_init(&token);
626 parse_my_hdr(&token, &buf, 0, &err); /* adds to UserHeader */
627 FREE(&token.data);
628 }
629
630 p = mutt_str_getenv("EMAIL");
631 if (p)
632 {
633 cs_str_initial_set(cs, "from", p, NULL);
634 cs_str_reset(cs, "from", NULL);
635 }
636
637 /* "$mailcap_path" precedence: config file, environment, code */
638 const char *env_mc = mutt_str_getenv("MAILCAPS");
639 if (env_mc)
640 cs_str_string_set(cs, "mailcap_path", env_mc, NULL);
641
642 /* "$tmpdir" precedence: config file, environment, code */
643 const char *env_tmp = mutt_str_getenv("TMPDIR");
644 if (env_tmp)
645 cs_str_string_set(cs, "tmpdir", env_tmp, NULL);
646
647 /* "$visual", "$editor" precedence: config file, environment, code */
648 const char *env_ed = mutt_str_getenv("VISUAL");
649 if (!env_ed)
650 env_ed = mutt_str_getenv("EDITOR");
651 if (!env_ed)
652 env_ed = "vi";
653 cs_str_initial_set(cs, "editor", env_ed, NULL);
654
655 const char *const c_editor = cs_subset_string(NeoMutt->sub, "editor");
656 if (!c_editor)
657 cs_str_reset(cs, "editor", NULL);
658
659 const char *charset = mutt_ch_get_langinfo_charset();
660 cs_str_initial_set(cs, "charset", charset, NULL);
661 cs_str_reset(cs, "charset", NULL);
662 mutt_ch_set_charset(charset);
663 FREE(&charset);
664
665#ifdef HAVE_GETSID
666 /* Unset suspend by default if we're the session leader */
667 if (getsid(0) == getpid())
668 cs_subset_str_native_set(NeoMutt->sub, "suspend", false, NULL);
669#endif
670
671 /* RFC2368, "4. Unsafe headers"
672 * The creator of a mailto URL can't expect the resolver of a URL to
673 * understand more than the "subject" and "body" headers. Clients that
674 * resolve mailto URLs into mail messages should be able to correctly
675 * create RFC822-compliant mail messages using the "subject" and "body"
676 * headers. */
677 add_to_stailq(&MailToAllow, "body");
678 add_to_stailq(&MailToAllow, "subject");
679 /* Cc, In-Reply-To, and References help with not breaking threading on
680 * mailing lists, see https://github.com/neomutt/neomutt/issues/115 */
682 add_to_stailq(&MailToAllow, "in-reply-to");
683 add_to_stailq(&MailToAllow, "references");
684
685 if (STAILQ_EMPTY(&Muttrc))
686 {
687 const char *xdg_cfg_home = mutt_str_getenv("XDG_CONFIG_HOME");
688
689 if (!xdg_cfg_home && HomeDir)
690 {
691 mutt_buffer_printf(&buf, "%s/.config", HomeDir);
692 xdg_cfg_home = mutt_buffer_string(&buf);
693 }
694
695 char *config = find_cfg(HomeDir, xdg_cfg_home);
696 if (config)
697 {
699 }
700 }
701 else
702 {
703 struct ListNode *np = NULL;
704 STAILQ_FOREACH(np, &Muttrc, entries)
705 {
706 mutt_buffer_strcpy(&buf, np->data);
707 FREE(&np->data);
709 np->data = mutt_buffer_strdup(&buf);
710 if (access(np->data, F_OK))
711 {
712 mutt_perror(np->data);
713 goto done; // TEST10: neomutt -F missing
714 }
715 }
716 }
717
718 if (!STAILQ_EMPTY(&Muttrc))
719 {
720 cs_str_string_set(cs, "alias_file", STAILQ_FIRST(&Muttrc)->data, NULL);
721 }
722
723 /* Process the global rc file if it exists and the user hasn't explicitly
724 * requested not to via "-n". */
725 if (!skip_sys_rc)
726 {
727 do
728 {
730 break;
731
732 mutt_buffer_printf(&buf, "%s/neomuttrc", SYSCONFDIR);
733 if (access(mutt_buffer_string(&buf), F_OK) == 0)
734 break;
735
736 mutt_buffer_printf(&buf, "%s/Muttrc", SYSCONFDIR);
737 if (access(mutt_buffer_string(&buf), F_OK) == 0)
738 break;
739
740 mutt_buffer_printf(&buf, "%s/neomuttrc", PKGDATADIR);
741 if (access(mutt_buffer_string(&buf), F_OK) == 0)
742 break;
743
744 mutt_buffer_printf(&buf, "%s/Muttrc", PKGDATADIR);
745 } while (false);
746
747 if (access(mutt_buffer_string(&buf), F_OK) == 0)
748 {
749 if (source_rc(mutt_buffer_string(&buf), &err) != 0)
750 {
751 mutt_error("%s", err.data);
752 need_pause = 1; // TEST11: neomutt (error in /etc/neomuttrc)
753 }
754 }
755 }
756
757 /* Read the user's initialization file. */
758 struct ListNode *np = NULL;
759 STAILQ_FOREACH(np, &Muttrc, entries)
760 {
761 if (np->data)
762 {
763 if (source_rc(np->data, &err) != 0)
764 {
765 mutt_error("%s", err.data);
766 need_pause = 1; // TEST12: neomutt (error in ~/.neomuttrc)
767 }
768 }
769 }
770
771 if (execute_commands(commands) != 0)
772 need_pause = 1; // TEST13: neomutt -e broken
773
774 if (!get_hostname(cs))
775 goto done;
776
777 {
778 char name[256] = { 0 };
779 const char *c_real_name = cs_subset_string(NeoMutt->sub, "real_name");
780 if (!c_real_name)
781 {
782 struct passwd *pw = getpwuid(getuid());
783 if (pw)
784 c_real_name = mutt_gecos_name(name, sizeof(name), pw);
785 }
786 cs_str_initial_set(cs, "real_name", c_real_name, NULL);
787 cs_str_reset(cs, "real_name", NULL);
788 }
789
790 if (need_pause && !OptNoCurses)
791 {
793 if (mutt_any_key_to_continue(NULL) == 'q')
794 goto done; // TEST14: neomutt -e broken (press 'q')
795 }
796
797 const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
798 mutt_file_mkdir(c_tmpdir, S_IRWXU);
799
802
803#ifdef USE_NOTMUCH
804 const bool c_virtual_spool_file = cs_subset_bool(NeoMutt->sub, "virtual_spool_file");
805 if (c_virtual_spool_file)
806 {
807 /* Find the first virtual folder and open it */
808 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
810 struct MailboxNode *mp = STAILQ_FIRST(&ml);
811 if (mp)
812 cs_str_string_set(cs, "spool_file", mailbox_path(mp->mailbox), NULL);
814 }
815#endif
816 rc = 0;
817
818done:
821 return rc;
822}
823
836 struct Buffer *token, struct Buffer *err)
837{
838 if (mutt_buffer_len(line) == 0)
839 return 0;
840
842
844
845 /* Read from the beginning of line->data */
846 mutt_buffer_seek(line, 0);
847
848 SKIPWS(line->dptr);
849 while (*line->dptr)
850 {
851 if (*line->dptr == '#')
852 break; /* rest of line is a comment */
853 if (*line->dptr == ';')
854 {
855 line->dptr++;
856 continue;
857 }
859
860 struct Command *cmd = NULL;
861 size_t size = mutt_commands_array(&cmd);
862 size_t i;
863 for (i = 0; i < size; i++)
864 {
865 if (mutt_str_equal(token->data, cmd[i].name))
866 {
867 mutt_debug(LL_DEBUG1, "NT_COMMAND: %s\n", cmd[i].name);
868 rc = cmd[i].parse(token, line, cmd[i].data, err);
869 if ((rc == MUTT_CMD_WARNING) || (rc == MUTT_CMD_ERROR) || (rc == MUTT_CMD_FINISH))
870 goto finish; /* Propagate return code */
871
872 notify_send(NeoMutt->notify, NT_COMMAND, i, (void *) cmd);
873 break; /* Continue with next command */
874 }
875 }
876 if (i == size)
877 {
878 mutt_buffer_printf(err, _("%s: unknown command"), NONULL(token->data));
879 rc = MUTT_CMD_ERROR;
880 break; /* Ignore the rest of the line */
881 }
882 }
883finish:
884 return rc;
885}
886
893enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
894{
895 if (!line || (*line == '\0'))
896 return MUTT_CMD_ERROR;
897
898 struct Buffer *line_buffer = mutt_buffer_pool_get();
899 struct Buffer *token = mutt_buffer_pool_get();
900
901 mutt_buffer_strcpy(line_buffer, line);
902
903 enum CommandResult rc = mutt_parse_rc_buffer(line_buffer, token, err);
904
905 mutt_buffer_pool_release(&line_buffer);
907 return rc;
908}
909
917int mutt_query_variables(struct ListHead *queries, bool show_docs)
918{
919 struct Buffer value = mutt_buffer_make(256);
920 struct Buffer tmp = mutt_buffer_make(256);
921 int rc = 0;
922
923 struct ListNode *np = NULL;
924 STAILQ_FOREACH(np, queries, entries)
925 {
926 mutt_buffer_reset(&value);
927
928 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, np->data);
929 if (!he)
930 {
931 mutt_warning(_("No such variable: %s"), np->data);
932 rc = 1;
933 continue;
934 }
935
936 if (he->type & DT_DEPRECATED)
937 {
938 mutt_warning(_("Config variable '%s' is deprecated"), np->data);
939 rc = 1;
940 continue;
941 }
942
943 int rv = cs_subset_he_string_get(NeoMutt->sub, he, &value);
944 if (CSR_RESULT(rv) != CSR_SUCCESS)
945 {
946 rc = 1;
947 continue;
948 }
949
950 int type = DTYPE(he->type);
951 if (type == DT_PATH)
952 mutt_pretty_mailbox(value.data, value.dsize);
953
954 if ((type != DT_BOOL) && (type != DT_NUMBER) && (type != DT_LONG) && (type != DT_QUAD))
955 {
956 mutt_buffer_reset(&tmp);
957 pretty_var(value.data, &tmp);
958 mutt_buffer_strcpy(&value, tmp.data);
959 }
960
961 dump_config_neo(NeoMutt->sub->cs, he, &value, NULL,
962 show_docs ? CS_DUMP_SHOW_DOCS : CS_DUMP_NO_FLAGS, stdout);
963 }
964
965 mutt_buffer_dealloc(&value);
967
968 return rc; // TEST16: neomutt -Q charset
969}
Email Address Handling.
Email Aliases.
void alias_init(void)
Set up the Alias globals.
Definition: alias.c:679
void alias_shutdown(void)
Clean up the Alias globals.
Definition: alias.c:687
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
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:275
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:371
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:52
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:189
void mutt_buffer_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:483
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:462
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:447
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:389
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
Color and attribute parsing.
void mutt_colors_cleanup(void)
Cleanup all the colours.
Definition: color.c:71
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_WARNING
Warning: Help given to the user.
Definition: command.h:36
@ MUTT_CMD_FINISH
Finish: Stop processing this file.
Definition: command.h:38
void clear_source_stack(void)
Free memory from the stack used for the source command.
int source_rc(const char *rcfile_path, struct Buffer *err)
Read an initialization file.
Functions to parse commands in a config file.
void mutt_comp_init(void)
Setup feature commands.
Definition: compress.c:70
Compressed mbox local mailbox type.
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
Convenience wrapper for the config headers.
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
Connection Library.
Convenience wrapper for the core headers.
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:387
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:522
#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
Structs that make up an email.
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:736
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:151
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:946
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:39
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 getdnsdomainname(struct Buffer *result)
Lookup the host's name using DNS.
Definition: getdomain.c:122
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_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() -.
#define mutt_warning(...)
Definition: logging.h:85
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_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
Convenience wrapper for the gui headers.
Read/write command history from/to a file.
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 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:367
Parse and execute user-defined hooks.
#define MUTT_HOOK_NO_FLAGS
No flags are set.
Definition: hook.h:37
IMAP network mailbox.
void imap_init(void)
Setup feature commands.
Definition: imap.c:84
static char * find_cfg(const char *home, const char *xdg_cfg_home)
Find a config file.
Definition: init.c:113
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:272
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:893
enum CommandResult mutt_parse_rc_buffer(struct Buffer *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:835
static char * getmailname(void)
Try to retrieve the FQDN from mailname files.
Definition: init.c:154
static int execute_commands(struct ListHead *p)
Execute a set of NeoMutt commands.
Definition: init.c:81
int mutt_query_variables(struct ListHead *queries, bool show_docs)
Implement the -Q command line flag.
Definition: init.c:917
void mutt_opts_free(void)
Clean up before quitting.
Definition: init.c:518
int mutt_init(struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:574
static bool get_hostname(struct ConfigSet *cs)
Find the Fully-Qualified Domain Name.
Definition: init.c:186
Config/command parsing.
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1668
Manage keymappings.
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:346
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:43
#define mutt_array_size(x)
Definition: memory.h:36
GUI present the user with a selectable list.
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
Convenience wrapper for the library headers.
#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
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
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:451
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:927
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
Many unsorted constants and some structs.
#define MUTT_TOKEN_CONDENSE
^(char) to control chars (macros)
Definition: mutt.h:69
#define MUTT_TOKEN_BACKTICK_VARS
Expand variables within backticks.
Definition: mutt.h:75
#define MUTT_TOKEN_MINUS
Treat '-' as a special.
Definition: mutt.h:79
#define MUTT_TOKEN_PLUS
Treat '+' as a special.
Definition: mutt.h:78
#define MUTT_TOKEN_COMMENT
Don't reap comments.
Definition: mutt.h:73
#define MUTT_TOKEN_QUOTE
Don't interpret quotes.
Definition: mutt.h:71
#define MUTT_TOKEN_NOSHELL
Don't expand environment variables.
Definition: mutt.h:76
uint16_t TokenFlags
Flags for mutt_extract_token(), e.g. MUTT_TOKEN_EQUAL.
Definition: mutt.h:66
#define MUTT_TOKEN_SPACE
Don't treat whitespace as a term.
Definition: mutt.h:70
#define MUTT_TOKEN_SEMICOLON
Don't treat ; as special.
Definition: mutt.h:74
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:67
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:72
#define MUTT_TOKEN_EQUAL
Treat '=' as a special.
Definition: mutt.h:68
#define MUTT_TOKEN_QUESTION
Treat '?' as a special.
Definition: mutt.h:77
void mutt_commands_free(void)
Free Commands array.
size_t mutt_commands_array(struct Command **first)
Get Commands array.
void mutt_commands_init(void)
Initialize commands array and register default commands.
struct CommandArray commands
Definitions of NeoMutt commands.
Hundreds of global variables to back the user variables.
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 Muttrc
List of config files to read.
Definition: mutt_globals.h:64
char * Username
User's login name.
Definition: mutt_globals.h:52
struct ListHead HeaderOrderList
List of header fields in the order they should be displayed.
Definition: mutt_globals.h:62
void mutt_lua_init(void)
Setup feature commands.
Definition: mutt_lua.c:469
Integrated Lua scripting.
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
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 add_to_stailq(struct ListHead *head, const char *str)
Add a string to a list.
Definition: muttlib.c:1719
int mutt_set_xdg_path(enum XdgType type, struct Buffer *buf)
Find an XDG path or its fallback.
Definition: muttlib.c:1510
Some miscellaneous functions.
const char * myvar_get(const char *var)
Get the value of a "my_" variable.
Definition: myvar.c:92
Handling of personal config ('my' variables)
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
@ NT_COMMAND
A Command has been executed, Command.
Definition: notify_type.h:42
Notmuch virtual mailbox type.
void nm_init(void)
Setup feature commands.
Definition: notmuch.c:99
Handling of global boolean variables.
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:53
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
Prototypes for many functions.
@ XDG_CONFIG_DIRS
XDG system dir: /etc/xdg.
Definition: protos.h:44
#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
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
GUI display the mailboxes in a side panel.
void sb_init(void)
Set up the Sidebar.
Definition: sidebar.c:196
void sb_shutdown(void)
Clean up the Sidebar.
Definition: sidebar.c:208
#define NONULL(x)
Definition: string2.h:37
#define IS_SPACE(ch)
Definition: string2.h:38
#define SKIPWS(ch)
Definition: string2.h:46
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
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
const char * name
Name of the command.
Definition: command.h:50
Container for lots of config items.
Definition: set.h:260
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
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
List of Mailboxes.
Definition: mailbox.h:153
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:154
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
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
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
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
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition: subset.c:179
void driver_tags_cleanup(void)
Deinitialize structures used for tags.
Definition: tags.c:230
void driver_tags_init(void)
Initialize structures used for tags.
Definition: tags.c:218
#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