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