NeoMutt  2025-12-11-276-g10b23b
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
muttlib.c
Go to the documentation of this file.
1
27
33
34#include "config.h"
35#include <errno.h>
36#include <limits.h>
37#include <pwd.h>
38#include <stdbool.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <sys/stat.h>
43#include <unistd.h>
44#include "mutt/lib.h"
45#include "address/lib.h"
46#include "config/lib.h"
47#include "email/lib.h"
48#include "core/lib.h"
49#include "alias/lib.h"
50#include "gui/lib.h"
51#include "mutt.h"
52#include "muttlib.h"
53#include "browser/lib.h"
54#include "editor/lib.h"
55#include "history/lib.h"
56#include "hooks/lib.h"
57#include "imap/lib.h"
58#include "ncrypt/lib.h"
59#include "question/lib.h"
60#include "globals.h"
61#include "mx.h"
62
64static const char *XdgEnvVars[] = {
65 [XDG_CONFIG_HOME] = "XDG_CONFIG_HOME",
66 [XDG_CONFIG_DIRS] = "XDG_CONFIG_DIRS",
67};
68
70static const char *XdgDefaults[] = {
71 [XDG_CONFIG_HOME] = "~/.config",
72 [XDG_CONFIG_DIRS] = "/etc/xdg",
73};
74
83void mutt_adv_mktemp(struct Buffer *buf)
84{
85 if (buf_is_empty(buf))
86 {
87 buf_mktemp(buf);
88 }
89 else
90 {
91 struct Buffer *prefix = buf_pool_get();
92 buf_strcpy(prefix, buf->data);
93 mutt_file_sanitize_filename(prefix->data, true);
94 const char *const c_tmp_dir = cs_subset_path(NeoMutt->sub, "tmp_dir");
95 buf_printf(buf, "%s/%s", NONULL(c_tmp_dir), buf_string(prefix));
96
97 struct stat st = { 0 };
98 if ((lstat(buf_string(buf), &st) == -1) && (errno == ENOENT))
99 goto out;
100
101 char *suffix = strchr(prefix->data, '.');
102 if (suffix)
103 {
104 *suffix = '\0';
105 suffix++;
106 }
107 buf_mktemp_pfx_sfx(buf, prefix->data, suffix);
108
109 out:
110 buf_pool_release(&prefix);
111 }
112}
113
121void expand_path(struct Buffer *buf, bool regex)
122{
123 const char *s = NULL;
124 const char *tail = "";
125
126 bool recurse = false;
127
128 struct Buffer *p = buf_pool_get();
129 struct Buffer *q = buf_pool_get();
130 struct Buffer *tmp = buf_pool_get();
131
132 do
133 {
134 recurse = false;
135 s = buf_string(buf);
136
137 switch (*s)
138 {
139 case '~':
140 {
141 if ((s[1] == '/') || (s[1] == '\0'))
142 {
144 tail = s + 1;
145 }
146 else
147 {
148 char *t = strchr(s + 1, '/');
149 if (t)
150 *t = '\0';
151
152 struct passwd *pw = getpwnam(s + 1);
153 if (pw)
154 {
155 buf_strcpy(p, pw->pw_dir);
156 if (t)
157 {
158 *t = '/';
159 tail = t;
160 }
161 else
162 {
163 tail = "";
164 }
165 }
166 else
167 {
168 /* user not found! */
169 if (t)
170 *t = '/';
171 buf_reset(p);
172 tail = s;
173 }
174 }
175 break;
176 }
177
178 case '=':
179 case '+':
180 {
181 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
182 enum MailboxType mb_type = mx_path_probe(c_folder);
183
184 /* if folder = {host} or imap[s]://host/: don't append slash */
185 if ((mb_type == MUTT_IMAP) && ((c_folder[strlen(c_folder) - 1] == '}') ||
186 (c_folder[strlen(c_folder) - 1] == '/')))
187 {
188 buf_strcpy(p, c_folder);
189 }
190 else if (mb_type == MUTT_NOTMUCH)
191 {
192 buf_strcpy(p, c_folder);
193 }
194 else if (c_folder && (c_folder[strlen(c_folder) - 1] == '/'))
195 {
196 buf_strcpy(p, c_folder);
197 }
198 else
199 {
200 buf_printf(p, "%s/", NONULL(c_folder));
201 }
202
203 tail = s + 1;
204 break;
205 }
206
207 /* elm compatibility, @ expands alias to user name */
208
209 case '@':
210 {
211 struct AddressList *al = alias_lookup(s + 1);
212 if (al && !TAILQ_EMPTY(al))
213 {
214 struct Email *e = email_new();
215 e->env = mutt_env_new();
216 mutt_addrlist_copy(&e->env->from, al, false);
217 mutt_addrlist_copy(&e->env->to, al, false);
218
220 mutt_default_save(p, e);
221
222 email_free(&e);
223 /* Avoid infinite recursion if the resulting folder starts with '@' */
224 if (*p->data != '@')
225 recurse = true;
226
227 tail = "";
228 }
229 break;
230 }
231
232 case '>':
233 {
234 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
235 buf_strcpy(p, c_mbox);
236 tail = s + 1;
237 break;
238 }
239
240 case '<':
241 {
242 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
243 buf_strcpy(p, c_record);
244 tail = s + 1;
245 break;
246 }
247
248 case '!':
249 {
250 if (s[1] == '!')
251 {
253 tail = s + 2;
254 }
255 else
256 {
257 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
258 buf_strcpy(p, c_spool_file);
259 tail = s + 1;
260 }
261 break;
262 }
263
264 case '-':
265 {
267 tail = s + 1;
268 break;
269 }
270
271 case '^':
272 {
274 tail = s + 1;
275 break;
276 }
277
278 default:
279 {
280 buf_reset(p);
281 tail = s;
282 }
283 }
284
285 if (regex && *(buf_string(p)) && !recurse)
286 {
288 buf_printf(tmp, "%s%s", buf_string(q), tail);
289 }
290 else
291 {
292 buf_printf(tmp, "%s%s", buf_string(p), tail);
293 }
294
295 buf_copy(buf, tmp);
296 } while (recurse);
297
300 buf_pool_release(&tmp);
301
302 /* Rewrite IMAP path in canonical form - aids in string comparisons of
303 * folders. May possibly fail, in which case buf should be the same. */
304 if (imap_path_probe(buf_string(buf), NULL) == MUTT_IMAP)
305 imap_path_canon(buf);
306}
307
320char *mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
321{
322 regmatch_t pat_match[1] = { 0 };
323 char *p = NULL;
324
325 if (!pw || !pw->pw_gecos)
326 return NULL;
327
328 memset(dest, 0, destlen);
329
330 const struct Regex *c_gecos_mask = cs_subset_regex(NeoMutt->sub, "gecos_mask");
331 if (mutt_regex_capture(c_gecos_mask, pw->pw_gecos, 1, pat_match))
332 {
333 mutt_str_copy(dest, pw->pw_gecos + pat_match[0].rm_so,
334 MIN(pat_match[0].rm_eo - pat_match[0].rm_so + 1, destlen));
335 }
336 else if ((p = strchr(pw->pw_gecos, ',')))
337 {
338 mutt_str_copy(dest, pw->pw_gecos, MIN(destlen, p - pw->pw_gecos + 1));
339 }
340 else
341 {
342 mutt_str_copy(dest, pw->pw_gecos, destlen);
343 }
344
345 size_t pwnl = strlen(pw->pw_name);
346
347 for (int idx = 0; dest[idx]; idx++)
348 {
349 if (dest[idx] == '&')
350 {
351 memmove(&dest[idx + pwnl], &dest[idx + 1],
352 MAX((ssize_t) (destlen - idx - pwnl - 1), 0));
353 memcpy(&dest[idx], pw->pw_name, MIN(destlen - idx - 1, pwnl));
354 dest[idx] = mutt_toupper(dest[idx]);
355 }
356 }
357
358 return dest;
359}
360
368{
369 switch (b->type)
370 {
371 case TYPE_TEXT:
372 if (mutt_istr_equal("plain", b->subtype))
373 return false;
374 break;
375 case TYPE_APPLICATION:
377 return false;
379 return false;
380 break;
381
382 case TYPE_MULTIPART:
383 case TYPE_MESSAGE:
384 return false;
385 }
386
387 return true;
388}
389
395bool mutt_is_text_part(const struct Body *b)
396{
397 int t = b->type;
398 char *s = b->subtype;
399
401 return false;
402
403 if (t == TYPE_TEXT)
404 return true;
405
406 if (t == TYPE_MESSAGE)
407 {
408 if (mutt_istr_equal("delivery-status", s))
409 return true;
410 }
411
412 if (((WithCrypto & APPLICATION_PGP) != 0) && (t == TYPE_APPLICATION))
413 {
414 if (mutt_istr_equal("pgp-keys", s))
415 return true;
416 }
417
418 return false;
419}
420
427void pretty_mailbox(struct Buffer *buf)
428{
429 if (!buf || !buf->data)
430 return;
431
432 /* Ensure buffer is large enough for path manipulation operations.
433 * The function will modify the string in-place, potentially shortening it.
434 * buf_alloc() also guarantees buf->data is not NULL. */
435 buf_alloc(buf, PATH_MAX);
436
437 char *p = buf->data;
438 char *q = buf->data;
439 size_t len;
440 enum UrlScheme scheme;
441 char tmp[PATH_MAX] = { 0 };
442
443 scheme = url_check_scheme(buf->data);
444
445 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
446 if ((scheme == U_IMAP) || (scheme == U_IMAPS))
447 {
448 imap_pretty_mailbox(buf->data, buf->dsize, c_folder);
449 goto done;
450 }
451
452 if (scheme == U_NOTMUCH)
453 goto done;
454
455 /* if buf is an url, only collapse path component */
456 if (scheme != U_UNKNOWN)
457 {
458 p = strchr(buf->data, ':') + 1;
459 if (mutt_strn_equal(p, "//", 2))
460 q = strchr(p + 2, '/');
461 if (!q)
462 q = strchr(p, '\0');
463 p = q;
464 }
465
466 /* cleanup path */
467 if (strstr(p, "//") || strstr(p, "/./"))
468 {
469 /* first attempt to collapse the pathname, this is more
470 * lightweight than realpath() and doesn't resolve links */
471 while (*p)
472 {
473 if ((p[0] == '/') && (p[1] == '/'))
474 {
475 *q++ = '/';
476 p += 2;
477 }
478 else if ((p[0] == '/') && (p[1] == '.') && (p[2] == '/'))
479 {
480 *q++ = '/';
481 p += 3;
482 }
483 else
484 {
485 *q++ = *p++;
486 }
487 }
488 *q = '\0';
489 }
490 else if (strstr(p, "..") && ((scheme == U_UNKNOWN) || (scheme == U_FILE)) &&
491 realpath(p, tmp))
492 {
493 mutt_str_copy(p, tmp, buf->dsize - (p - buf->data));
494 }
495
496 if ((len = mutt_str_startswith(buf->data, c_folder)) && (buf->data[len] == '/'))
497 {
498 buf->data[0] = '=';
499 memmove(buf->data + 1, buf->data + len, mutt_str_len(buf->data + len) + 1);
500 }
501 else if ((len = mutt_str_startswith(buf->data, NeoMutt->home_dir)) &&
502 (buf->data[len] == '/'))
503 {
504 buf->data[0] = '~';
505 memmove(buf->data + 1, buf->data + len, mutt_str_len(buf->data + len) + 1);
506 }
507
508done:
509 buf_fix_dptr(buf);
510}
511
523int mutt_check_overwrite(const char *attname, const char *path, struct Buffer *fname,
524 enum SaveAttach *opt, char **directory)
525{
526 struct stat st = { 0 };
527
528 buf_strcpy(fname, path);
529 if (access(buf_string(fname), F_OK) != 0)
530 return 0;
531 if (stat(buf_string(fname), &st) != 0)
532 return -1;
533 if (S_ISDIR(st.st_mode))
534 {
535 enum QuadOption ans = MUTT_NO;
536 if (directory)
537 {
538 switch (mw_multi_choice
539 /* L10N: Means "The path you specified as the destination file is a directory."
540 See the msgid "Save to file: " (alias.c, recvattach.c)
541 These three letters correspond to the choices in the string. */
542 (_("File is a directory, save under it: (y)es, (n)o, (a)ll?"), _("yna")))
543 {
544 case 3: /* all */
545 mutt_str_replace(directory, buf_string(fname));
546 break;
547 case 1: /* yes */
548 FREE(directory);
549 break;
550 case -1: /* abort */
551 FREE(directory);
552 return -1;
553 case 2: /* no */
554 FREE(directory);
555 return 1;
556 }
557 }
558 /* L10N: Means "The path you specified as the destination file is a directory."
559 See the msgid "Save to file: " (alias.c, recvattach.c) */
560 else if ((ans = query_yesorno(_("File is a directory, save under it?"), MUTT_YES)) != MUTT_YES)
561 return (ans == MUTT_NO) ? 1 : -1;
562
563 struct Buffer *tmp = buf_pool_get();
564 buf_strcpy(tmp, mutt_path_basename(NONULL(attname)));
565 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
566 if ((mw_get_field(_("File under directory: "), tmp, MUTT_COMP_CLEAR,
567 HC_FILE, &CompleteFileOps, &cdata) != 0) ||
568 buf_is_empty(tmp))
569 {
570 buf_pool_release(&tmp);
571 return (-1);
572 }
573 buf_concat_path(fname, path, buf_string(tmp));
574 buf_pool_release(&tmp);
575 }
576
577 if ((*opt == MUTT_SAVE_NO_FLAGS) && (access(buf_string(fname), F_OK) == 0))
578 {
579 char buf[4096] = { 0 };
580 snprintf(buf, sizeof(buf), "%s - %s", buf_string(fname),
581 // L10N: Options for: File %s exists, (o)verwrite, (a)ppend, or (c)ancel?
582 _("File exists, (o)verwrite, (a)ppend, or (c)ancel?"));
583 switch (mw_multi_choice(buf, _("oac")))
584 {
585 case -1: /* abort */
586 return -1;
587 case 3: /* cancel */
588 return 1;
589
590 case 2: /* append */
591 *opt = MUTT_SAVE_APPEND;
592 break;
593 case 1: /* overwrite */
594 break;
595 }
596 }
597 return 0;
598}
599
607void generate_save_path(struct Buffer *dest, const struct Address *a)
608{
609 if (a && a->mailbox)
610 {
611 buf_copy(dest, a->mailbox);
612 const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
613 if (!c_save_address)
614 {
615 char *p = strpbrk(dest->data, "%@");
616 if (p)
617 {
618 *p = '\0';
619 buf_fix_dptr(dest);
620 }
621 }
622 mutt_str_lower(dest->data);
623 /* Sanitize filename by replacing unsafe characters */
624 for (char *p = dest->data; *p; p++)
625 if ((*p == '/') || mutt_isspace(*p) || !IsPrint((unsigned char) *p))
626 *p = '_';
627 }
628 else
629 {
630 buf_reset(dest);
631 }
632}
633
644FILE *mutt_open_read(const char *path, pid_t *thepid)
645{
646 FILE *fp = NULL;
647 struct stat st = { 0 };
648
649 size_t len = mutt_str_len(path);
650 if (len == 0)
651 {
652 return NULL;
653 }
654
655 if (path[len - 1] == '|')
656 {
657 /* read from a pipe */
658
659 char *p = mutt_str_dup(path);
660
661 p[len - 1] = 0;
662 mutt_endwin();
663 *thepid = filter_create(p, NULL, &fp, NULL, NeoMutt->env);
664 FREE(&p);
665 }
666 else
667 {
668 if (stat(path, &st) < 0)
669 return NULL;
670 if (S_ISDIR(st.st_mode))
671 {
672 errno = EINVAL;
673 return NULL;
674 }
675 fp = mutt_file_fopen(path, "r");
676 *thepid = -1;
677 }
678 return fp;
679}
680
689int mutt_save_confirm(const char *s, struct stat *st)
690{
691 int rc = 0;
692
693 enum MailboxType type = mx_path_probe(s);
694
695 if (type == MUTT_POP)
696 {
697 mutt_error(_("Can't save message to POP mailbox"));
698 return 1;
699 }
700
701 if ((type != MUTT_MAILBOX_ERROR) && (type != MUTT_UNKNOWN) && (mx_access(s, W_OK) == 0))
702 {
703 const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
704 if (c_confirm_append)
705 {
706 struct Buffer *tmp = buf_pool_get();
707 buf_printf(tmp, _("Append messages to %s?"), s);
709 NeoMutt->sub, "confirm_append");
710 if (ans == MUTT_NO)
711 rc = 1;
712 else if (ans == MUTT_ABORT)
713 rc = -1;
714 buf_pool_release(&tmp);
715 }
716 }
717
718 if (type == MUTT_NNTP)
719 {
720 mutt_error(_("Can't save message to news server"));
721 return 0;
722 }
723
724 if (stat(s, st) != -1)
725 {
726 if (type == MUTT_MAILBOX_ERROR)
727 {
728 mutt_error(_("%s is not a mailbox"), s);
729 return 1;
730 }
731 }
732 else if (type != MUTT_IMAP)
733 {
734 st->st_mtime = 0;
735 st->st_atime = 0;
736
737 /* pathname does not exist */
738 if (errno == ENOENT)
739 {
740 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
741 if (c_confirm_create)
742 {
743 struct Buffer *tmp = buf_pool_get();
744 buf_printf(tmp, _("Create %s?"), s);
746 NeoMutt->sub, "confirm_create");
747 if (ans == MUTT_NO)
748 rc = 1;
749 else if (ans == MUTT_ABORT)
750 rc = -1;
751 buf_pool_release(&tmp);
752 }
753
754 /* user confirmed with MUTT_YES or set `$confirm_create` */
755 if (rc == 0)
756 {
757 /* create dir recursively */
758 char *tmp_path = mutt_path_dirname(s);
759 if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1)
760 {
761 /* report failure & abort */
762 mutt_perror("%s", s);
763 FREE(&tmp_path);
764 return 1;
765 }
766 FREE(&tmp_path);
767 }
768 }
769 else
770 {
771 mutt_perror("%s", s);
772 return 1;
773 }
774 }
775
776 msgwin_clear_text(NULL);
777 return rc;
778}
779
786void mutt_sleep(short s)
787{
788 const short c_sleep_time = cs_subset_number(NeoMutt->sub, "sleep_time");
789 if (c_sleep_time > s)
790 sleep(c_sleep_time);
791 else if (s)
792 sleep(s);
793}
794
802void mutt_encode_path(struct Buffer *buf, const char *src)
803{
804 char *p = mutt_str_dup(src);
805 int rc = mutt_ch_convert_string(&p, cc_charset(), "us-ascii", MUTT_ICONV_NO_FLAGS);
806 size_t len = buf_strcpy(buf, (rc == 0) ? NONULL(p) : NONULL(src));
807
808 /* convert the path to POSIX "Portable Filename Character Set" */
809 for (size_t i = 0; i < len; i++)
810 {
811 if (!mutt_isalnum(buf_at(buf, i)) && !strchr("/.-_", buf_at(buf, i)))
812 {
813 buf->data[i] = '_';
814 }
815 }
816 FREE(&p);
817}
818
827int mutt_set_xdg_path(enum XdgType type, struct Buffer *buf)
828{
829 const char *xdg_env = mutt_str_getenv(XdgEnvVars[type]);
830 char *xdg = xdg_env ? mutt_str_dup(xdg_env) : mutt_str_dup(XdgDefaults[type]);
831 char *x = xdg; /* mutt_str_sep() changes xdg, so free x instead later */
832 char *token = NULL;
833 int rc = 0;
834
835 while ((token = mutt_str_sep(&xdg, ":")))
836 {
837 if (buf_printf(buf, "%s/%s/neomuttrc", token, PACKAGE) < 0)
838 continue;
839 expand_path(buf, false);
840 if (access(buf_string(buf), F_OK) == 0)
841 {
842 rc = 1;
843 break;
844 }
845
846 if (buf_printf(buf, "%s/%s/Muttrc", token, PACKAGE) < 0)
847 continue;
848 expand_path(buf, false);
849 if (access(buf_string(buf), F_OK) == 0)
850 {
851 rc = 1;
852 break;
853 }
854 }
855
856 FREE(&x);
857 return rc;
858}
859
866void mutt_get_parent_path(const char *path, char *buf, size_t buflen)
867{
868 enum MailboxType mb_type = mx_path_probe(path);
869
870 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
871 if (mb_type == MUTT_IMAP)
872 {
873 imap_get_parent_path(path, buf, buflen);
874 }
875 else if (mb_type == MUTT_NOTMUCH)
876 {
877 mutt_str_copy(buf, c_folder, buflen);
878 }
879 else
880 {
881 mutt_str_copy(buf, path, buflen);
882 int n = mutt_str_len(buf);
883 if (n == 0)
884 return;
885
886 /* remove any final trailing '/' */
887 if (buf[n - 1] == '/')
888 buf[n - 1] = '\0';
889
890 /* Remove everything until the next slash */
891 for (n--; ((n >= 0) && (buf[n] != '/')); n--)
892 ; // do nothing
893
894 if (n > 0)
895 {
896 buf[n] = '\0';
897 }
898 else
899 {
900 buf[0] = '/';
901 buf[1] = '\0';
902 }
903 }
904}
905
912void buf_sanitize_filename(struct Buffer *buf, const char *path, short slash)
913{
914 if (!buf || !path)
915 return;
916
917 buf_reset(buf);
918
919 for (; *path; path++)
920 {
921 if ((slash && (*path == '/')) || !strchr(FilenameSafeChars, *path))
922 buf_addch(buf, '_');
923 else
924 buf_addch(buf, *path);
925 }
926}
927
934int mutt_str_pretty_size(struct Buffer *buf, size_t num)
935{
936 if (!buf)
937 return 0;
938
939 const bool c_size_show_bytes = cs_subset_bool(NeoMutt->sub, "size_show_bytes");
940 const bool c_size_show_fractions = cs_subset_bool(NeoMutt->sub, "size_show_fractions");
941 const bool c_size_show_mb = cs_subset_bool(NeoMutt->sub, "size_show_mb");
942 const bool c_size_units_on_left = cs_subset_bool(NeoMutt->sub, "size_units_on_left");
943
944 if (c_size_show_bytes && (num < 1024))
945 {
946 return buf_add_printf(buf, "%d", (int) num);
947 }
948
949 if (num == 0)
950 {
951 return buf_addstr(buf, c_size_units_on_left ? "K0" : "0K");
952 }
953
954 if (c_size_show_fractions && (num < 10189)) /* 0.1K - 9.9K */
955 {
956 return buf_add_printf(buf, c_size_units_on_left ? "K%3.1f" : "%3.1fK",
957 (num < 103) ? 0.1 : (num / 1024.0));
958 }
959
960 if (!c_size_show_mb || (num < 1023949)) /* 10K - 999K */
961 {
962 /* 51 is magic which causes 10189/10240 to be rounded up to 10 */
963 return buf_add_printf(buf, c_size_units_on_left ? ("K%zu") : ("%zuK"), (num + 51) / 1024);
964 }
965
966 if (c_size_show_fractions && (num < 10433332)) /* 1.0M - 9.9M */
967 {
968 return buf_add_printf(buf, c_size_units_on_left ? "M%3.1f" : "%3.1fM", num / 1048576.0);
969 }
970
971 /* 10M+ -- (10433332 + 52428) / 1048576 = 10 */
972 return buf_add_printf(buf, c_size_units_on_left ? ("M%zu") : ("%zuM"),
973 (num + 52428) / 1048576);
974}
975
980void mutt_exit(int code)
981{
982 mutt_endwin();
983#ifdef USE_DEBUG_BACKTRACE
984 if (code != 0)
986#endif
987 exit(code);
988}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:765
Email Address Handling.
Email Aliases.
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition alias.c:273
void show_backtrace(void)
Log the program's call stack.
Definition backtrace.c:40
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition complete.c:152
Select a Mailbox from a list.
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition buffer.c:182
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:668
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition buffer.c:601
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition buffer.c:509
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:337
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition helpers.c:217
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
const char * cc_charset(void)
Get the cached value of $charset.
Convenience wrapper for the core headers.
MailboxType
Supported mailbox formats.
Definition mailbox.h:40
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition mailbox.h:42
@ MUTT_POP
'POP3' Mailbox type
Definition mailbox.h:51
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:48
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition mailbox.h:43
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:609
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:548
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:96
int mutt_toupper(int arg)
Wrapper for toupper(3)
Definition ctype.c:140
bool mutt_isalnum(int arg)
Wrapper for isalnum(3)
Definition ctype.c:40
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:151
Edit a string.
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:43
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
Structs that make up an email.
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
const char FilenameSafeChars[]
Set of characters <=0x7F that are safe to use in filenames.
Definition file.c:71
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition file.c:628
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition file.c:848
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition file.c:586
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
char * LastFolder
Previously selected mailbox.
Definition globals.c:39
char * CurrentFolder
Currently selected mailbox.
Definition globals.c:38
Global variables.
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:271
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
#define mutt_error(...)
Definition logging2.h:94
#define mutt_perror(...)
Definition logging2.h:95
int imap_path_canon(struct Buffer *path)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition imap.c:2557
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2543
Convenience wrapper for the gui headers.
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition lib.h:58
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition exec.c:214
Hook Commands.
IMAP network mailbox.
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition util.c:165
void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
Prettify an IMAP mailbox name.
Definition util.c:585
#define IsPrint(ch)
Definition mbyte.h:39
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MIN(a, b)
Return the minimum of two values.
Definition memory.h:40
#define MAX(a, b)
Return the maximum of two values.
Definition memory.h:38
@ TYPE_MESSAGE
Type: 'message/*'.
Definition mime.h:35
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition msgwin.c:518
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition charset.c:817
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition charset.h:66
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition filter.c:209
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
const char * mutt_path_basename(const char *path)
Find the last component for a pathname.
Definition path.c:282
char * mutt_path_dirname(const char *path)
Return a path up to, but not including, the final '/'.
Definition path.c:312
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
Match a regex against a string, with provided options.
Definition regex.c:597
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:674
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition string.c:317
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition string.c:728
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:500
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:583
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
char * mutt_str_sep(char **stringp, const char *delim)
Find first occurrence of any of delim characters in *stringp.
Definition string.c:190
Many unsorted constants and some structs.
XdgType
XDG variable types.
Definition mutt.h:65
@ XDG_CONFIG_HOME
XDG home dir: ~/.config.
Definition mutt.h:66
@ XDG_CONFIG_DIRS
XDG system dir: /etc/xdg.
Definition mutt.h:67
#define PATH_MAX
Definition mutt.h:48
SaveAttach
Options for saving attachments.
Definition mutt_attach.h:57
@ MUTT_SAVE_APPEND
Append to existing file.
Definition mutt_attach.h:59
@ MUTT_SAVE_NO_FLAGS
Overwrite existing file (the default)
Definition mutt_attach.h:58
void mutt_get_parent_path(const char *path, char *buf, size_t buflen)
Find the parent of a path (or mailbox)
Definition muttlib.c:866
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user's real name in /etc/passwd.
Definition muttlib.c:320
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition muttlib.c:980
int mutt_str_pretty_size(struct Buffer *buf, size_t num)
Display an abbreviated size, like 3.4K.
Definition muttlib.c:934
void mutt_sleep(short s)
Sleep for a while.
Definition muttlib.c:786
bool mutt_is_text_part(const struct Body *b)
Is this part of an email in plain text?
Definition muttlib.c:395
void generate_save_path(struct Buffer *dest, const struct Address *a)
Make a safe filename from an email address.
Definition muttlib.c:607
void pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:427
bool mutt_needs_mailcap(struct Body *b)
Does this type need a mailcap entry do display.
Definition muttlib.c:367
int mutt_set_xdg_path(enum XdgType type, struct Buffer *buf)
Find an XDG path or its fallback.
Definition muttlib.c:827
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:121
static const char * XdgEnvVars[]
Accepted XDG environment variables.
Definition muttlib.c:64
void buf_sanitize_filename(struct Buffer *buf, const char *path, short slash)
Replace unsafe characters in a filename.
Definition muttlib.c:912
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition muttlib.c:83
int mutt_check_overwrite(const char *attname, const char *path, struct Buffer *fname, enum SaveAttach *opt, char **directory)
Ask the user if overwriting is necessary.
Definition muttlib.c:523
void mutt_encode_path(struct Buffer *buf, const char *src)
Convert a path to 'us-ascii'.
Definition muttlib.c:802
static const char * XdgDefaults[]
XDG default locations.
Definition muttlib.c:70
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition muttlib.c:689
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition muttlib.c:644
Some miscellaneous functions.
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition mx.c:167
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition mx.c:1323
API for mailboxes.
API for encryption/signing of emails.
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:98
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:99
#define WithCrypto
Definition lib.h:124
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
QuadOption
Possible values for a quad-option.
Definition quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition question.c:354
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:326
#define TAILQ_EMPTY(head)
Definition queue.h:778
#define NONULL(x)
Definition string2.h:44
An email address.
Definition address.h:35
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
The body of an email.
Definition body.h:36
char * subtype
content-type subtype
Definition body.h:61
unsigned int type
content-type primary type, ContentType
Definition body.h:40
String manipulation buffer.
Definition buffer.h:36
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
The envelope/body of an email.
Definition email.h:39
struct Envelope * env
Envelope information.
Definition email.h:68
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
struct AddressList from
Email's 'From' list.
Definition envelope.h:59
Input for the file completion function.
Definition curs_lib.h:39
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:58
char * home_dir
User's home directory.
Definition neomutt.h:56
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Cached regular expression.
Definition regex3.h:85
#define buf_mktemp(buf)
Definition tmp.h:33
#define buf_mktemp_pfx_sfx(buf, prefix, suffix)
Definition tmp.h:34
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition url.c:226
UrlScheme
All recognised Url types.
Definition url.h:34
@ U_NOTMUCH
Url is notmuch://.
Definition url.h:46
@ U_UNKNOWN
Url wasn't recognised.
Definition url.h:35
@ U_FILE
Url is file://.
Definition url.h:36
@ U_IMAP
Url is imap://.
Definition url.h:39
@ U_IMAPS
Url is imaps://.
Definition url.h:40