NeoMutt  2023-05-17-56-ga67199
Teaching an old dog new tricks
DOXYGEN
muttlib.c File Reference

Some miscellaneous functions. More...

#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "muttlib.h"
#include "enter/lib.h"
#include "ncrypt/lib.h"
#include "parse/lib.h"
#include "question/lib.h"
#include "format_flags.h"
#include "globals.h"
#include "hook.h"
#include "mx.h"
#include "protos.h"
#include "imap/lib.h"
+ Include dependency graph for muttlib.c:

Go to the source code of this file.

Functions

void mutt_adv_mktemp (struct Buffer *buf)
 Create a temporary file. More...
 
char * mutt_expand_path (char *buf, size_t buflen)
 Create the canonical path. More...
 
void buf_expand_path_regex (struct Buffer *buf, bool regex)
 Create the canonical path (with regex char escaping) More...
 
void buf_expand_path (struct Buffer *buf)
 Create the canonical path. More...
 
char * mutt_expand_path_regex (char *buf, size_t buflen, bool regex)
 Create the canonical path (with regex char escaping) More...
 
char * mutt_gecos_name (char *dest, size_t destlen, struct passwd *pw)
 Lookup a user's real name in /etc/passwd. More...
 
bool mutt_needs_mailcap (struct Body *m)
 Does this type need a mailcap entry do display. More...
 
bool mutt_is_text_part (struct Body *b)
 Is this part of an email in plain text? More...
 
void mutt_pretty_mailbox (char *buf, size_t buflen)
 Shorten a mailbox path using '~' or '='. More...
 
void buf_pretty_mailbox (struct Buffer *buf)
 Shorten a mailbox path using '~' or '='. More...
 
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. More...
 
void mutt_save_path (char *buf, size_t buflen, const struct Address *addr)
 Turn an email address into a filename (for saving) More...
 
void buf_save_path (struct Buffer *dest, const struct Address *a)
 Make a safe filename from an email address. More...
 
void mutt_safe_path (struct Buffer *dest, const struct Address *a)
 Make a safe filename from an email address. More...
 
void mutt_expando_format (char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
 Expand expandos (x) in a string -. More...
 
FILE * mutt_open_read (const char *path, pid_t *thepid)
 Run a command to read from. More...
 
int mutt_save_confirm (const char *s, struct stat *st)
 Ask the user to save. More...
 
void mutt_sleep (short s)
 Sleep for a while. More...
 
const char * mutt_make_version (void)
 Generate the NeoMutt version string. More...
 
void mutt_encode_path (struct Buffer *buf, const char *src)
 Convert a path to 'us-ascii'. More...
 
int mutt_set_xdg_path (enum XdgType type, struct Buffer *buf)
 Find an XDG path or its fallback. More...
 
void mutt_get_parent_path (const char *path, char *buf, size_t buflen)
 Find the parent of a path (or mailbox) More...
 
int mutt_inbox_cmp (const char *a, const char *b)
 Do two folders share the same path and one is an inbox. More...
 
void buf_sanitize_filename (struct Buffer *buf, const char *path, short slash)
 Replace unsafe characters in a filename. More...
 
void mutt_str_pretty_size (char *buf, size_t buflen, size_t num)
 Display an abbreviated size, like 3.4K. More...
 
void add_to_stailq (struct ListHead *head, const char *str)
 Add a string to a list. More...
 
void remove_from_stailq (struct ListHead *head, const char *str)
 Remove an item, matching a string, from a List. More...
 

Variables

static const char * XdgEnvVars []
 Accepted XDG environment variables. More...
 
static const char * XdgDefaults []
 XDG default locations. More...
 

Detailed Description

Some miscellaneous functions.

Authors
  • Michael R. Elkins
  • Thomas Roessler
  • 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.c.

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

86{
87 if (!(buf->data && (buf->data[0] != '\0')))
88 {
89 buf_mktemp(buf);
90 }
91 else
92 {
93 struct Buffer *prefix = buf_pool_get();
94 buf_strcpy(prefix, buf->data);
95 mutt_file_sanitize_filename(prefix->data, true);
96 const char *const c_tmp_dir = cs_subset_path(NeoMutt->sub, "tmp_dir");
97 buf_printf(buf, "%s/%s", NONULL(c_tmp_dir), buf_string(prefix));
98
99 struct stat st = { 0 };
100 if ((lstat(buf_string(buf), &st) == -1) && (errno == ENOENT))
101 goto out;
102
103 char *suffix = strchr(prefix->data, '.');
104 if (suffix)
105 {
106 *suffix = '\0';
107 suffix++;
108 }
109 buf_mktemp_pfx_sfx(buf, prefix->data, suffix);
110
111 out:
112 buf_pool_release(&prefix);
113 }
114}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:401
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:90
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:665
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:34
char * data
Pointer to data.
Definition: buffer.h:35
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
#define buf_mktemp(buf)
Definition: tmp.h:37
#define buf_mktemp_pfx_sfx(buf, prefix, suffix)
Definition: tmp.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_expand_path()

char * mutt_expand_path ( char *  buf,
size_t  buflen 
)

Create the canonical path.

Parameters
bufBuffer with path
buflenLength of buffer
Return values
ptrThe expanded string
Note
The path is expanded in-place

Definition at line 124 of file muttlib.c.

125{
126 return mutt_expand_path_regex(buf, buflen, false);
127}
char * mutt_expand_path_regex(char *buf, size_t buflen, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:347
+ 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 136 of file muttlib.c.

137{
138 const char *s = NULL;
139 const char *tail = "";
140
141 bool recurse = false;
142
143 struct Buffer *p = buf_pool_get();
144 struct Buffer *q = buf_pool_get();
145 struct Buffer *tmp = buf_pool_get();
146
147 do
148 {
149 recurse = false;
150 s = buf_string(buf);
151
152 switch (*s)
153 {
154 case '~':
155 {
156 if ((s[1] == '/') || (s[1] == '\0'))
157 {
159 tail = s + 1;
160 }
161 else
162 {
163 char *t = strchr(s + 1, '/');
164 if (t)
165 *t = '\0';
166
167 struct passwd *pw = getpwnam(s + 1);
168 if (pw)
169 {
170 buf_strcpy(p, pw->pw_dir);
171 if (t)
172 {
173 *t = '/';
174 tail = t;
175 }
176 else
177 {
178 tail = "";
179 }
180 }
181 else
182 {
183 /* user not found! */
184 if (t)
185 *t = '/';
186 buf_reset(p);
187 tail = s;
188 }
189 }
190 break;
191 }
192
193 case '=':
194 case '+':
195 {
196 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
197 enum MailboxType mb_type = mx_path_probe(c_folder);
198
199 /* if folder = {host} or imap[s]://host/: don't append slash */
200 if ((mb_type == MUTT_IMAP) && ((c_folder[strlen(c_folder) - 1] == '}') ||
201 (c_folder[strlen(c_folder) - 1] == '/')))
202 {
203 buf_strcpy(p, NONULL(c_folder));
204 }
205 else if (mb_type == MUTT_NOTMUCH)
206 {
207 buf_strcpy(p, NONULL(c_folder));
208 }
209 else if (c_folder && (c_folder[strlen(c_folder) - 1] == '/'))
210 {
211 buf_strcpy(p, NONULL(c_folder));
212 }
213 else
214 {
215 buf_printf(p, "%s/", NONULL(c_folder));
216 }
217
218 tail = s + 1;
219 break;
220 }
221
222 /* elm compatibility, @ expands alias to user name */
223
224 case '@':
225 {
226 struct AddressList *al = alias_lookup(s + 1);
227 if (al && !TAILQ_EMPTY(al))
228 {
229 struct Email *e = email_new();
230 e->env = mutt_env_new();
231 mutt_addrlist_copy(&e->env->from, al, false);
232 mutt_addrlist_copy(&e->env->to, al, false);
233
234 /* TODO: fix mutt_default_save() to use Buffer */
236 mutt_default_save(p->data, p->dsize, e);
237 buf_fix_dptr(p);
238
239 email_free(&e);
240 /* Avoid infinite recursion if the resulting folder starts with '@' */
241 if (*p->data != '@')
242 recurse = true;
243
244 tail = "";
245 }
246 break;
247 }
248
249 case '>':
250 {
251 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
252 buf_strcpy(p, c_mbox);
253 tail = s + 1;
254 break;
255 }
256
257 case '<':
258 {
259 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
260 buf_strcpy(p, c_record);
261 tail = s + 1;
262 break;
263 }
264
265 case '!':
266 {
267 if (s[1] == '!')
268 {
270 tail = s + 2;
271 }
272 else
273 {
274 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
275 buf_strcpy(p, c_spool_file);
276 tail = s + 1;
277 }
278 break;
279 }
280
281 case '-':
282 {
284 tail = s + 1;
285 break;
286 }
287
288 case '^':
289 {
291 tail = s + 1;
292 break;
293 }
294
295 default:
296 {
297 buf_reset(p);
298 tail = s;
299 }
300 }
301
302 if (regex && *(buf_string(p)) && !recurse)
303 {
305 buf_printf(tmp, "%s%s", buf_string(q), tail);
306 }
307 else
308 {
309 buf_printf(tmp, "%s%s", buf_string(p), tail);
310 }
311
312 buf_copy(buf, tmp);
313 } while (recurse);
314
317 buf_pool_release(&tmp);
318
319#ifdef USE_IMAP
320 /* Rewrite IMAP path in canonical form - aids in string comparisons of
321 * folders. May possibly fail, in which case buf should be the same. */
322 if (imap_path_probe(buf_string(buf), NULL) == MUTT_IMAP)
323 imap_expand_path(buf);
324#endif
325}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:750
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:279
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:194
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:566
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:347
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
char * HomeDir
User's home directory.
Definition: globals.c:39
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:43
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition: file.c:684
char * LastFolder
Previously selected mailbox.
Definition: globals.c:45
char * CurrentFolder
Currently selected mailbox.
Definition: globals.c:44
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2325
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:737
int imap_expand_path(struct Buffer *buf)
Buffer wrapper around imap_path_canon()
Definition: imap.c:2365
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
#define PATH_MAX
Definition: mutt.h:41
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1348
#define TAILQ_EMPTY(head)
Definition: queue.h:721
size_t dsize
Length of data.
Definition: buffer.h:37
The envelope/body of an email.
Definition: email.h:37
struct Envelope * env
Envelope information.
Definition: email.h:66
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_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 333 of file muttlib.c.

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

◆ mutt_expand_path_regex()

char * mutt_expand_path_regex ( char *  buf,
size_t  buflen,
bool  regex 
)

Create the canonical path (with regex char escaping)

Parameters
bufBuffer with path
buflenLength of buffer
regexIf true, escape any regex characters
Return values
ptrThe expanded string
Note
The path is expanded in-place

Definition at line 347 of file muttlib.c.

348{
349 struct Buffer *tmp = buf_pool_get();
350
351 buf_addstr(tmp, NONULL(buf));
352 buf_expand_path_regex(tmp, regex);
353 mutt_str_copy(buf, buf_string(tmp), buflen);
354
355 buf_pool_release(&tmp);
356
357 return buf;
358}
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
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:653
+ 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 372 of file muttlib.c.

373{
374 regmatch_t pat_match[1];
375 size_t pwnl;
376 char *p = NULL;
377
378 if (!pw || !pw->pw_gecos)
379 return NULL;
380
381 memset(dest, 0, destlen);
382
383 const struct Regex *c_gecos_mask = cs_subset_regex(NeoMutt->sub, "gecos_mask");
384 if (mutt_regex_capture(c_gecos_mask, pw->pw_gecos, 1, pat_match))
385 {
386 mutt_str_copy(dest, pw->pw_gecos + pat_match[0].rm_so,
387 MIN(pat_match[0].rm_eo - pat_match[0].rm_so + 1, destlen));
388 }
389 else if ((p = strchr(pw->pw_gecos, ',')))
390 {
391 mutt_str_copy(dest, pw->pw_gecos, MIN(destlen, p - pw->pw_gecos + 1));
392 }
393 else
394 {
395 mutt_str_copy(dest, pw->pw_gecos, destlen);
396 }
397
398 pwnl = strlen(pw->pw_name);
399
400 for (int idx = 0; dest[idx]; idx++)
401 {
402 if (dest[idx] == '&')
403 {
404 memmove(&dest[idx + pwnl], &dest[idx + 1],
405 MAX((ssize_t) (destlen - idx - pwnl - 1), 0));
406 memcpy(&dest[idx], pw->pw_name, MIN(destlen - idx - 1, pwnl));
407 dest[idx] = toupper((unsigned char) dest[idx]);
408 }
409 }
410
411 return dest;
412}
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:243
#define MIN(a, b)
Definition: memory.h:31
#define MAX(a, b)
Definition: memory.h:30
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:618
Cached regular expression.
Definition: regex3.h:89
+ 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 m)

Does this type need a mailcap entry do display.

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

Definition at line 420 of file muttlib.c.

421{
422 switch (m->type)
423 {
424 case TYPE_TEXT:
425 if (mutt_istr_equal("plain", m->subtype))
426 return false;
427 break;
428 case TYPE_APPLICATION:
430 return false;
432 return false;
433 break;
434
435 case TYPE_MULTIPART:
436 case TYPE_MESSAGE:
437 return false;
438 }
439
440 return true;
441}
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:538
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:599
@ 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
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:810
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#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_is_text_part()

bool mutt_is_text_part ( 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 448 of file muttlib.c.

449{
450 int t = b->type;
451 char *s = b->subtype;
452
454 return false;
455
456 if (t == TYPE_TEXT)
457 return true;
458
459 if (t == TYPE_MESSAGE)
460 {
461 if (mutt_istr_equal("delivery-status", s))
462 return true;
463 }
464
465 if (((WithCrypto & APPLICATION_PGP) != 0) && (t == TYPE_APPLICATION))
466 {
467 if (mutt_istr_equal("pgp-keys", s))
468 return true;
469 }
470
471 return false;
472}
+ 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 481 of file muttlib.c.

482{
483 if (!buf)
484 return;
485
486 char *p = buf, *q = buf;
487 size_t len;
488 enum UrlScheme scheme;
489 char tmp[PATH_MAX] = { 0 };
490
491 scheme = url_check_scheme(buf);
492
493 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
494 if ((scheme == U_IMAP) || (scheme == U_IMAPS))
495 {
496 imap_pretty_mailbox(buf, buflen, c_folder);
497 return;
498 }
499
500 if (scheme == U_NOTMUCH)
501 return;
502
503 /* if buf is an url, only collapse path component */
504 if (scheme != U_UNKNOWN)
505 {
506 p = strchr(buf, ':') + 1;
507 if (mutt_strn_equal(p, "//", 2))
508 q = strchr(p + 2, '/');
509 if (!q)
510 q = strchr(p, '\0');
511 p = q;
512 }
513
514 /* cleanup path */
515 if (strstr(p, "//") || strstr(p, "/./"))
516 {
517 /* first attempt to collapse the pathname, this is more
518 * lightweight than realpath() and doesn't resolve links */
519 while (*p)
520 {
521 if ((p[0] == '/') && (p[1] == '/'))
522 {
523 *q++ = '/';
524 p += 2;
525 }
526 else if ((p[0] == '/') && (p[1] == '.') && (p[2] == '/'))
527 {
528 *q++ = '/';
529 p += 3;
530 }
531 else
532 {
533 *q++ = *p++;
534 }
535 }
536 *q = '\0';
537 }
538 else if (strstr(p, "..") && ((scheme == U_UNKNOWN) || (scheme == U_FILE)) &&
539 realpath(p, tmp))
540 {
541 mutt_str_copy(p, tmp, buflen - (p - buf));
542 }
543
544 if ((len = mutt_str_startswith(buf, c_folder)) && (buf[len] == '/'))
545 {
546 *buf++ = '=';
547 memmove(buf, buf + len, mutt_str_len(buf + len) + 1);
548 }
549 else if ((len = mutt_str_startswith(buf, HomeDir)) && (buf[len] == '/'))
550 {
551 *buf++ = '~';
552 memmove(buf, buf + len - 1, mutt_str_len(buf + len - 1) + 1);
553 }
554}
void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
Prettify an IMAP mailbox name.
Definition: util.c:580
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:497
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:228
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
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 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 560 of file muttlib.c.

561{
562 if (!buf || !buf->data)
563 return;
564 /* This reduces the size of the Buffer, so we can pass it through.
565 * We adjust the size just to make sure buf->data is not NULL though */
566 buf_alloc(buf, PATH_MAX);
567 mutt_pretty_mailbox(buf->data, buf->dsize);
568 buf_fix_dptr(buf);
569}
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:481
+ 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 582 of file muttlib.c.

584{
585 struct stat st = { 0 };
586
587 buf_strcpy(fname, path);
588 if (access(buf_string(fname), F_OK) != 0)
589 return 0;
590 if (stat(buf_string(fname), &st) != 0)
591 return -1;
592 if (S_ISDIR(st.st_mode))
593 {
594 enum QuadOption ans = MUTT_NO;
595 if (directory)
596 {
597 switch (mutt_multi_choice
598 /* L10N: Means "The path you specified as the destination file is a directory."
599 See the msgid "Save to file: " (alias.c, recvattach.c)
600 These three letters correspond to the choices in the string. */
601 (_("File is a directory, save under it: (y)es, (n)o, (a)ll?"), _("yna")))
602 {
603 case 3: /* all */
604 mutt_str_replace(directory, buf_string(fname));
605 break;
606 case 1: /* yes */
607 FREE(directory);
608 break;
609 case -1: /* abort */
610 FREE(directory);
611 return -1;
612 case 2: /* no */
613 FREE(directory);
614 return 1;
615 }
616 }
617 /* L10N: Means "The path you specified as the destination file is a directory."
618 See the msgid "Save to file: " (alias.c, recvattach.c) */
619 else if ((ans = mutt_yesorno(_("File is a directory, save under it?"), MUTT_YES)) != MUTT_YES)
620 return (ans == MUTT_NO) ? 1 : -1;
621
622 struct Buffer *tmp = buf_pool_get();
623 buf_strcpy(tmp, mutt_path_basename(NONULL(attname)));
624 if ((buf_get_field(_("File under directory: "), tmp, MUTT_COMP_FILE | MUTT_COMP_CLEAR,
625 false, NULL, NULL, NULL) != 0) ||
626 buf_is_empty(tmp))
627 {
628 buf_pool_release(&tmp);
629 return (-1);
630 }
631 buf_concat_path(fname, path, buf_string(tmp));
632 buf_pool_release(&tmp);
633 }
634
635 if ((*opt == MUTT_SAVE_NO_FLAGS) && (access(buf_string(fname), F_OK) == 0))
636 {
637 char buf[4096] = { 0 };
638 snprintf(buf, sizeof(buf), "%s - %s", buf_string(fname),
639 // L10N: Options for: File %s exists, (o)verwrite, (a)ppend, or (c)ancel?
640 _("File exists, (o)verwrite, (a)ppend, or (c)ancel?"));
641 switch (mutt_multi_choice(buf, _("oac")))
642 {
643 case -1: /* abort */
644 return -1;
645 case 3: /* cancel */
646 return 1;
647
648 case 2: /* append */
649 *opt = MUTT_SAVE_APPEND;
650 break;
651 case 1: /* overwrite */
652 *opt = MUTT_SAVE_OVERWRITE;
653 break;
654 }
655 }
656 return 0;
657}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:478
int buf_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
#define FREE(x)
Definition: memory.h:43
#define _(a)
Definition: message.h:28
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:329
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
#define MUTT_COMP_FILE
File completion (in browser)
Definition: mutt.h:58
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:65
@ 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 mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:54
+ 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 668 of file muttlib.c.

669{
670 if (addr && addr->mailbox)
671 {
672 mutt_str_copy(buf, buf_string(addr->mailbox), buflen);
673 const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
674 if (!c_save_address)
675 {
676 char *p = strpbrk(buf, "%@");
677 if (p)
678 *p = '\0';
679 }
680 mutt_str_lower(buf);
681 }
682 else
683 {
684 *buf = '\0';
685 }
686}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition: string.c:385
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:

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

694{
695 if (a && a->mailbox)
696 {
697 buf_copy(dest, a->mailbox);
698 const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
699 if (!c_save_address)
700 {
701 char *p = strpbrk(dest->data, "%@");
702 if (p)
703 {
704 *p = '\0';
705 buf_fix_dptr(dest);
706 }
707 }
708 mutt_str_lower(dest->data);
709 }
710 else
711 {
712 buf_reset(dest);
713 }
714}
+ Here is the call graph for this function:
+ 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 723 of file muttlib.c.

724{
725 buf_save_path(dest, a);
726 for (char *p = dest->data; *p; p++)
727 if ((*p == '/') || isspace(*p) || !IsPrint((unsigned char) *p))
728 *p = '_';
729}
#define IsPrint(ch)
Definition: mbyte.h:38
void buf_save_path(struct Buffer *dest, const struct Address *a)
Make a safe filename from an email address.
Definition: muttlib.c:693
+ 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 1280 of file muttlib.c.

1281{
1282 FILE *fp = NULL;
1283 struct stat st = { 0 };
1284
1285 size_t len = mutt_str_len(path);
1286 if (len == 0)
1287 {
1288 return NULL;
1289 }
1290
1291 if (path[len - 1] == '|')
1292 {
1293 /* read from a pipe */
1294
1295 char *p = mutt_str_dup(path);
1296
1297 p[len - 1] = 0;
1298 mutt_endwin();
1299 *thepid = filter_create(p, NULL, &fp, NULL);
1300 FREE(&p);
1301 }
1302 else
1303 {
1304 if (stat(path, &st) < 0)
1305 return NULL;
1306 if (S_ISDIR(st.st_mode))
1307 {
1308 errno = EINVAL;
1309 return NULL;
1310 }
1311 fp = fopen(path, "r");
1312 *thepid = -1;
1313 }
1314 return fp;
1315}
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:355
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
+ 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 1325 of file muttlib.c.

1326{
1327 int rc = 0;
1328
1329 enum MailboxType type = mx_path_probe(s);
1330
1331#ifdef USE_POP
1332 if (type == MUTT_POP)
1333 {
1334 mutt_error(_("Can't save message to POP mailbox"));
1335 return 1;
1336 }
1337#endif
1338
1339 if ((type != MUTT_MAILBOX_ERROR) && (type != MUTT_UNKNOWN) && (mx_access(s, W_OK) == 0))
1340 {
1341 const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
1342 if (c_confirm_append)
1343 {
1344 struct Buffer *tmp = buf_pool_get();
1345 buf_printf(tmp, _("Append messages to %s?"), s);
1346 enum QuadOption ans = mutt_yesorno(buf_string(tmp), MUTT_YES);
1347 if (ans == MUTT_NO)
1348 rc = 1;
1349 else if (ans == MUTT_ABORT)
1350 rc = -1;
1351 buf_pool_release(&tmp);
1352 }
1353 }
1354
1355#ifdef USE_NNTP
1356 if (type == MUTT_NNTP)
1357 {
1358 mutt_error(_("Can't save message to news server"));
1359 return 0;
1360 }
1361#endif
1362
1363 if (stat(s, st) != -1)
1364 {
1365 if (type == MUTT_MAILBOX_ERROR)
1366 {
1367 mutt_error(_("%s is not a mailbox"), s);
1368 return 1;
1369 }
1370 }
1371 else if (type != MUTT_IMAP)
1372 {
1373 st->st_mtime = 0;
1374 st->st_atime = 0;
1375
1376 /* pathname does not exist */
1377 if (errno == ENOENT)
1378 {
1379 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
1380 if (c_confirm_create)
1381 {
1382 struct Buffer *tmp = buf_pool_get();
1383 buf_printf(tmp, _("Create %s?"), s);
1384 enum QuadOption ans = mutt_yesorno(buf_string(tmp), MUTT_YES);
1385 if (ans == MUTT_NO)
1386 rc = 1;
1387 else if (ans == MUTT_ABORT)
1388 rc = -1;
1389 buf_pool_release(&tmp);
1390 }
1391
1392 /* user confirmed with MUTT_YES or set `$confirm_create` */
1393 if (rc == 0)
1394 {
1395 /* create dir recursively */
1396 char *tmp_path = mutt_path_dirname(s);
1397 if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1)
1398 {
1399 /* report failure & abort */
1400 mutt_perror(s);
1401 FREE(&tmp_path);
1402 return 1;
1403 }
1404 FREE(&tmp_path);
1405 }
1406 }
1407 else
1408 {
1409 mutt_perror(s);
1410 return 1;
1411 }
1412 }
1413
1415 return rc;
1416}
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:952
#define mutt_error(...)
Definition: logging2.h:90
#define mutt_perror(...)
Definition: logging2.h:91
@ 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
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:250
char * mutt_path_dirname(const char *path)
Return a path up to, but not including, the final '/'.
Definition: path.c:376
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition: mx.c:185
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
+ 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 1424 of file muttlib.c.

1425{
1426 const short c_sleep_time = cs_subset_number(NeoMutt->sub, "sleep_time");
1427 if (c_sleep_time > s)
1428 sleep(c_sleep_time);
1429 else if (s)
1430 sleep(s);
1431}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
+ 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 1439 of file muttlib.c.

1440{
1441 static char vstring[256];
1442 snprintf(vstring, sizeof(vstring), "NeoMutt %s%s", PACKAGE_VERSION, GitVer);
1443 return vstring;
1444}
const char * GitVer
+ 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 1453 of file muttlib.c.

1454{
1455 char *p = mutt_str_dup(src);
1456 int rc = mutt_ch_convert_string(&p, cc_charset(), "us-ascii", MUTT_ICONV_NO_FLAGS);
1457 size_t len = buf_strcpy(buf, (rc == 0) ? NONULL(p) : NONULL(src));
1458
1459 /* convert the path to POSIX "Portable Filename Character Set" */
1460 for (size_t i = 0; i < len; i++)
1461 {
1462 if (!isalnum(buf->data[i]) && !strchr("/.-_", buf->data[i]))
1463 {
1464 buf->data[i] = '_';
1465 }
1466 }
1467 FREE(&p);
1468}
const char * cc_charset(void)
Get the cached value of $charset.
Definition: cache.c:106
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:822
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_set_xdg_path()

int mutt_set_xdg_path ( enum XdgType  type,
struct Buffer buf 
)

Find an XDG path or its fallback.

Parameters
typeType of XDG variable, e.g. XDG_CONFIG_HOME
bufBuffer to save path
Return values
1An entry was found that actually exists on disk and 0 otherwise

Process an XDG environment variable or its fallback.

Definition at line 1478 of file muttlib.c.

1479{
1480 const char *xdg_env = mutt_str_getenv(XdgEnvVars[type]);
1481 char *xdg = xdg_env ? mutt_str_dup(xdg_env) : mutt_str_dup(XdgDefaults[type]);
1482 char *x = xdg; /* mutt_str_sep() changes xdg, so free x instead later */
1483 char *token = NULL;
1484 int rc = 0;
1485
1486 while ((token = mutt_str_sep(&xdg, ":")))
1487 {
1488 if (buf_printf(buf, "%s/%s/neomuttrc", token, PACKAGE) < 0)
1489 continue;
1490 buf_expand_path(buf);
1491 if (access(buf_string(buf), F_OK) == 0)
1492 {
1493 rc = 1;
1494 break;
1495 }
1496
1497 if (buf_printf(buf, "%s/%s/Muttrc", token, PACKAGE) < 0)
1498 continue;
1499 buf_expand_path(buf);
1500 if (access(buf_string(buf), F_OK) == 0)
1501 {
1502 rc = 1;
1503 break;
1504 }
1505 }
1506
1507 FREE(&x);
1508 return rc;
1509}
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:918
char * mutt_str_sep(char **stringp, const char *delim)
Find first occurrence of any of delim characters in *stringp.
Definition: string.c:184
static const char * XdgEnvVars[]
Accepted XDG environment variables.
Definition: muttlib.c:66
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:333
static const char * XdgDefaults[]
XDG default locations.
Definition: muttlib.c:72
+ 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 1517 of file muttlib.c.

1518{
1519 enum MailboxType mb_type = mx_path_probe(path);
1520
1521 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1522 if (mb_type == MUTT_IMAP)
1523 {
1524 imap_get_parent_path(path, buf, buflen);
1525 }
1526 else if (mb_type == MUTT_NOTMUCH)
1527 {
1528 mutt_str_copy(buf, c_folder, buflen);
1529 }
1530 else
1531 {
1532 mutt_str_copy(buf, path, buflen);
1533 int n = mutt_str_len(buf);
1534 if (n == 0)
1535 return;
1536
1537 /* remove any final trailing '/' */
1538 if (buf[n - 1] == '/')
1539 buf[n - 1] = '\0';
1540
1541 /* Remove everything until the next slash */
1542 for (n--; ((n >= 0) && (buf[n] != '/')); n--)
1543 ; // do nothing
1544
1545 if (n > 0)
1546 {
1547 buf[n] = '\0';
1548 }
1549 else
1550 {
1551 buf[0] = '/';
1552 buf[1] = '\0';
1553 }
1554 }
1555}
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:160
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_inbox_cmp()

int mutt_inbox_cmp ( const char *  a,
const char *  b 
)

Do two folders share the same path and one is an inbox.

Parameters
aFirst path
bSecond path
Return values
-1a is INBOX of b
0None is INBOX
1b is INBOX for a

This function compares two folder paths. It first looks for the position of the last common '/' character. If a valid position is found and it's not the last character in any of the two paths, the remaining parts of the paths are compared (case insensitively) with the string "INBOX". If one of the two paths matches, it's reported as being less than the other and the function returns -1 (a < b) or 1 (a > b). If no paths match the requirements, the two paths are considered equivalent and this function returns 0.

Examples:

  • mutt_inbox_cmp("/foo/bar", "/foo/baz") --> 0
  • mutt_inbox_cmp("/foo/bar/", "/foo/bar/inbox") --> 0
  • mutt_inbox_cmp("/foo/bar/sent", "/foo/bar/inbox") --> 1
  • mutt_inbox_cmp("=INBOX", "=Drafts") --> -1

Definition at line 1579 of file muttlib.c.

1580{
1581 /* fast-track in case the paths have been mutt_pretty_mailbox'ified */
1582 if ((a[0] == '+') && (b[0] == '+'))
1583 {
1584 return mutt_istr_equal(a + 1, "inbox") ? -1 :
1585 mutt_istr_equal(b + 1, "inbox") ? 1 :
1586 0;
1587 }
1588
1589 const char *a_end = strrchr(a, '/');
1590 const char *b_end = strrchr(b, '/');
1591
1592 /* If one path contains a '/', but not the other */
1593 if ((!a_end) ^ (!b_end))
1594 return 0;
1595
1596 /* If neither path contains a '/' */
1597 if (!a_end)
1598 return 0;
1599
1600 /* Compare the subpaths */
1601 size_t a_len = a_end - a;
1602 size_t b_len = b_end - b;
1603 size_t min = MIN(a_len, b_len);
1604 int same = (a[min] == '/') && (b[min] == '/') && (a[min + 1] != '\0') &&
1605 (b[min + 1] != '\0') && mutt_istrn_equal(a, b, min);
1606
1607 if (!same)
1608 return 0;
1609
1610 if (mutt_istr_equal(&a[min + 1], "inbox"))
1611 return -1;
1612
1613 if (mutt_istr_equal(&b[min + 1], "inbox"))
1614 return 1;
1615
1616 return 0;
1617}
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:525
+ 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 1625 of file muttlib.c.

1626{
1627 if (!buf || !path)
1628 return;
1629
1630 buf_reset(buf);
1631
1632 for (; *path; path++)
1633 {
1634 if ((slash && (*path == '/')) || !strchr(FilenameSafeChars, *path))
1635 buf_addch(buf, '_');
1636 else
1637 buf_addch(buf, *path);
1638 }
1639}
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
const char FilenameSafeChars[]
Set of characters that are safe to use in filenames.
Definition: file.c:59
+ 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 1647 of file muttlib.c.

1648{
1649 if (!buf || (buflen == 0))
1650 return;
1651
1652 const bool c_size_show_bytes = cs_subset_bool(NeoMutt->sub, "size_show_bytes");
1653 const bool c_size_show_fractions = cs_subset_bool(NeoMutt->sub, "size_show_fractions");
1654 const bool c_size_show_mb = cs_subset_bool(NeoMutt->sub, "size_show_mb");
1655 const bool c_size_units_on_left = cs_subset_bool(NeoMutt->sub, "size_units_on_left");
1656
1657 if (c_size_show_bytes && (num < 1024))
1658 {
1659 snprintf(buf, buflen, "%d", (int) num);
1660 }
1661 else if (num == 0)
1662 {
1663 mutt_str_copy(buf, c_size_units_on_left ? "K0" : "0K", buflen);
1664 }
1665 else if (c_size_show_fractions && (num < 10189)) /* 0.1K - 9.9K */
1666 {
1667 snprintf(buf, buflen, c_size_units_on_left ? "K%3.1f" : "%3.1fK",
1668 (num < 103) ? 0.1 : (num / 1024.0));
1669 }
1670 else if (!c_size_show_mb || (num < 1023949)) /* 10K - 999K */
1671 {
1672 /* 51 is magic which causes 10189/10240 to be rounded up to 10 */
1673 snprintf(buf, buflen, c_size_units_on_left ? ("K%zu") : ("%zuK"), (num + 51) / 1024);
1674 }
1675 else if (c_size_show_fractions && (num < 10433332)) /* 1.0M - 9.9M */
1676 {
1677 snprintf(buf, buflen, c_size_units_on_left ? "M%3.1f" : "%3.1fM", num / 1048576.0);
1678 }
1679 else /* 10M+ */
1680 {
1681 /* (10433332 + 52428) / 1048576 = 10 */
1682 snprintf(buf, buflen, c_size_units_on_left ? ("M%zu") : ("%zuM"), (num + 52428) / 1048576);
1683 }
1684}
+ 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 1693 of file muttlib.c.

1694{
1695 /* don't add a NULL or empty string to the list */
1696 if (!str || (*str == '\0'))
1697 return;
1698
1699 /* check to make sure the item is not already on this list */
1700 struct ListNode *np = NULL;
1701 STAILQ_FOREACH(np, head, entries)
1702 {
1703 if (mutt_istr_equal(str, np->data))
1704 {
1705 return;
1706 }
1707 }
1709}
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ 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 1718 of file muttlib.c.

1719{
1720 if (mutt_str_equal("*", str))
1721 {
1722 mutt_list_free(head); /* "unCMD *" means delete all current entries */
1723 }
1724 else
1725 {
1726 struct ListNode *np = NULL, *tmp = NULL;
1727 STAILQ_FOREACH_SAFE(np, head, entries, tmp)
1728 {
1729 if (mutt_istr_equal(str, np->data))
1730 {
1731 STAILQ_REMOVE(head, np, ListNode, entries);
1732 FREE(&np->data);
1733 FREE(&np);
1734 break;
1735 }
1736 }
1737 }
1738}
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
#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:

Variable Documentation

◆ XdgEnvVars

const char* XdgEnvVars[]
static
Initial value:
= {
[XDG_CONFIG_HOME] = "XDG_CONFIG_HOME",
[XDG_CONFIG_DIRS] = "XDG_CONFIG_DIRS",
}
@ XDG_CONFIG_HOME
XDG home dir: ~/.config.
Definition: protos.h:43
@ XDG_CONFIG_DIRS
XDG system dir: /etc/xdg.
Definition: protos.h:44

Accepted XDG environment variables.

Definition at line 66 of file muttlib.c.

◆ XdgDefaults

const char* XdgDefaults[]
static
Initial value:
= {
[XDG_CONFIG_HOME] = "~/.config",
[XDG_CONFIG_DIRS] = "/etc/xdg",
}

XDG default locations.

Definition at line 72 of file muttlib.c.