NeoMutt  2024-04-25-89-g194907
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
muttlib.h File Reference

Some miscellaneous functions. More...

#include <signal.h>
#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)
 
int mutt_inbox_cmp (const char *a, const char *b)
 Do two folders share the same path and one is an inbox -.
 
bool mutt_is_text_part (const struct Body *b)
 Is this part of an email in plain text?
 
const char * mutt_make_version (void)
 Generate the NeoMutt version string.
 
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.
 
void mutt_str_pretty_size (char *buf, size_t buflen, 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 84 of file muttlib.c.

85{
86 if (!(buf->data && (buf->data[0] != '\0')))
87 {
88 buf_mktemp(buf);
89 }
90 else
91 {
92 struct Buffer *prefix = buf_pool_get();
93 buf_strcpy(prefix, buf->data);
94 mutt_file_sanitize_filename(prefix->data, true);
95 const char *const c_tmp_dir = cs_subset_path(NeoMutt->sub, "tmp_dir");
96 buf_printf(buf, "%s/%s", NONULL(c_tmp_dir), buf_string(prefix));
97
98 struct stat st = { 0 };
99 if ((lstat(buf_string(buf), &st) == -1) && (errno == ENOENT))
100 goto out;
101
102 char *suffix = strchr(prefix->data, '.');
103 if (suffix)
104 {
105 *suffix = '\0';
106 suffix++;
107 }
108 buf_mktemp_pfx_sfx(buf, prefix->data, suffix);
109
110 out:
111 buf_pool_release(&prefix);
112 }
113}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
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:712
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
#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 315 of file muttlib.c.

316{
317 buf_expand_path_regex(buf, false);
318}
void buf_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:122
+ 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 122 of file muttlib.c.

123{
124 const char *s = NULL;
125 const char *tail = "";
126
127 bool recurse = false;
128
129 struct Buffer *p = buf_pool_get();
130 struct Buffer *q = buf_pool_get();
131 struct Buffer *tmp = buf_pool_get();
132
133 do
134 {
135 recurse = false;
136 s = buf_string(buf);
137
138 switch (*s)
139 {
140 case '~':
141 {
142 if ((s[1] == '/') || (s[1] == '\0'))
143 {
145 tail = s + 1;
146 }
147 else
148 {
149 char *t = strchr(s + 1, '/');
150 if (t)
151 *t = '\0';
152
153 struct passwd *pw = getpwnam(s + 1);
154 if (pw)
155 {
156 buf_strcpy(p, pw->pw_dir);
157 if (t)
158 {
159 *t = '/';
160 tail = t;
161 }
162 else
163 {
164 tail = "";
165 }
166 }
167 else
168 {
169 /* user not found! */
170 if (t)
171 *t = '/';
172 buf_reset(p);
173 tail = s;
174 }
175 }
176 break;
177 }
178
179 case '=':
180 case '+':
181 {
182 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
183 enum MailboxType mb_type = mx_path_probe(c_folder);
184
185 /* if folder = {host} or imap[s]://host/: don't append slash */
186 if ((mb_type == MUTT_IMAP) && ((c_folder[strlen(c_folder) - 1] == '}') ||
187 (c_folder[strlen(c_folder) - 1] == '/')))
188 {
189 buf_strcpy(p, c_folder);
190 }
191 else if (mb_type == MUTT_NOTMUCH)
192 {
193 buf_strcpy(p, c_folder);
194 }
195 else if (c_folder && (c_folder[strlen(c_folder) - 1] == '/'))
196 {
197 buf_strcpy(p, c_folder);
198 }
199 else
200 {
201 buf_printf(p, "%s/", NONULL(c_folder));
202 }
203
204 tail = s + 1;
205 break;
206 }
207
208 /* elm compatibility, @ expands alias to user name */
209
210 case '@':
211 {
212 struct AddressList *al = alias_lookup(s + 1);
213 if (al && !TAILQ_EMPTY(al))
214 {
215 struct Email *e = email_new();
216 e->env = mutt_env_new();
217 mutt_addrlist_copy(&e->env->from, al, false);
218 mutt_addrlist_copy(&e->env->to, al, false);
219
221 mutt_default_save(p, e);
222
223 email_free(&e);
224 /* Avoid infinite recursion if the resulting folder starts with '@' */
225 if (*p->data != '@')
226 recurse = true;
227
228 tail = "";
229 }
230 break;
231 }
232
233 case '>':
234 {
235 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
236 buf_strcpy(p, c_mbox);
237 tail = s + 1;
238 break;
239 }
240
241 case '<':
242 {
243 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
244 buf_strcpy(p, c_record);
245 tail = s + 1;
246 break;
247 }
248
249 case '!':
250 {
251 if (s[1] == '!')
252 {
254 tail = s + 2;
255 }
256 else
257 {
258 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
259 buf_strcpy(p, c_spool_file);
260 tail = s + 1;
261 }
262 break;
263 }
264
265 case '-':
266 {
268 tail = s + 1;
269 break;
270 }
271
272 case '^':
273 {
275 tail = s + 1;
276 break;
277 }
278
279 default:
280 {
281 buf_reset(p);
282 tail = s;
283 }
284 }
285
286 if (regex && *(buf_string(p)) && !recurse)
287 {
289 buf_printf(tmp, "%s%s", buf_string(q), tail);
290 }
291 else
292 {
293 buf_printf(tmp, "%s%s", buf_string(p), tail);
294 }
295
296 buf_copy(buf, tmp);
297 } while (recurse);
298
301 buf_pool_release(&tmp);
302
303 /* Rewrite IMAP path in canonical form - aids in string comparisons of
304 * folders. May possibly fail, in which case buf should be the same. */
305 if (imap_path_probe(buf_string(buf), NULL) == MUTT_IMAP)
306 imap_expand_path(buf);
307}
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:277
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
char * HomeDir
User's home directory.
Definition: globals.c:38
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:80
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:46
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition: file.c:754
char * LastFolder
Previously selected mailbox.
Definition: globals.c:44
char * CurrentFolder
Currently selected mailbox.
Definition: globals.c:43
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2345
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition: hook.c:770
int imap_expand_path(struct Buffer *path)
Buffer wrapper around imap_path_canon()
Definition: imap.c:2385
#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:1321
#define TAILQ_EMPTY(head)
Definition: queue.h:721
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
+ 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 519 of file muttlib.c.

520{
521 if (!buf || !buf->data)
522 return;
523 /* This reduces the size of the Buffer, so we can pass it through.
524 * We adjust the size just to make sure buf->data is not NULL though */
525 buf_alloc(buf, PATH_MAX);
526 mutt_pretty_mailbox(buf->data, buf->dsize);
527 buf_fix_dptr(buf);
528}
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:440
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 1044 of file muttlib.c.

1045{
1046 if (!buf || !path)
1047 return;
1048
1049 buf_reset(buf);
1050
1051 for (; *path; path++)
1052 {
1053 if ((slash && (*path == '/')) || !strchr(FilenameSafeChars, *path))
1054 buf_addch(buf, '_');
1055 else
1056 buf_addch(buf, *path);
1057 }
1058}
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:71
+ 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 653 of file muttlib.c.

654{
655 if (a && a->mailbox)
656 {
657 buf_copy(dest, a->mailbox);
658 const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
659 if (!c_save_address)
660 {
661 char *p = strpbrk(dest->data, "%@");
662 if (p)
663 {
664 *p = '\0';
665 buf_fix_dptr(dest);
666 }
667 }
668 mutt_str_lower(dest->data);
669 }
670 else
671 {
672 buf_reset(dest);
673 }
674}
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:313
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
+ 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 541 of file muttlib.c.

543{
544 struct stat st = { 0 };
545
546 buf_strcpy(fname, path);
547 if (access(buf_string(fname), F_OK) != 0)
548 return 0;
549 if (stat(buf_string(fname), &st) != 0)
550 return -1;
551 if (S_ISDIR(st.st_mode))
552 {
553 enum QuadOption ans = MUTT_NO;
554 if (directory)
555 {
556 switch (mw_multi_choice
557 /* L10N: Means "The path you specified as the destination file is a directory."
558 See the msgid "Save to file: " (alias.c, recvattach.c)
559 These three letters correspond to the choices in the string. */
560 (_("File is a directory, save under it: (y)es, (n)o, (a)ll?"), _("yna")))
561 {
562 case 3: /* all */
563 mutt_str_replace(directory, buf_string(fname));
564 break;
565 case 1: /* yes */
566 FREE(directory);
567 break;
568 case -1: /* abort */
569 FREE(directory);
570 return -1;
571 case 2: /* no */
572 FREE(directory);
573 return 1;
574 }
575 }
576 /* L10N: Means "The path you specified as the destination file is a directory."
577 See the msgid "Save to file: " (alias.c, recvattach.c) */
578 else if ((ans = query_yesorno(_("File is a directory, save under it?"), MUTT_YES)) != MUTT_YES)
579 return (ans == MUTT_NO) ? 1 : -1;
580
581 struct Buffer *tmp = buf_pool_get();
582 buf_strcpy(tmp, mutt_path_basename(NONULL(attname)));
583 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
584 if ((mw_get_field(_("File under directory: "), tmp, MUTT_COMP_CLEAR,
585 HC_FILE, &CompleteFileOps, &cdata) != 0) ||
586 buf_is_empty(tmp))
587 {
588 buf_pool_release(&tmp);
589 return (-1);
590 }
591 buf_concat_path(fname, path, buf_string(tmp));
592 buf_pool_release(&tmp);
593 }
594
595 if ((*opt == MUTT_SAVE_NO_FLAGS) && (access(buf_string(fname), F_OK) == 0))
596 {
597 char buf[4096] = { 0 };
598 snprintf(buf, sizeof(buf), "%s - %s", buf_string(fname),
599 // L10N: Options for: File %s exists, (o)verwrite, (a)ppend, or (c)ancel?
600 _("File exists, (o)verwrite, (a)ppend, or (c)ancel?"));
601 switch (mw_multi_choice(buf, _("oac")))
602 {
603 case -1: /* abort */
604 return -1;
605 case 3: /* cancel */
606 return 1;
607
608 case 2: /* append */
609 *opt = MUTT_SAVE_APPEND;
610 break;
611 case 1: /* overwrite */
612 *opt = MUTT_SAVE_OVERWRITE;
613 break;
614 }
615 }
616 return 0;
617}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
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:274
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:63
@ HC_FILE
Files.
Definition: lib.h:54
#define FREE(x)
Definition: memory.h:45
#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:280
#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_OVERWRITE
Overwrite existing file.
Definition: mutt_attach.h:60
@ MUTT_SAVE_NO_FLAGS
No flags set.
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:326
Input for the file completion function.
Definition: curs_lib.h:40
+ 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 872 of file muttlib.c.

873{
874 char *p = mutt_str_dup(src);
875 int rc = mutt_ch_convert_string(&p, cc_charset(), "us-ascii", MUTT_ICONV_NO_FLAGS);
876 size_t len = buf_strcpy(buf, (rc == 0) ? NONULL(p) : NONULL(src));
877
878 /* convert the path to POSIX "Portable Filename Character Set" */
879 for (size_t i = 0; i < len; i++)
880 {
881 if (!isalnum(buf->data[i]) && !strchr("/.-_", buf->data[i]))
882 {
883 buf->data[i] = '_';
884 }
885 }
886 FREE(&p);
887}
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
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:73
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
+ 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 332 of file muttlib.c.

333{
334 regmatch_t pat_match[1] = { 0 };
335 char *p = NULL;
336
337 if (!pw || !pw->pw_gecos)
338 return NULL;
339
340 memset(dest, 0, destlen);
341
342 const struct Regex *c_gecos_mask = cs_subset_regex(NeoMutt->sub, "gecos_mask");
343 if (mutt_regex_capture(c_gecos_mask, pw->pw_gecos, 1, pat_match))
344 {
345 mutt_str_copy(dest, pw->pw_gecos + pat_match[0].rm_so,
346 MIN(pat_match[0].rm_eo - pat_match[0].rm_so + 1, destlen));
347 }
348 else if ((p = strchr(pw->pw_gecos, ',')))
349 {
350 mutt_str_copy(dest, pw->pw_gecos, MIN(destlen, p - pw->pw_gecos + 1));
351 }
352 else
353 {
354 mutt_str_copy(dest, pw->pw_gecos, destlen);
355 }
356
357 size_t pwnl = strlen(pw->pw_name);
358
359 for (int idx = 0; dest[idx]; idx++)
360 {
361 if (dest[idx] == '&')
362 {
363 memmove(&dest[idx + pwnl], &dest[idx + 1],
364 MAX((ssize_t) (destlen - idx - pwnl - 1), 0));
365 memcpy(&dest[idx], pw->pw_name, MIN(destlen - idx - 1, pwnl));
366 dest[idx] = toupper((unsigned char) dest[idx]);
367 }
368 }
369
370 return dest;
371}
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:217
#define MIN(a, b)
Definition: memory.h:32
#define MAX(a, b)
Definition: memory.h:31
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
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:85
+ 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 936 of file muttlib.c.

937{
938 enum MailboxType mb_type = mx_path_probe(path);
939
940 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
941 if (mb_type == MUTT_IMAP)
942 {
943 imap_get_parent_path(path, buf, buflen);
944 }
945 else if (mb_type == MUTT_NOTMUCH)
946 {
947 mutt_str_copy(buf, c_folder, buflen);
948 }
949 else
950 {
951 mutt_str_copy(buf, path, buflen);
952 int n = mutt_str_len(buf);
953 if (n == 0)
954 return;
955
956 /* remove any final trailing '/' */
957 if (buf[n - 1] == '/')
958 buf[n - 1] = '\0';
959
960 /* Remove everything until the next slash */
961 for (n--; ((n >= 0) && (buf[n] != '/')); n--)
962 ; // do nothing
963
964 if (n > 0)
965 {
966 buf[n] = '\0';
967 }
968 else
969 {
970 buf[0] = '/';
971 buf[1] = '\0';
972 }
973 }
974}
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:162
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
+ 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 407 of file muttlib.c.

408{
409 int t = b->type;
410 char *s = b->subtype;
411
413 return false;
414
415 if (t == TYPE_TEXT)
416 return true;
417
418 if (t == TYPE_MESSAGE)
419 {
420 if (mutt_istr_equal("delivery-status", s))
421 return true;
422 }
423
424 if (((WithCrypto & APPLICATION_PGP) != 0) && (t == TYPE_APPLICATION))
425 {
426 if (mutt_istr_equal("pgp-keys", s))
427 return true;
428 }
429
430 return false;
431}
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:90
#define WithCrypto
Definition: lib.h:116
char * subtype
content-type subtype
Definition: body.h:60
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_make_version()

const char * mutt_make_version ( void  )

Generate the NeoMutt version string.

Return values
ptrVersion string
Note
This returns a pointer to a static buffer

Definition at line 858 of file muttlib.c.

859{
860 static char vstring[256];
861 snprintf(vstring, sizeof(vstring), "NeoMutt %s%s", PACKAGE_VERSION, GitVer);
862 return vstring;
863}
const char * GitVer

◆ 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 379 of file muttlib.c.

380{
381 switch (b->type)
382 {
383 case TYPE_TEXT:
384 if (mutt_istr_equal("plain", b->subtype))
385 return false;
386 break;
387 case TYPE_APPLICATION:
389 return false;
391 return false;
392 break;
393
394 case TYPE_MULTIPART:
395 case TYPE_MESSAGE:
396 return false;
397 }
398
399 return true;
400}
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:91
+ 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 701 of file muttlib.c.

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

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

684{
685 buf_save_path(dest, a);
686 for (char *p = dest->data; *p; p++)
687 if ((*p == '/') || isspace(*p) || !IsPrint((unsigned char) *p))
688 *p = '_';
689}
#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:653
+ 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 746 of file muttlib.c.

747{
748 int rc = 0;
749
750 enum MailboxType type = mx_path_probe(s);
751
752 if (type == MUTT_POP)
753 {
754 mutt_error(_("Can't save message to POP mailbox"));
755 return 1;
756 }
757
758 if ((type != MUTT_MAILBOX_ERROR) && (type != MUTT_UNKNOWN) && (mx_access(s, W_OK) == 0))
759 {
760 const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
761 if (c_confirm_append)
762 {
763 struct Buffer *tmp = buf_pool_get();
764 buf_printf(tmp, _("Append messages to %s?"), s);
766 NeoMutt->sub, "confirm_append");
767 if (ans == MUTT_NO)
768 rc = 1;
769 else if (ans == MUTT_ABORT)
770 rc = -1;
771 buf_pool_release(&tmp);
772 }
773 }
774
775 if (type == MUTT_NNTP)
776 {
777 mutt_error(_("Can't save message to news server"));
778 return 0;
779 }
780
781 if (stat(s, st) != -1)
782 {
783 if (type == MUTT_MAILBOX_ERROR)
784 {
785 mutt_error(_("%s is not a mailbox"), s);
786 return 1;
787 }
788 }
789 else if (type != MUTT_IMAP)
790 {
791 st->st_mtime = 0;
792 st->st_atime = 0;
793
794 /* pathname does not exist */
795 if (errno == ENOENT)
796 {
797 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
798 if (c_confirm_create)
799 {
800 struct Buffer *tmp = buf_pool_get();
801 buf_printf(tmp, _("Create %s?"), s);
803 NeoMutt->sub, "confirm_create");
804 if (ans == MUTT_NO)
805 rc = 1;
806 else if (ans == MUTT_ABORT)
807 rc = -1;
808 buf_pool_release(&tmp);
809 }
810
811 /* user confirmed with MUTT_YES or set `$confirm_create` */
812 if (rc == 0)
813 {
814 /* create dir recursively */
815 char *tmp_path = mutt_path_dirname(s);
816 if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1)
817 {
818 /* report failure & abort */
819 mutt_perror("%s", s);
820 FREE(&tmp_path);
821 return 1;
822 }
823 FREE(&tmp_path);
824 }
825 }
826 else
827 {
828 mutt_perror("%s", s);
829 return 1;
830 }
831 }
832
833 msgwin_clear_text(NULL);
834 return rc;
835}
@ 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:974
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_perror(...)
Definition: logging2.h:93
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:519
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:341
+ 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 628 of file muttlib.c.

629{
630 if (addr && addr->mailbox)
631 {
632 mutt_str_copy(buf, buf_string(addr->mailbox), buflen);
633 const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
634 if (!c_save_address)
635 {
636 char *p = strpbrk(buf, "%@");
637 if (p)
638 *p = '\0';
639 }
640 mutt_str_lower(buf);
641 }
642 else
643 {
644 *buf = '\0';
645 }
646}
+ 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 843 of file muttlib.c.

844{
845 const short c_sleep_time = cs_subset_number(NeoMutt->sub, "sleep_time");
846 if (c_sleep_time > s)
847 sleep(c_sleep_time);
848 else if (s)
849 sleep(s);
850}
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()

void mutt_str_pretty_size ( char *  buf,
size_t  buflen,
size_t  num 
)

Display an abbreviated size, like 3.4K.

Parameters
bufBuffer for the result
buflenLength of the buffer
numNumber to abbreviate

Definition at line 1066 of file muttlib.c.

1067{
1068 if (!buf || (buflen == 0))
1069 return;
1070
1071 const bool c_size_show_bytes = cs_subset_bool(NeoMutt->sub, "size_show_bytes");
1072 const bool c_size_show_fractions = cs_subset_bool(NeoMutt->sub, "size_show_fractions");
1073 const bool c_size_show_mb = cs_subset_bool(NeoMutt->sub, "size_show_mb");
1074 const bool c_size_units_on_left = cs_subset_bool(NeoMutt->sub, "size_units_on_left");
1075
1076 if (c_size_show_bytes && (num < 1024))
1077 {
1078 snprintf(buf, buflen, "%d", (int) num);
1079 }
1080 else if (num == 0)
1081 {
1082 mutt_str_copy(buf, c_size_units_on_left ? "K0" : "0K", buflen);
1083 }
1084 else if (c_size_show_fractions && (num < 10189)) /* 0.1K - 9.9K */
1085 {
1086 snprintf(buf, buflen, c_size_units_on_left ? "K%3.1f" : "%3.1fK",
1087 (num < 103) ? 0.1 : (num / 1024.0));
1088 }
1089 else if (!c_size_show_mb || (num < 1023949)) /* 10K - 999K */
1090 {
1091 /* 51 is magic which causes 10189/10240 to be rounded up to 10 */
1092 snprintf(buf, buflen, c_size_units_on_left ? ("K%zu") : ("%zuK"), (num + 51) / 1024);
1093 }
1094 else if (c_size_show_fractions && (num < 10433332)) /* 1.0M - 9.9M */
1095 {
1096 snprintf(buf, buflen, c_size_units_on_left ? "M%3.1f" : "%3.1fM", num / 1048576.0);
1097 }
1098 else /* 10M+ */
1099 {
1100 /* (10433332 + 52428) / 1048576 = 10 */
1101 snprintf(buf, buflen, c_size_units_on_left ? ("M%zu") : ("%zuM"), (num + 52428) / 1048576);
1102 }
1103}
+ 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 1112 of file muttlib.c.

1113{
1114 /* don't add a NULL or empty string to the list */
1115 if (!str || (*str == '\0'))
1116 return;
1117
1118 /* check to make sure the item is not already on this list */
1119 struct ListNode *np = NULL;
1120 STAILQ_FOREACH(np, head, entries)
1121 {
1122 if (mutt_istr_equal(str, np->data))
1123 {
1124 return;
1125 }
1126 }
1128}
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:352
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 1137 of file muttlib.c.

1138{
1139 if (mutt_str_equal("*", str))
1140 {
1141 mutt_list_free(head); /* "unCMD *" means delete all current entries */
1142 }
1143 else
1144 {
1145 struct ListNode *np = NULL, *tmp = NULL;
1146 STAILQ_FOREACH_SAFE(np, head, entries, tmp)
1147 {
1148 if (mutt_istr_equal(str, np->data))
1149 {
1150 STAILQ_REMOVE(head, np, ListNode, entries);
1151 FREE(&np->data);
1152 FREE(&np);
1153 break;
1154 }
1155 }
1156 }
1157}
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:402
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
+ Here is the call graph for this function:
+ Here is the caller graph for this function: