NeoMutt  2024-04-16-36-g75b6fb
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 <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 "browser/lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "imap/lib.h"
#include "ncrypt/lib.h"
#include "question/lib.h"
#include "globals.h"
#include "hook.h"
#include "mx.h"
#include "protos.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.
 
char * mutt_expand_path (char *buf, size_t buflen)
 Create the canonical path.
 
void buf_expand_path_regex (struct Buffer *buf, bool regex)
 Create the canonical path (with regex char escaping)
 
void buf_expand_path (struct Buffer *buf)
 Create the canonical path.
 
char * mutt_expand_path_regex (char *buf, size_t buflen, bool regex)
 Create the canonical path (with regex char escaping)
 
char * mutt_gecos_name (char *dest, size_t destlen, struct passwd *pw)
 Lookup a user's real name in /etc/passwd.
 
bool mutt_needs_mailcap (struct Body *b)
 Does this type need a mailcap entry do display.
 
bool mutt_is_text_part (const struct Body *b)
 Is this part of an email in plain text?
 
void mutt_pretty_mailbox (char *buf, size_t buflen)
 Shorten a mailbox path using '~' or '='.
 
void buf_pretty_mailbox (struct Buffer *buf)
 Shorten a mailbox path using '~' or '='.
 
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_save_path (char *buf, size_t buflen, const struct Address *addr)
 Turn an email address into a filename (for saving)
 
void buf_save_path (struct Buffer *dest, const struct Address *a)
 Make a safe filename from an email address.
 
void mutt_safe_path (struct Buffer *dest, const struct Address *a)
 Make a safe filename from an email address.
 
FILE * mutt_open_read (const char *path, pid_t *thepid)
 Run a command to read from.
 
int mutt_save_confirm (const char *s, struct stat *st)
 Ask the user to save.
 
void mutt_sleep (short s)
 Sleep for a while.
 
const char * mutt_make_version (void)
 Generate the NeoMutt version string.
 
void mutt_encode_path (struct Buffer *buf, const char *src)
 Convert a path to 'us-ascii'.
 
int mutt_set_xdg_path (enum XdgType type, struct Buffer *buf)
 Find an XDG path or its fallback.
 
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 -.
 
void buf_sanitize_filename (struct Buffer *buf, const char *path, short slash)
 Replace unsafe characters in a filename.
 
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.
 

Variables

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

Detailed Description

Some miscellaneous functions.

Authors
  • Michael R. Elkins
  • Thomas Roessler
  • Richard Russon
  • Aleksa Sarai
  • 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 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:160
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
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:169
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:709
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:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
#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:

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

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

136{
137 const char *s = NULL;
138 const char *tail = "";
139
140 bool recurse = false;
141
142 struct Buffer *p = buf_pool_get();
143 struct Buffer *q = buf_pool_get();
144 struct Buffer *tmp = buf_pool_get();
145
146 do
147 {
148 recurse = false;
149 s = buf_string(buf);
150
151 switch (*s)
152 {
153 case '~':
154 {
155 if ((s[1] == '/') || (s[1] == '\0'))
156 {
158 tail = s + 1;
159 }
160 else
161 {
162 char *t = strchr(s + 1, '/');
163 if (t)
164 *t = '\0';
165
166 struct passwd *pw = getpwnam(s + 1);
167 if (pw)
168 {
169 buf_strcpy(p, pw->pw_dir);
170 if (t)
171 {
172 *t = '/';
173 tail = t;
174 }
175 else
176 {
177 tail = "";
178 }
179 }
180 else
181 {
182 /* user not found! */
183 if (t)
184 *t = '/';
185 buf_reset(p);
186 tail = s;
187 }
188 }
189 break;
190 }
191
192 case '=':
193 case '+':
194 {
195 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
196 enum MailboxType mb_type = mx_path_probe(c_folder);
197
198 /* if folder = {host} or imap[s]://host/: don't append slash */
199 if ((mb_type == MUTT_IMAP) && ((c_folder[strlen(c_folder) - 1] == '}') ||
200 (c_folder[strlen(c_folder) - 1] == '/')))
201 {
202 buf_strcpy(p, c_folder);
203 }
204 else if (mb_type == MUTT_NOTMUCH)
205 {
206 buf_strcpy(p, c_folder);
207 }
208 else if (c_folder && (c_folder[strlen(c_folder) - 1] == '/'))
209 {
210 buf_strcpy(p, c_folder);
211 }
212 else
213 {
214 buf_printf(p, "%s/", NONULL(c_folder));
215 }
216
217 tail = s + 1;
218 break;
219 }
220
221 /* elm compatibility, @ expands alias to user name */
222
223 case '@':
224 {
225 struct AddressList *al = alias_lookup(s + 1);
226 if (al && !TAILQ_EMPTY(al))
227 {
228 struct Email *e = email_new();
229 e->env = mutt_env_new();
230 mutt_addrlist_copy(&e->env->from, al, false);
231 mutt_addrlist_copy(&e->env->to, al, false);
232
234 mutt_default_save(p, e);
235
236 email_free(&e);
237 /* Avoid infinite recursion if the resulting folder starts with '@' */
238 if (*p->data != '@')
239 recurse = true;
240
241 tail = "";
242 }
243 break;
244 }
245
246 case '>':
247 {
248 const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
249 buf_strcpy(p, c_mbox);
250 tail = s + 1;
251 break;
252 }
253
254 case '<':
255 {
256 const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
257 buf_strcpy(p, c_record);
258 tail = s + 1;
259 break;
260 }
261
262 case '!':
263 {
264 if (s[1] == '!')
265 {
267 tail = s + 2;
268 }
269 else
270 {
271 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
272 buf_strcpy(p, c_spool_file);
273 tail = s + 1;
274 }
275 break;
276 }
277
278 case '-':
279 {
281 tail = s + 1;
282 break;
283 }
284
285 case '^':
286 {
288 tail = s + 1;
289 break;
290 }
291
292 default:
293 {
294 buf_reset(p);
295 tail = s;
296 }
297 }
298
299 if (regex && *(buf_string(p)) && !recurse)
300 {
302 buf_printf(tmp, "%s%s", buf_string(q), tail);
303 }
304 else
305 {
306 buf_printf(tmp, "%s%s", buf_string(p), tail);
307 }
308
309 buf_copy(buf, tmp);
310 } while (recurse);
311
314 buf_pool_release(&tmp);
315
316 /* Rewrite IMAP path in canonical form - aids in string comparisons of
317 * folders. May possibly fail, in which case buf should be the same. */
318 if (imap_path_probe(buf_string(buf), NULL) == MUTT_IMAP)
319 imap_expand_path(buf);
320}
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:75
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:600
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:336
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
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:751
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:1319
#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_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 328 of file muttlib.c.

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

343{
344 struct Buffer *tmp = buf_pool_get();
345
346 buf_addstr(tmp, NONULL(buf));
347 buf_expand_path_regex(tmp, regex);
348 mutt_str_copy(buf, buf_string(tmp), buflen);
349
350 buf_pool_release(&tmp);
351
352 return buf;
353}
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
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:575
+ 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 367 of file muttlib.c.

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

415{
416 switch (b->type)
417 {
418 case TYPE_TEXT:
419 if (mutt_istr_equal("plain", b->subtype))
420 return false;
421 break;
422 case TYPE_APPLICATION:
424 return false;
426 return false;
427 break;
428
429 case TYPE_MULTIPART:
430 case TYPE_MESSAGE:
431 return false;
432 }
433
434 return true;
435}
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:595
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition: crypt.c:534
@ 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:666
#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 ( 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 442 of file muttlib.c.

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

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

555{
556 if (!buf || !buf->data)
557 return;
558 /* This reduces the size of the Buffer, so we can pass it through.
559 * We adjust the size just to make sure buf->data is not NULL though */
560 buf_alloc(buf, PATH_MAX);
561 mutt_pretty_mailbox(buf->data, buf->dsize);
562 buf_fix_dptr(buf);
563}
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:475
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:

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

578{
579 struct stat st = { 0 };
580
581 buf_strcpy(fname, path);
582 if (access(buf_string(fname), F_OK) != 0)
583 return 0;
584 if (stat(buf_string(fname), &st) != 0)
585 return -1;
586 if (S_ISDIR(st.st_mode))
587 {
588 enum QuadOption ans = MUTT_NO;
589 if (directory)
590 {
591 switch (mw_multi_choice
592 /* L10N: Means "The path you specified as the destination file is a directory."
593 See the msgid "Save to file: " (alias.c, recvattach.c)
594 These three letters correspond to the choices in the string. */
595 (_("File is a directory, save under it: (y)es, (n)o, (a)ll?"), _("yna")))
596 {
597 case 3: /* all */
598 mutt_str_replace(directory, buf_string(fname));
599 break;
600 case 1: /* yes */
601 FREE(directory);
602 break;
603 case -1: /* abort */
604 FREE(directory);
605 return -1;
606 case 2: /* no */
607 FREE(directory);
608 return 1;
609 }
610 }
611 /* L10N: Means "The path you specified as the destination file is a directory."
612 See the msgid "Save to file: " (alias.c, recvattach.c) */
613 else if ((ans = query_yesorno(_("File is a directory, save under it?"), MUTT_YES)) != MUTT_YES)
614 return (ans == MUTT_NO) ? 1 : -1;
615
616 struct Buffer *tmp = buf_pool_get();
617 buf_strcpy(tmp, mutt_path_basename(NONULL(attname)));
618 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
619 if ((mw_get_field(_("File under directory: "), tmp, MUTT_COMP_CLEAR,
620 HC_FILE, &CompleteFileOps, &cdata) != 0) ||
621 buf_is_empty(tmp))
622 {
623 buf_pool_release(&tmp);
624 return (-1);
625 }
626 buf_concat_path(fname, path, buf_string(tmp));
627 buf_pool_release(&tmp);
628 }
629
630 if ((*opt == MUTT_SAVE_NO_FLAGS) && (access(buf_string(fname), F_OK) == 0))
631 {
632 char buf[4096] = { 0 };
633 snprintf(buf, sizeof(buf), "%s - %s", buf_string(fname),
634 // L10N: Options for: File %s exists, (o)verwrite, (a)ppend, or (c)ancel?
635 _("File exists, (o)verwrite, (a)ppend, or (c)ancel?"));
636 switch (mw_multi_choice(buf, _("oac")))
637 {
638 case -1: /* abort */
639 return -1;
640 case 3: /* cancel */
641 return 1;
642
643 case 2: /* append */
644 *opt = MUTT_SAVE_APPEND;
645 break;
646 case 1: /* overwrite */
647 *opt = MUTT_SAVE_OVERWRITE;
648 break;
649 }
650 }
651 return 0;
652}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:155
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:290
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:508
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:64
@ 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:274
#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:327
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_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 663 of file muttlib.c.

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

689{
690 if (a && a->mailbox)
691 {
692 buf_copy(dest, a->mailbox);
693 const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
694 if (!c_save_address)
695 {
696 char *p = strpbrk(dest->data, "%@");
697 if (p)
698 {
699 *p = '\0';
700 buf_fix_dptr(dest);
701 }
702 }
703 mutt_str_lower(dest->data);
704 }
705 else
706 {
707 buf_reset(dest);
708 }
709}
+ 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 718 of file muttlib.c.

719{
720 buf_save_path(dest, a);
721 for (char *p = dest->data; *p; p++)
722 if ((*p == '/') || isspace(*p) || !IsPrint((unsigned char) *p))
723 *p = '_';
724}
#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:688
+ 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 736 of file muttlib.c.

737{
738 FILE *fp = NULL;
739 struct stat st = { 0 };
740
741 size_t len = mutt_str_len(path);
742 if (len == 0)
743 {
744 return NULL;
745 }
746
747 if (path[len - 1] == '|')
748 {
749 /* read from a pipe */
750
751 char *p = mutt_str_dup(path);
752
753 p[len - 1] = 0;
754 mutt_endwin();
755 *thepid = filter_create(p, NULL, &fp, NULL, EnvList);
756 FREE(&p);
757 }
758 else
759 {
760 if (stat(path, &st) < 0)
761 return NULL;
762 if (S_ISDIR(st.st_mode))
763 {
764 errno = EINVAL;
765 return NULL;
766 }
767 fp = mutt_file_fopen(path, "r");
768 *thepid = -1;
769 }
770 return fp;
771}
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:151
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:146
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 ** EnvList
Private copy of the environment variables.
Definition: globals.c:78
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_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 781 of file muttlib.c.

782{
783 int rc = 0;
784
785 enum MailboxType type = mx_path_probe(s);
786
787 if (type == MUTT_POP)
788 {
789 mutt_error(_("Can't save message to POP mailbox"));
790 return 1;
791 }
792
793 if ((type != MUTT_MAILBOX_ERROR) && (type != MUTT_UNKNOWN) && (mx_access(s, W_OK) == 0))
794 {
795 const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
796 if (c_confirm_append)
797 {
798 struct Buffer *tmp = buf_pool_get();
799 buf_printf(tmp, _("Append messages to %s?"), s);
801 NeoMutt->sub, "confirm_append");
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
810 if (type == MUTT_NNTP)
811 {
812 mutt_error(_("Can't save message to news server"));
813 return 0;
814 }
815
816 if (stat(s, st) != -1)
817 {
818 if (type == MUTT_MAILBOX_ERROR)
819 {
820 mutt_error(_("%s is not a mailbox"), s);
821 return 1;
822 }
823 }
824 else if (type != MUTT_IMAP)
825 {
826 st->st_mtime = 0;
827 st->st_atime = 0;
828
829 /* pathname does not exist */
830 if (errno == ENOENT)
831 {
832 const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
833 if (c_confirm_create)
834 {
835 struct Buffer *tmp = buf_pool_get();
836 buf_printf(tmp, _("Create %s?"), s);
838 NeoMutt->sub, "confirm_create");
839 if (ans == MUTT_NO)
840 rc = 1;
841 else if (ans == MUTT_ABORT)
842 rc = -1;
843 buf_pool_release(&tmp);
844 }
845
846 /* user confirmed with MUTT_YES or set `$confirm_create` */
847 if (rc == 0)
848 {
849 /* create dir recursively */
850 char *tmp_path = mutt_path_dirname(s);
851 if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1)
852 {
853 /* report failure & abort */
854 mutt_perror("%s", s);
855 FREE(&tmp_path);
856 return 1;
857 }
858 FREE(&tmp_path);
859 }
860 }
861 else
862 {
863 mutt_perror("%s", s);
864 return 1;
865 }
866 }
867
868 msgwin_clear_text(NULL);
869 return rc;
870}
@ 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:971
#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:168
@ 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:342
+ 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 878 of file muttlib.c.

879{
880 const short c_sleep_time = cs_subset_number(NeoMutt->sub, "sleep_time");
881 if (c_sleep_time > s)
882 sleep(c_sleep_time);
883 else if (s)
884 sleep(s);
885}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:144
+ 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 893 of file muttlib.c.

894{
895 static char vstring[256];
896 snprintf(vstring, sizeof(vstring), "NeoMutt %s%s", PACKAGE_VERSION, GitVer);
897 return vstring;
898}
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 907 of file muttlib.c.

908{
909 char *p = mutt_str_dup(src);
910 int rc = mutt_ch_convert_string(&p, cc_charset(), "us-ascii", MUTT_ICONV_NO_FLAGS);
911 size_t len = buf_strcpy(buf, (rc == 0) ? NONULL(p) : NONULL(src));
912
913 /* convert the path to POSIX "Portable Filename Character Set" */
914 for (size_t i = 0; i < len; i++)
915 {
916 if (!isalnum(buf->data[i]) && !strchr("/.-_", buf->data[i]))
917 {
918 buf->data[i] = '_';
919 }
920 }
921 FREE(&p);
922}
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:72
+ 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 932 of file muttlib.c.

933{
934 const char *xdg_env = mutt_str_getenv(XdgEnvVars[type]);
935 char *xdg = xdg_env ? mutt_str_dup(xdg_env) : mutt_str_dup(XdgDefaults[type]);
936 char *x = xdg; /* mutt_str_sep() changes xdg, so free x instead later */
937 char *token = NULL;
938 int rc = 0;
939
940 while ((token = mutt_str_sep(&xdg, ":")))
941 {
942 if (buf_printf(buf, "%s/%s/neomuttrc", token, PACKAGE) < 0)
943 continue;
944 buf_expand_path(buf);
945 if (access(buf_string(buf), F_OK) == 0)
946 {
947 rc = 1;
948 break;
949 }
950
951 if (buf_printf(buf, "%s/%s/Muttrc", token, PACKAGE) < 0)
952 continue;
953 buf_expand_path(buf);
954 if (access(buf_string(buf), F_OK) == 0)
955 {
956 rc = 1;
957 break;
958 }
959 }
960
961 FREE(&x);
962 return rc;
963}
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:720
char * mutt_str_sep(char **stringp, const char *delim)
Find first occurrence of any of delim characters in *stringp.
Definition: string.c:186
static const char * XdgEnvVars[]
Accepted XDG environment variables.
Definition: muttlib.c:65
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:328
static const char * XdgDefaults[]
XDG default locations.
Definition: muttlib.c:71
+ 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 971 of file muttlib.c.

972{
973 enum MailboxType mb_type = mx_path_probe(path);
974
975 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
976 if (mb_type == MUTT_IMAP)
977 {
978 imap_get_parent_path(path, buf, buflen);
979 }
980 else if (mb_type == MUTT_NOTMUCH)
981 {
982 mutt_str_copy(buf, c_folder, buflen);
983 }
984 else
985 {
986 mutt_str_copy(buf, path, buflen);
987 int n = mutt_str_len(buf);
988 if (n == 0)
989 return;
990
991 /* remove any final trailing '/' */
992 if (buf[n - 1] == '/')
993 buf[n - 1] = '\0';
994
995 /* Remove everything until the next slash */
996 for (n--; ((n >= 0) && (buf[n] != '/')); n--)
997 ; // do nothing
998
999 if (n > 0)
1000 {
1001 buf[n] = '\0';
1002 }
1003 else
1004 {
1005 buf[0] = '/';
1006 buf[1] = '\0';
1007 }
1008 }
1009}
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:162
+ 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 1079 of file muttlib.c.

1080{
1081 if (!buf || !path)
1082 return;
1083
1084 buf_reset(buf);
1085
1086 for (; *path; path++)
1087 {
1088 if ((slash && (*path == '/')) || !strchr(FilenameSafeChars, *path))
1089 buf_addch(buf, '_');
1090 else
1091 buf_addch(buf, *path);
1092 }
1093}
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
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:

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

1102{
1103 if (!buf || (buflen == 0))
1104 return;
1105
1106 const bool c_size_show_bytes = cs_subset_bool(NeoMutt->sub, "size_show_bytes");
1107 const bool c_size_show_fractions = cs_subset_bool(NeoMutt->sub, "size_show_fractions");
1108 const bool c_size_show_mb = cs_subset_bool(NeoMutt->sub, "size_show_mb");
1109 const bool c_size_units_on_left = cs_subset_bool(NeoMutt->sub, "size_units_on_left");
1110
1111 if (c_size_show_bytes && (num < 1024))
1112 {
1113 snprintf(buf, buflen, "%d", (int) num);
1114 }
1115 else if (num == 0)
1116 {
1117 mutt_str_copy(buf, c_size_units_on_left ? "K0" : "0K", buflen);
1118 }
1119 else if (c_size_show_fractions && (num < 10189)) /* 0.1K - 9.9K */
1120 {
1121 snprintf(buf, buflen, c_size_units_on_left ? "K%3.1f" : "%3.1fK",
1122 (num < 103) ? 0.1 : (num / 1024.0));
1123 }
1124 else if (!c_size_show_mb || (num < 1023949)) /* 10K - 999K */
1125 {
1126 /* 51 is magic which causes 10189/10240 to be rounded up to 10 */
1127 snprintf(buf, buflen, c_size_units_on_left ? ("K%zu") : ("%zuK"), (num + 51) / 1024);
1128 }
1129 else if (c_size_show_fractions && (num < 10433332)) /* 1.0M - 9.9M */
1130 {
1131 snprintf(buf, buflen, c_size_units_on_left ? "M%3.1f" : "%3.1fM", num / 1048576.0);
1132 }
1133 else /* 10M+ */
1134 {
1135 /* (10433332 + 52428) / 1048576 = 10 */
1136 snprintf(buf, buflen, c_size_units_on_left ? ("M%zu") : ("%zuM"), (num + 52428) / 1048576);
1137 }
1138}
+ 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 1147 of file muttlib.c.

1148{
1149 /* don't add a NULL or empty string to the list */
1150 if (!str || (*str == '\0'))
1151 return;
1152
1153 /* check to make sure the item is not already on this list */
1154 struct ListNode *np = NULL;
1155 STAILQ_FOREACH(np, head, entries)
1156 {
1157 if (mutt_istr_equal(str, np->data))
1158 {
1159 return;
1160 }
1161 }
1163}
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 1172 of file muttlib.c.

1173{
1174 if (mutt_str_equal("*", str))
1175 {
1176 mutt_list_free(head); /* "unCMD *" means delete all current entries */
1177 }
1178 else
1179 {
1180 struct ListNode *np = NULL, *tmp = NULL;
1181 STAILQ_FOREACH_SAFE(np, head, entries, tmp)
1182 {
1183 if (mutt_istr_equal(str, np->data))
1184 {
1185 STAILQ_REMOVE(head, np, ListNode, entries);
1186 FREE(&np->data);
1187 FREE(&np);
1188 break;
1189 }
1190 }
1191 }
1192}
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:654
#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:44
@ XDG_CONFIG_DIRS
XDG system dir: /etc/xdg.
Definition: protos.h:45

Accepted XDG environment variables.

Definition at line 65 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 71 of file muttlib.c.