NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
muttlib.h File Reference

Some miscellaneous functions. More...

#include <stdbool.h>
#include <stdio.h>
#include <sys/types.h>
#include "attach/lib.h"
+ Include dependency graph for muttlib.h:

Go to the source code of this file.

Functions

void mutt_adv_mktemp (struct Buffer *buf)
 Create a temporary file.
 
void buf_expand_path (struct Buffer *buf)
 Create the canonical path.
 
void buf_expand_path_regex (struct Buffer *buf, bool regex)
 Create the canonical path (with regex char escaping)
 
void buf_pretty_mailbox (struct Buffer *s)
 Shorten a mailbox path using '~' or '='.
 
void buf_sanitize_filename (struct Buffer *buf, const char *path, short slash)
 Replace unsafe characters in a filename.
 
void buf_save_path (struct Buffer *dest, const struct Address *a)
 Make a safe filename from an email address.
 
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.
 
void mutt_encode_path (struct Buffer *buf, const char *src)
 Convert a path to 'us-ascii'.
 
char * mutt_gecos_name (char *dest, size_t destlen, struct passwd *pw)
 Lookup a user's real name in /etc/passwd.
 
void mutt_get_parent_path (const char *path, char *buf, size_t buflen)
 Find the parent of a path (or mailbox)
 
bool mutt_is_text_part (const struct Body *b)
 Is this part of an email in plain text?
 
bool mutt_needs_mailcap (struct Body *b)
 Does this type need a mailcap entry do display.
 
FILE * mutt_open_read (const char *path, pid_t *thepid)
 Run a command to read from.
 
void mutt_pretty_mailbox (char *buf, size_t buflen)
 Shorten a mailbox path using '~' or '='.
 
void mutt_safe_path (struct Buffer *dest, const struct Address *a)
 Make a safe filename from an email address.
 
int mutt_save_confirm (const char *s, struct stat *st)
 Ask the user to save.
 
void mutt_save_path (char *d, size_t dsize, const struct Address *a)
 Turn an email address into a filename (for saving)
 
void mutt_sleep (short s)
 Sleep for a while.
 
int mutt_str_pretty_size (struct Buffer *buf, size_t num)
 Display an abbreviated size, like 3.4K.
 
void add_to_stailq (struct ListHead *head, const char *str)
 Add a string to a list.
 
void remove_from_stailq (struct ListHead *head, const char *str)
 Remove an item, matching a string, from a List.
 

Detailed Description

Some miscellaneous functions.

Authors
  • Richard Russon
  • Pietro Cerutti

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

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

Definition in file muttlib.h.

Function Documentation

◆ mutt_adv_mktemp()

void mutt_adv_mktemp ( struct Buffer * buf)

Create a temporary file.

Parameters
bufBuffer for the name

Accept a "suggestion" for file name. If that file exists, then construct one with unique name but keep any extension. This might fail, I guess.

Definition at line 83 of file muttlib.c.

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}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition file.c:589
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
#define NONULL(x)
Definition string2.h:43
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
Container for Accounts, Notifications.
Definition neomutt.h:43
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:47
#define buf_mktemp(buf)
Definition tmp.h:33
#define buf_mktemp_pfx_sfx(buf, prefix, suffix)
Definition tmp.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buf_expand_path()

void buf_expand_path ( struct Buffer * buf)

Create the canonical path.

Parameters
bufBuffer with path
Note
The path is expanded in-place

Definition at line 314 of file muttlib.c.

315{
316 buf_expand_path_regex(buf, false);
317}
void buf_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition muttlib.c:121
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buf_expand_path_regex()

void buf_expand_path_regex ( struct Buffer * buf,
bool regex )

Create the canonical path (with regex char escaping)

Parameters
bufBuffer with path
regexIf true, escape any regex characters
Note
The path is expanded in-place

Definition at line 121 of file muttlib.c.

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}
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
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition alias.c:276
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition buffer.c:601
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
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
MailboxType
Supported mailbox formats.
Definition mailbox.h:41
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:51
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:50
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
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition file.c:631
char * LastFolder
Previously selected mailbox.
Definition globals.c:40
char * CurrentFolder
Currently selected mailbox.
Definition globals.c:39
int imap_path_canon(struct Buffer *path)
Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
Definition imap.c:2363
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2349
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition hook.c:777
#define PATH_MAX
Definition mutt.h:42
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition mx.c:1326
#define TAILQ_EMPTY(head)
Definition queue.h:778
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
char * home_dir
User's home directory.
Definition neomutt.h:53
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buf_pretty_mailbox()

void buf_pretty_mailbox ( struct Buffer * buf)

Shorten a mailbox path using '~' or '='.

Parameters
bufBuffer containing Mailbox name

Definition at line 518 of file muttlib.c.

519{
520 if (!buf || !buf->data)
521 return;
522 /* This reduces the size of the Buffer, so we can pass it through.
523 * We adjust the size just to make sure buf->data is not NULL though */
524 buf_alloc(buf, PATH_MAX);
525 mutt_pretty_mailbox(buf->data, buf->dsize);
526 buf_fix_dptr(buf);
527}
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition buffer.c:182
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:439
size_t dsize
Length of data.
Definition buffer.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buf_sanitize_filename()

void buf_sanitize_filename ( struct Buffer * buf,
const char * path,
short slash )

Replace unsafe characters in a filename.

Parameters
bufBuffer for the result
pathFilename to make safe
slashReplace '/' characters too

Definition at line 967 of file muttlib.c.

968{
969 if (!buf || !path)
970 return;
971
972 buf_reset(buf);
973
974 for (; *path; path++)
975 {
976 if ((slash && (*path == '/')) || !strchr(FilenameSafeChars, *path))
977 buf_addch(buf, '_');
978 else
979 buf_addch(buf, *path);
980 }
981}
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
const char FilenameSafeChars[]
Set of characters <=0x7F that are safe to use in filenames.
Definition file.c:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buf_save_path()

void buf_save_path ( struct Buffer * dest,
const struct Address * a )

Make a safe filename from an email address.

Parameters
destBuffer for the result
aAddress to use

Definition at line 651 of file muttlib.c.

652{
653 if (a && a->mailbox)
654 {
655 buf_copy(dest, a->mailbox);
656 const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
657 if (!c_save_address)
658 {
659 char *p = strpbrk(dest->data, "%@");
660 if (p)
661 {
662 *p = '\0';
663 buf_fix_dptr(dest);
664 }
665 }
666 mutt_str_lower(dest->data);
667 }
668 else
669 {
670 buf_reset(dest);
671 }
672}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition string.c:315
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_check_overwrite()

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.

Parameters
[in]attnameAttachment name
[in]pathPath to save the file
[out]fnameBuffer for filename
[out]optSave option, see SaveAttach
[out]directoryDirectory to save under (OPTIONAL)
Return values
0Success
-1Abort
1Error

Definition at line 540 of file muttlib.c.

542{
543 struct stat st = { 0 };
544
545 buf_strcpy(fname, path);
546 if (access(buf_string(fname), F_OK) != 0)
547 return 0;
548 if (stat(buf_string(fname), &st) != 0)
549 return -1;
550 if (S_ISDIR(st.st_mode))
551 {
552 enum QuadOption ans = MUTT_NO;
553 if (directory)
554 {
555 switch (mw_multi_choice
556 /* L10N: Means "The path you specified as the destination file is a directory."
557 See the msgid "Save to file: " (alias.c, recvattach.c)
558 These three letters correspond to the choices in the string. */
559 (_("File is a directory, save under it: (y)es, (n)o, (a)ll?"), _("yna")))
560 {
561 case 3: /* all */
562 mutt_str_replace(directory, buf_string(fname));
563 break;
564 case 1: /* yes */
565 FREE(directory);
566 break;
567 case -1: /* abort */
568 FREE(directory);
569 return -1;
570 case 2: /* no */
571 FREE(directory);
572 return 1;
573 }
574 }
575 /* L10N: Means "The path you specified as the destination file is a directory."
576 See the msgid "Save to file: " (alias.c, recvattach.c) */
577 else if ((ans = query_yesorno(_("File is a directory, save under it?"), MUTT_YES)) != MUTT_YES)
578 return (ans == MUTT_NO) ? 1 : -1;
579
580 struct Buffer *tmp = buf_pool_get();
581 buf_strcpy(tmp, mutt_path_basename(NONULL(attname)));
582 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
583 if ((mw_get_field(_("File under directory: "), tmp, MUTT_COMP_CLEAR,
584 HC_FILE, &CompleteFileOps, &cdata) != 0) ||
585 buf_is_empty(tmp))
586 {
587 buf_pool_release(&tmp);
588 return (-1);
589 }
590 buf_concat_path(fname, path, buf_string(tmp));
591 buf_pool_release(&tmp);
592 }
593
594 if ((*opt == MUTT_SAVE_NO_FLAGS) && (access(buf_string(fname), F_OK) == 0))
595 {
596 char buf[4096] = { 0 };
597 snprintf(buf, sizeof(buf), "%s - %s", buf_string(fname),
598 // L10N: Options for: File %s exists, (o)verwrite, (a)ppend, or (c)ancel?
599 _("File exists, (o)verwrite, (a)ppend, or (c)ancel?"));
600 switch (mw_multi_choice(buf, _("oac")))
601 {
602 case -1: /* abort */
603 return -1;
604 case 3: /* cancel */
605 return 1;
606
607 case 2: /* append */
608 *opt = MUTT_SAVE_APPEND;
609 break;
610 case 1: /* overwrite */
611 break;
612 }
613 }
614 return 0;
615}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition complete.c:152
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
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:272
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:61
@ HC_FILE
Files.
Definition lib.h:57
#define FREE(x)
Definition memory.h:62
#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_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:282
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition mutt.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
QuadOption
Possible values for a quad-option.
Definition quad.h:36
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:325
Input for the file completion function.
Definition curs_lib.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_encode_path()

void mutt_encode_path ( struct Buffer * buf,
const char * src )

Convert a path to 'us-ascii'.

Parameters
bufBuffer for the result
srcPath to convert (OPTIONAL)

If src is NULL, the path in buf will be converted in-place.

Definition at line 857 of file muttlib.c.

858{
859 char *p = mutt_str_dup(src);
860 int rc = mutt_ch_convert_string(&p, cc_charset(), "us-ascii", MUTT_ICONV_NO_FLAGS);
861 size_t len = buf_strcpy(buf, (rc == 0) ? NONULL(p) : NONULL(src));
862
863 /* convert the path to POSIX "Portable Filename Character Set" */
864 for (size_t i = 0; i < len; i++)
865 {
866 if (!mutt_isalnum(buf_at(buf, i)) && !strchr("/.-_", buf_at(buf, i)))
867 {
868 buf->data[i] = '_';
869 }
870 }
871 FREE(&p);
872}
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:668
const char * cc_charset(void)
Get the cached value of $charset.
bool mutt_isalnum(int arg)
Wrapper for isalnum(3)
Definition ctype.c:39
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition charset.c:831
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition charset.h:64
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:255
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_gecos_name()

char * mutt_gecos_name ( char * dest,
size_t destlen,
struct passwd * pw )

Lookup a user's real name in /etc/passwd.

Parameters
destBuffer for the result
destlenLength of buffer
pwPasswd entry
Return values
ptrResult buffer on success

Extract the real name from /etc/passwd's GECOS field. When set, honor the regular expression in $gecos_mask, otherwise assume that the GECOS field is a comma-separated list. Replace "&" by a capitalized version of the user's login name.

Definition at line 331 of file muttlib.c.

332{
333 regmatch_t pat_match[1] = { 0 };
334 char *p = NULL;
335
336 if (!pw || !pw->pw_gecos)
337 return NULL;
338
339 memset(dest, 0, destlen);
340
341 const struct Regex *c_gecos_mask = cs_subset_regex(NeoMutt->sub, "gecos_mask");
342 if (mutt_regex_capture(c_gecos_mask, pw->pw_gecos, 1, pat_match))
343 {
344 mutt_str_copy(dest, pw->pw_gecos + pat_match[0].rm_so,
345 MIN(pat_match[0].rm_eo - pat_match[0].rm_so + 1, destlen));
346 }
347 else if ((p = strchr(pw->pw_gecos, ',')))
348 {
349 mutt_str_copy(dest, pw->pw_gecos, MIN(destlen, p - pw->pw_gecos + 1));
350 }
351 else
352 {
353 mutt_str_copy(dest, pw->pw_gecos, destlen);
354 }
355
356 size_t pwnl = strlen(pw->pw_name);
357
358 for (int idx = 0; dest[idx]; idx++)
359 {
360 if (dest[idx] == '&')
361 {
362 memmove(&dest[idx + pwnl], &dest[idx + 1],
363 MAX((ssize_t) (destlen - idx - pwnl - 1), 0));
364 memcpy(&dest[idx], pw->pw_name, MIN(destlen - idx - 1, pwnl));
365 dest[idx] = mutt_toupper(dest[idx]);
366 }
367 }
368
369 return dest;
370}
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition helpers.c:217
int mutt_toupper(int arg)
Wrapper for toupper(3)
Definition ctype.c:139
#define MIN(a, b)
Definition memory.h:37
#define MAX(a, b)
Definition memory.h:36
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:596
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:581
Cached regular expression.
Definition regex3.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_get_parent_path()

void mutt_get_parent_path ( const char * path,
char * buf,
size_t buflen )

Find the parent of a path (or mailbox)

Parameters
pathPath to use
bufBuffer for the result
buflenLength of buffer

Definition at line 921 of file muttlib.c.

922{
923 enum MailboxType mb_type = mx_path_probe(path);
924
925 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
926 if (mb_type == MUTT_IMAP)
927 {
928 imap_get_parent_path(path, buf, buflen);
929 }
930 else if (mb_type == MUTT_NOTMUCH)
931 {
932 mutt_str_copy(buf, c_folder, buflen);
933 }
934 else
935 {
936 mutt_str_copy(buf, path, buflen);
937 int n = mutt_str_len(buf);
938 if (n == 0)
939 return;
940
941 /* remove any final trailing '/' */
942 if (buf[n - 1] == '/')
943 buf[n - 1] = '\0';
944
945 /* Remove everything until the next slash */
946 for (n--; ((n >= 0) && (buf[n] != '/')); n--)
947 ; // do nothing
948
949 if (n > 0)
950 {
951 buf[n] = '\0';
952 }
953 else
954 {
955 buf[0] = '/';
956 buf[1] = '\0';
957 }
958 }
959}
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition util.c:163
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:498
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_text_part()

bool mutt_is_text_part ( const struct Body * b)

Is this part of an email in plain text?

Parameters
bPart of an email
Return values
truePart is in plain text

Definition at line 406 of file muttlib.c.

407{
408 int t = b->type;
409 char *s = b->subtype;
410
412 return false;
413
414 if (t == TYPE_TEXT)
415 return true;
416
417 if (t == TYPE_MESSAGE)
418 {
419 if (mutt_istr_equal("delivery-status", s))
420 return true;
421 }
422
423 if (((WithCrypto & APPLICATION_PGP) != 0) && (t == TYPE_APPLICATION))
424 {
425 if (mutt_istr_equal("pgp-keys", s))
426 return true;
427 }
428
429 return false;
430}
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:548
@ TYPE_MESSAGE
Type: 'message/*'.
Definition mime.h:35
@ TYPE_APPLICATION
Type: 'application/*'.
Definition mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:672
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:96
#define WithCrypto
Definition lib.h:122
char * subtype
content-type subtype
Definition body.h:61
unsigned int type
content-type primary type, ContentType
Definition body.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_needs_mailcap()

bool mutt_needs_mailcap ( struct Body * b)

Does this type need a mailcap entry do display.

Parameters
bAttachment body to be displayed
Return values
trueNeoMutt requires a mailcap entry to display
falseotherwise

Definition at line 378 of file muttlib.c.

379{
380 switch (b->type)
381 {
382 case TYPE_TEXT:
383 if (mutt_istr_equal("plain", b->subtype))
384 return false;
385 break;
386 case TYPE_APPLICATION:
388 return false;
390 return false;
391 break;
392
393 case TYPE_MULTIPART:
394 case TYPE_MESSAGE:
395 return false;
396 }
397
398 return true;
399}
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:609
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:97
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_open_read()

FILE * mutt_open_read ( const char * path,
pid_t * thepid )

Run a command to read from.

Parameters
[in]pathPath to command
[out]thepidPID of the command
Return values
ptrFile containing output of command

This function allows the user to specify a command to read stdout from in place of a normal file. If the last character in the string is a pipe (|), then we assume it is a command to run instead of a normal file.

Definition at line 699 of file muttlib.c.

700{
701 FILE *fp = NULL;
702 struct stat st = { 0 };
703
704 size_t len = mutt_str_len(path);
705 if (len == 0)
706 {
707 return NULL;
708 }
709
710 if (path[len - 1] == '|')
711 {
712 /* read from a pipe */
713
714 char *p = mutt_str_dup(path);
715
716 p[len - 1] = 0;
717 mutt_endwin();
718 *thepid = filter_create(p, NULL, &fp, NULL, NeoMutt->env);
719 FREE(&p);
720 }
721 else
722 {
723 if (stat(path, &st) < 0)
724 return NULL;
725 if (S_ISDIR(st.st_mode))
726 {
727 errno = EINVAL;
728 return NULL;
729 }
730 fp = mutt_file_fopen(path, "r");
731 *thepid = -1;
732 }
733 return fp;
734}
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:152
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
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
char ** env
Private copy of the environment variables.
Definition neomutt.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pretty_mailbox()

void mutt_pretty_mailbox ( char * buf,
size_t buflen )

Shorten a mailbox path using '~' or '='.

Parameters
bufBuffer containing string to shorten
buflenLength of buffer

Collapse the pathname using ~ or = when possible

Definition at line 439 of file muttlib.c.

440{
441 if (!buf)
442 return;
443
444 char *p = buf, *q = buf;
445 size_t len;
446 enum UrlScheme scheme;
447 char tmp[PATH_MAX] = { 0 };
448
449 scheme = url_check_scheme(buf);
450
451 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
452 if ((scheme == U_IMAP) || (scheme == U_IMAPS))
453 {
454 imap_pretty_mailbox(buf, buflen, c_folder);
455 return;
456 }
457
458 if (scheme == U_NOTMUCH)
459 return;
460
461 /* if buf is an url, only collapse path component */
462 if (scheme != U_UNKNOWN)
463 {
464 p = strchr(buf, ':') + 1;
465 if (mutt_strn_equal(p, "//", 2))
466 q = strchr(p + 2, '/');
467 if (!q)
468 q = strchr(p, '\0');
469 p = q;
470 }
471
472 /* cleanup path */
473 if (strstr(p, "//") || strstr(p, "/./"))
474 {
475 /* first attempt to collapse the pathname, this is more
476 * lightweight than realpath() and doesn't resolve links */
477 while (*p)
478 {
479 if ((p[0] == '/') && (p[1] == '/'))
480 {
481 *q++ = '/';
482 p += 2;
483 }
484 else if ((p[0] == '/') && (p[1] == '.') && (p[2] == '/'))
485 {
486 *q++ = '/';
487 p += 3;
488 }
489 else
490 {
491 *q++ = *p++;
492 }
493 }
494 *q = '\0';
495 }
496 else if (strstr(p, "..") && ((scheme == U_UNKNOWN) || (scheme == U_FILE)) &&
497 realpath(p, tmp))
498 {
499 mutt_str_copy(p, tmp, buflen - (p - buf));
500 }
501
502 if ((len = mutt_str_startswith(buf, c_folder)) && (buf[len] == '/'))
503 {
504 *buf++ = '=';
505 memmove(buf, buf + len, mutt_str_len(buf + len) + 1);
506 }
507 else if ((len = mutt_str_startswith(buf, NeoMutt->home_dir)) && (buf[len] == '/'))
508 {
509 *buf++ = '~';
510 memmove(buf, buf + len - 1, mutt_str_len(buf + len - 1) + 1);
511 }
512}
void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
Prettify an IMAP mailbox name.
Definition util.c:583
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:427
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:232
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition url.c:225
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
+ Here is the caller graph for this function:

◆ mutt_safe_path()

void mutt_safe_path ( struct Buffer * dest,
const struct Address * a )

Make a safe filename from an email address.

Parameters
destBuffer for the result
aAddress to use

The filename will be stripped of '/', space, etc to make it safe.

Definition at line 681 of file muttlib.c.

682{
683 buf_save_path(dest, a);
684 for (char *p = dest->data; *p; p++)
685 if ((*p == '/') || mutt_isspace(*p) || !IsPrint((unsigned char) *p))
686 *p = '_';
687}
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:95
#define IsPrint(ch)
Definition mbyte.h:40
void buf_save_path(struct Buffer *dest, const struct Address *a)
Make a safe filename from an email address.
Definition muttlib.c:651
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_confirm()

int mutt_save_confirm ( const char * s,
struct stat * st )

Ask the user to save.

Parameters
sSave location
stTimestamp
Return values
0OK to proceed
-1to abort
1to retry

Definition at line 744 of file muttlib.c.

745{
746 int rc = 0;
747
748 enum MailboxType type = mx_path_probe(s);
749
750 if (type == MUTT_POP)
751 {
752 mutt_error(_("Can't save message to POP mailbox"));
753 return 1;
754 }
755
756 if ((type != MUTT_MAILBOX_ERROR) && (type != MUTT_UNKNOWN) && (mx_access(s, W_OK) == 0))
757 {
758 const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
759 if (c_confirm_append)
760 {
761 struct Buffer *tmp = buf_pool_get();
762 buf_printf(tmp, _("Append messages to %s?"), s);
764 NeoMutt->sub, "confirm_append");
765 if (ans == MUTT_NO)
766 rc = 1;
767 else if (ans == MUTT_ABORT)
768 rc = -1;
769 buf_pool_release(&tmp);
770 }
771 }
772
773 if (type == MUTT_NNTP)
774 {
775 mutt_error(_("Can't save message to news server"));
776 return 0;
777 }
778
779 if (stat(s, st) != -1)
780 {
781 if (type == MUTT_MAILBOX_ERROR)
782 {
783 mutt_error(_("%s is not a mailbox"), s);
784 return 1;
785 }
786 }
787 else if (type != MUTT_IMAP)
788 {
789 st->st_mtime = 0;
790 st->st_atime = 0;
791
792 /* pathname does not exist */
793 if (errno == ENOENT)
794 {
795 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
796 if (c_confirm_create)
797 {
798 struct Buffer *tmp = buf_pool_get();
799 buf_printf(tmp, _("Create %s?"), s);
801 NeoMutt->sub, "confirm_create");
802 if (ans == MUTT_NO)
803 rc = 1;
804 else if (ans == MUTT_ABORT)
805 rc = -1;
806 buf_pool_release(&tmp);
807 }
808
809 /* user confirmed with MUTT_YES or set `$confirm_create` */
810 if (rc == 0)
811 {
812 /* create dir recursively */
813 char *tmp_path = mutt_path_dirname(s);
814 if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1)
815 {
816 /* report failure & abort */
817 mutt_perror("%s", s);
818 FREE(&tmp_path);
819 return 1;
820 }
821 FREE(&tmp_path);
822 }
823 }
824 else
825 {
826 mutt_perror("%s", s);
827 return 1;
828 }
829 }
830
831 msgwin_clear_text(NULL);
832 return rc;
833}
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition mailbox.h:43
@ MUTT_POP
'POP3' Mailbox type
Definition mailbox.h:52
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:49
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition mailbox.h:44
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition file.c:851
#define mutt_error(...)
Definition logging2.h:93
#define mutt_perror(...)
Definition logging2.h:94
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition msgwin.c:518
char * mutt_path_dirname(const char *path)
Return a path up to, but not including, the final '/'.
Definition path.c:312
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition mx.c:170
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition quad.h:37
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:353
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_path()

void mutt_save_path ( char * buf,
size_t buflen,
const struct Address * addr )

Turn an email address into a filename (for saving)

Parameters
bufBuffer for the result
buflenLength of buffer
addrEmail address to use

If the user hasn't set $save_address the name will be truncated to the '@' character.

Definition at line 626 of file muttlib.c.

627{
628 if (addr && addr->mailbox)
629 {
630 mutt_str_copy(buf, buf_string(addr->mailbox), buflen);
631 const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
632 if (!c_save_address)
633 {
634 char *p = strpbrk(buf, "%@");
635 if (p)
636 *p = '\0';
637 }
638 mutt_str_lower(buf);
639 }
640 else
641 {
642 *buf = '\0';
643 }
644}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sleep()

void mutt_sleep ( short s)

Sleep for a while.

Parameters
sNumber of seconds to sleep

If the user config '$sleep_time' is larger, sleep that long instead.

Definition at line 841 of file muttlib.c.

842{
843 const short c_sleep_time = cs_subset_number(NeoMutt->sub, "sleep_time");
844 if (c_sleep_time > s)
845 sleep(c_sleep_time);
846 else if (s)
847 sleep(s);
848}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_str_pretty_size()

int mutt_str_pretty_size ( struct Buffer * buf,
size_t num )

Display an abbreviated size, like 3.4K.

Parameters
[out]bufBuffer for the result
[in]numNumber to abbreviate
Return values
numBytes written to buf

Definition at line 989 of file muttlib.c.

990{
991 if (!buf)
992 return 0;
993
994 const bool c_size_show_bytes = cs_subset_bool(NeoMutt->sub, "size_show_bytes");
995 const bool c_size_show_fractions = cs_subset_bool(NeoMutt->sub, "size_show_fractions");
996 const bool c_size_show_mb = cs_subset_bool(NeoMutt->sub, "size_show_mb");
997 const bool c_size_units_on_left = cs_subset_bool(NeoMutt->sub, "size_units_on_left");
998
999 if (c_size_show_bytes && (num < 1024))
1000 {
1001 return buf_add_printf(buf, "%d", (int) num);
1002 }
1003
1004 if (num == 0)
1005 {
1006 return buf_addstr(buf, c_size_units_on_left ? "K0" : "0K");
1007 }
1008
1009 if (c_size_show_fractions && (num < 10189)) /* 0.1K - 9.9K */
1010 {
1011 return buf_add_printf(buf, c_size_units_on_left ? "K%3.1f" : "%3.1fK",
1012 (num < 103) ? 0.1 : (num / 1024.0));
1013 }
1014
1015 if (!c_size_show_mb || (num < 1023949)) /* 10K - 999K */
1016 {
1017 /* 51 is magic which causes 10189/10240 to be rounded up to 10 */
1018 return buf_add_printf(buf, c_size_units_on_left ? ("K%zu") : ("%zuK"), (num + 51) / 1024);
1019 }
1020
1021 if (c_size_show_fractions && (num < 10433332)) /* 1.0M - 9.9M */
1022 {
1023 return buf_add_printf(buf, c_size_units_on_left ? "M%3.1f" : "%3.1fM", num / 1048576.0);
1024 }
1025
1026 /* 10M+ -- (10433332 + 52428) / 1048576 = 10 */
1027 return buf_add_printf(buf, c_size_units_on_left ? ("M%zu") : ("%zuM"),
1028 (num + 52428) / 1048576);
1029}
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_to_stailq()

void add_to_stailq ( struct ListHead * head,
const char * str )

Add a string to a list.

Parameters
headString list
strString to add
Note
Duplicate or empty strings will not be added

Definition at line 1038 of file muttlib.c.

1039{
1040 /* don't add a NULL or empty string to the list */
1041 if (!str || (*str == '\0'))
1042 return;
1043
1044 /* check to make sure the item is not already on this list */
1045 struct ListNode *np = NULL;
1046 STAILQ_FOREACH(np, head, entries)
1047 {
1048 if (mutt_istr_equal(str, np->data))
1049 {
1050 return;
1051 }
1052 }
1054}
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition list.c:65
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ remove_from_stailq()

void remove_from_stailq ( struct ListHead * head,
const char * str )

Remove an item, matching a string, from a List.

Parameters
headHead of the List
strString to match
Note
The string comparison is case-insensitive

Definition at line 1063 of file muttlib.c.

1064{
1065 if (mutt_str_equal("*", str))
1066 {
1067 mutt_list_free(head); /* "unCMD *" means delete all current entries */
1068 }
1069 else
1070 {
1071 struct ListNode *np = NULL, *tmp = NULL;
1072 STAILQ_FOREACH_SAFE(np, head, entries, tmp)
1073 {
1074 if (mutt_istr_equal(str, np->data))
1075 {
1076 STAILQ_REMOVE(head, np, ListNode, entries);
1077 FREE(&np->data);
1078 FREE(&np);
1079 break;
1080 }
1081 }
1082 }
1083}
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:660
#define STAILQ_REMOVE(head, elm, type, field)
Definition queue.h:441
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition queue.h:400
+ Here is the call graph for this function:
+ Here is the caller graph for this function: