NeoMutt  2022-04-29-81-g9c5a59
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 <inttypes.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 "ncrypt/lib.h"
#include "question/lib.h"
#include "format_flags.h"
#include "hook.h"
#include "init.h"
#include "mutt_globals.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 mutt_buffer_expand_path_regex (struct Buffer *buf, bool regex)
 Create the canonical path (with regex char escaping) More...
 
void mutt_buffer_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_buffer_mktemp_full (struct Buffer *buf, const char *prefix, const char *suffix, const char *src, int line)
 Create a temporary file. More...
 
void mutt_mktemp_full (char *buf, size_t buflen, const char *prefix, const char *suffix, const char *src, int line)
 Create a temporary filename. More...
 
void mutt_pretty_mailbox (char *buf, size_t buflen)
 Shorten a mailbox path using '~' or '='. More...
 
void mutt_buffer_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 mutt_buffer_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 mutt_buffer_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 * xdg_env_vars []
 
static const char * xdg_defaults []
 

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

84 {
85  if (!(buf->data && (buf->data[0] != '\0')))
86  {
87  mutt_buffer_mktemp(buf);
88  }
89  else
90  {
91  struct Buffer *prefix = mutt_buffer_pool_get();
92  mutt_buffer_strcpy(prefix, buf->data);
93  mutt_file_sanitize_filename(prefix->data, true);
94  const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
95  mutt_buffer_printf(buf, "%s/%s", NONULL(c_tmpdir), mutt_buffer_string(prefix));
96 
97  struct stat st = { 0 };
98  if ((lstat(mutt_buffer_string(buf), &st) == -1) && (errno == ENOENT))
99  goto out;
100 
101  char *suffix = strchr(prefix->data, '.');
102  if (suffix)
103  {
104  *suffix = '\0';
105  suffix++;
106  }
107  mutt_buffer_mktemp_pfx_sfx(buf, prefix->data, suffix);
108 
109  out:
110  mutt_buffer_pool_release(&prefix);
111  }
112 }
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:647
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
#define mutt_buffer_mktemp_pfx_sfx(buf, prefix, suffix)
Definition: muttlib.h:75
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#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
+ 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 122 of file muttlib.c.

123 {
124  return mutt_expand_path_regex(buf, buflen, false);
125 }
char * mutt_expand_path_regex(char *buf, size_t buflen, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:335
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_buffer_expand_path_regex()

void mutt_buffer_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 134 of file muttlib.c.

135 {
136  const char *s = NULL;
137  const char *tail = "";
138 
139  bool recurse = false;
140 
141  struct Buffer *p = mutt_buffer_pool_get();
142  struct Buffer *q = mutt_buffer_pool_get();
143  struct Buffer *tmp = mutt_buffer_pool_get();
144 
145  do
146  {
147  recurse = false;
148  s = mutt_buffer_string(buf);
149 
150  switch (*s)
151  {
152  case '~':
153  {
154  if ((s[1] == '/') || (s[1] == '\0'))
155  {
157  tail = s + 1;
158  }
159  else
160  {
161  char *t = strchr(s + 1, '/');
162  if (t)
163  *t = '\0';
164 
165  struct passwd *pw = getpwnam(s + 1);
166  if (pw)
167  {
168  mutt_buffer_strcpy(p, pw->pw_dir);
169  if (t)
170  {
171  *t = '/';
172  tail = t;
173  }
174  else
175  tail = "";
176  }
177  else
178  {
179  /* user not found! */
180  if (t)
181  *t = '/';
183  tail = s;
184  }
185  }
186  break;
187  }
188 
189  case '=':
190  case '+':
191  {
192  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
193  enum MailboxType mb_type = mx_path_probe(c_folder);
194 
195  /* if folder = {host} or imap[s]://host/: don't append slash */
196  if ((mb_type == MUTT_IMAP) && ((c_folder[strlen(c_folder) - 1] == '}') ||
197  (c_folder[strlen(c_folder) - 1] == '/')))
198  {
199  mutt_buffer_strcpy(p, NONULL(c_folder));
200  }
201  else if (mb_type == MUTT_NOTMUCH)
202  mutt_buffer_strcpy(p, NONULL(c_folder));
203  else if (c_folder && (c_folder[strlen(c_folder) - 1] == '/'))
204  mutt_buffer_strcpy(p, NONULL(c_folder));
205  else
206  mutt_buffer_printf(p, "%s/", NONULL(c_folder));
207 
208  tail = s + 1;
209  break;
210  }
211 
212  /* elm compatibility, @ expands alias to user name */
213 
214  case '@':
215  {
216  struct AddressList *al = alias_lookup(s + 1);
217  if (al && !TAILQ_EMPTY(al))
218  {
219  struct Email *e = email_new();
220  e->env = mutt_env_new();
221  mutt_addrlist_copy(&e->env->from, al, false);
222  mutt_addrlist_copy(&e->env->to, al, false);
223 
224  /* TODO: fix mutt_default_save() to use Buffer */
226  mutt_default_save(p->data, p->dsize, e);
228 
229  email_free(&e);
230  /* Avoid infinite recursion if the resulting folder starts with '@' */
231  if (*p->data != '@')
232  recurse = true;
233 
234  tail = "";
235  }
236  break;
237  }
238 
239  case '>':
240  {
241  const char *const c_mbox = cs_subset_string(NeoMutt->sub, "mbox");
242  mutt_buffer_strcpy(p, c_mbox);
243  tail = s + 1;
244  break;
245  }
246 
247  case '<':
248  {
249  const char *const c_record = cs_subset_string(NeoMutt->sub, "record");
250  mutt_buffer_strcpy(p, c_record);
251  tail = s + 1;
252  break;
253  }
254 
255  case '!':
256  {
257  if (s[1] == '!')
258  {
260  tail = s + 2;
261  }
262  else
263  {
264  const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
265  mutt_buffer_strcpy(p, c_spool_file);
266  tail = s + 1;
267  }
268  break;
269  }
270 
271  case '-':
272  {
274  tail = s + 1;
275  break;
276  }
277 
278  case '^':
279  {
281  tail = s + 1;
282  break;
283  }
284 
285  default:
286  {
288  tail = s;
289  }
290  }
291 
292  if (regex && *(mutt_buffer_string(p)) && !recurse)
293  {
295  mutt_buffer_printf(tmp, "%s%s", mutt_buffer_string(q), tail);
296  }
297  else
298  mutt_buffer_printf(tmp, "%s%s", mutt_buffer_string(p), tail);
299 
300  mutt_buffer_copy(buf, tmp);
301  } while (recurse);
302 
306 
307 #ifdef USE_IMAP
308  /* Rewrite IMAP path in canonical form - aids in string comparisons of
309  * folders. May possibly fail, in which case buf should be the same. */
310  if (imap_path_probe(mutt_buffer_string(buf), NULL) == MUTT_IMAP)
311  imap_expand_path(buf);
312 #endif
313 }
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:279
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:447
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
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:666
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2400
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:710
int imap_expand_path(struct Buffer *buf)
Buffer wrapper around imap_path_canon()
Definition: imap.c:2440
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:40
char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1327
#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:

◆ mutt_buffer_expand_path()

void mutt_buffer_expand_path ( struct Buffer buf)

Create the canonical path.

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

Definition at line 321 of file muttlib.c.

322 {
323  mutt_buffer_expand_path_regex(buf, false);
324 }
void mutt_buffer_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:134
+ 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 335 of file muttlib.c.

336 {
337  struct Buffer *tmp = mutt_buffer_pool_get();
338 
339  mutt_buffer_addstr(tmp, NONULL(buf));
340  mutt_buffer_expand_path_regex(tmp, regex);
341  mutt_str_copy(buf, mutt_buffer_string(tmp), buflen);
342 
344 
345  return buf;
346 }
size_t mutt_buffer_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:629
+ 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 360 of file muttlib.c.

361 {
362  regmatch_t pat_match[1];
363  size_t pwnl;
364  char *p = NULL;
365 
366  if (!pw || !pw->pw_gecos)
367  return NULL;
368 
369  memset(dest, 0, destlen);
370 
371  const struct Regex *c_gecos_mask = cs_subset_regex(NeoMutt->sub, "gecos_mask");
372  if (mutt_regex_capture(c_gecos_mask, pw->pw_gecos, 1, pat_match))
373  {
374  mutt_str_copy(dest, pw->pw_gecos + pat_match[0].rm_so,
375  MIN(pat_match[0].rm_eo - pat_match[0].rm_so + 1, destlen));
376  }
377  else if ((p = strchr(pw->pw_gecos, ',')))
378  mutt_str_copy(dest, pw->pw_gecos, MIN(destlen, p - pw->pw_gecos + 1));
379  else
380  mutt_str_copy(dest, pw->pw_gecos, destlen);
381 
382  pwnl = strlen(pw->pw_name);
383 
384  for (int idx = 0; dest[idx]; idx++)
385  {
386  if (dest[idx] == '&')
387  {
388  memmove(&dest[idx + pwnl], &dest[idx + 1],
389  MAX((ssize_t) (destlen - idx - pwnl - 1), 0));
390  memcpy(&dest[idx], pw->pw_name, MIN(destlen - idx - 1, pwnl));
391  dest[idx] = toupper((unsigned char) dest[idx]);
392  }
393  }
394 
395  return dest;
396 }
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:614
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 404 of file muttlib.c.

405 {
406  switch (m->type)
407  {
408  case TYPE_TEXT:
409  if (mutt_istr_equal("plain", m->subtype))
410  return false;
411  break;
412  case TYPE_APPLICATION:
414  return false;
416  return false;
417  break;
418 
419  case TYPE_MULTIPART:
420  case TYPE_MESSAGE:
421  return false;
422  }
423 
424  return true;
425 }
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:544
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:601
@ 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:796
#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 432 of file muttlib.c.

433 {
434  int t = b->type;
435  char *s = b->subtype;
436 
438  return false;
439 
440  if (t == TYPE_TEXT)
441  return true;
442 
443  if (t == TYPE_MESSAGE)
444  {
445  if (mutt_istr_equal("delivery-status", s))
446  return true;
447  }
448 
449  if (((WithCrypto & APPLICATION_PGP) != 0) && (t == TYPE_APPLICATION))
450  {
451  if (mutt_istr_equal("pgp-keys", s))
452  return true;
453  }
454 
455  return false;
456 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_buffer_mktemp_full()

void mutt_buffer_mktemp_full ( struct Buffer buf,
const char *  prefix,
const char *  suffix,
const char *  src,
int  line 
)

Create a temporary file.

Parameters
bufBuffer for result
prefixPrefix for filename
suffixSuffix for filename
srcSource file of caller
lineSource line number of caller

Definition at line 466 of file muttlib.c.

468 {
469  const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
470  mutt_buffer_printf(buf, "%s/%s-%s-%d-%d-%" PRIu64 "%s%s", NONULL(c_tmpdir),
471  NONULL(prefix), NONULL(ShortHostname), (int) getuid(),
472  (int) getpid(), mutt_rand64(), suffix ? "." : "", NONULL(suffix));
473 
474  mutt_debug(LL_DEBUG3, "%s:%d: mutt_mktemp returns \"%s\"\n", src, line,
475  mutt_buffer_string(buf));
476  if (unlink(mutt_buffer_string(buf)) && (errno != ENOENT))
477  {
478  mutt_debug(LL_DEBUG1, "%s:%d: ERROR: unlink(\"%s\"): %s (errno %d)\n", src,
479  line, mutt_buffer_string(buf), strerror(errno), errno);
480  }
481 }
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:129
+ Here is the call graph for this function:

◆ mutt_mktemp_full()

void mutt_mktemp_full ( char *  buf,
size_t  buflen,
const char *  prefix,
const char *  suffix,
const char *  src,
int  line 
)

Create a temporary filename.

Parameters
bufBuffer for result
buflenLength of buffer
prefixPrefix for filename
suffixSuffix for filename
srcSource file of caller
lineSource line number of caller
Note
This doesn't create the file, only the name

Definition at line 494 of file muttlib.c.

496 {
497  const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
498  size_t n = snprintf(buf, buflen, "%s/%s-%s-%d-%d-%" PRIu64 "%s%s", NONULL(c_tmpdir),
499  NONULL(prefix), NONULL(ShortHostname), (int) getuid(),
500  (int) getpid(), mutt_rand64(), suffix ? "." : "", NONULL(suffix));
501  if (n >= buflen)
502  {
503  mutt_debug(LL_DEBUG1, "%s:%d: ERROR: insufficient buffer space to hold temporary filename! buflen=%zu but need %zu\n",
504  src, line, buflen, n);
505  }
506  mutt_debug(LL_DEBUG3, "%s:%d: mutt_mktemp returns \"%s\"\n", src, line, buf);
507  if ((unlink(buf) != 0) && (errno != ENOENT))
508  {
509  mutt_debug(LL_DEBUG1, "%s:%d: ERROR: unlink(\"%s\"): %s (errno %d)\n", src,
510  line, buf, strerror(errno), errno);
511  }
512 }
+ Here is the call 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 521 of file muttlib.c.

522 {
523  if (!buf)
524  return;
525 
526  char *p = buf, *q = buf;
527  size_t len;
528  enum UrlScheme scheme;
529  char tmp[PATH_MAX];
530 
531  scheme = url_check_scheme(buf);
532 
533  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
534  if ((scheme == U_IMAP) || (scheme == U_IMAPS))
535  {
536  imap_pretty_mailbox(buf, buflen, c_folder);
537  return;
538  }
539 
540  if (scheme == U_NOTMUCH)
541  return;
542 
543  /* if buf is an url, only collapse path component */
544  if (scheme != U_UNKNOWN)
545  {
546  p = strchr(buf, ':') + 1;
547  if (mutt_strn_equal(p, "//", 2))
548  q = strchr(p + 2, '/');
549  if (!q)
550  q = strchr(p, '\0');
551  p = q;
552  }
553 
554  /* cleanup path */
555  if (strstr(p, "//") || strstr(p, "/./"))
556  {
557  /* first attempt to collapse the pathname, this is more
558  * lightweight than realpath() and doesn't resolve links */
559  while (*p)
560  {
561  if ((p[0] == '/') && (p[1] == '/'))
562  {
563  *q++ = '/';
564  p += 2;
565  }
566  else if ((p[0] == '/') && (p[1] == '.') && (p[2] == '/'))
567  {
568  *q++ = '/';
569  p += 3;
570  }
571  else
572  *q++ = *p++;
573  }
574  *q = '\0';
575  }
576  else if (strstr(p, "..") && ((scheme == U_UNKNOWN) || (scheme == U_FILE)) &&
577  realpath(p, tmp))
578  {
579  mutt_str_copy(p, tmp, buflen - (p - buf));
580  }
581 
582  if ((len = mutt_str_startswith(buf, c_folder)) && (buf[len] == '/'))
583  {
584  *buf++ = '=';
585  memmove(buf, buf + len, mutt_str_len(buf + len) + 1);
586  }
587  else if ((len = mutt_str_startswith(buf, HomeDir)) && (buf[len] == '/'))
588  {
589  *buf++ = '~';
590  memmove(buf, buf + len - 1, mutt_str_len(buf + len - 1) + 1);
591  }
592 }
void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
Prettify an IMAP mailbox name.
Definition: util.c:589
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:473
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:221
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:

◆ mutt_buffer_pretty_mailbox()

void mutt_buffer_pretty_mailbox ( struct Buffer buf)

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

Parameters
bufBuffer containing Mailbox name

Definition at line 598 of file muttlib.c.

599 {
600  if (!buf || !buf->data)
601  return;
602  /* This reduces the size of the Buffer, so we can pass it through.
603  * We adjust the size just to make sure buf->data is not NULL though */
605  mutt_pretty_mailbox(buf->data, buf->dsize);
607 }
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:521
+ 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 620 of file muttlib.c.

622 {
623  struct stat st = { 0 };
624 
625  mutt_buffer_strcpy(fname, path);
626  if (access(mutt_buffer_string(fname), F_OK) != 0)
627  return 0;
628  if (stat(mutt_buffer_string(fname), &st) != 0)
629  return -1;
630  if (S_ISDIR(st.st_mode))
631  {
632  enum QuadOption ans = MUTT_NO;
633  if (directory)
634  {
635  switch (mutt_multi_choice
636  /* L10N: Means "The path you specified as the destination file is a directory."
637  See the msgid "Save to file: " (alias.c, recvattach.c)
638  These three letters correspond to the choices in the string. */
639  (_("File is a directory, save under it: (y)es, (n)o, (a)ll?"), _("yna")))
640  {
641  case 3: /* all */
642  mutt_str_replace(directory, mutt_buffer_string(fname));
643  break;
644  case 1: /* yes */
645  FREE(directory);
646  break;
647  case -1: /* abort */
648  FREE(directory);
649  return -1;
650  case 2: /* no */
651  FREE(directory);
652  return 1;
653  }
654  }
655  /* L10N: Means "The path you specified as the destination file is a directory."
656  See the msgid "Save to file: " (alias.c, recvattach.c) */
657  else if ((ans = mutt_yesorno(_("File is a directory, save under it?"), MUTT_YES)) != MUTT_YES)
658  return (ans == MUTT_NO) ? 1 : -1;
659 
660  struct Buffer *tmp = mutt_buffer_pool_get();
662  if ((mutt_buffer_get_field(_("File under directory: "), tmp, MUTT_COMP_FILE | MUTT_COMP_CLEAR,
663  false, NULL, NULL, NULL) != 0) ||
665  {
667  return (-1);
668  }
669  mutt_buffer_concat_path(fname, path, mutt_buffer_string(tmp));
671  }
672 
673  if ((*opt == MUTT_SAVE_NO_FLAGS) && (access(mutt_buffer_string(fname), F_OK) == 0))
674  {
675  char buf[4096] = { 0 };
676  snprintf(buf, sizeof(buf), "%s - %s", mutt_buffer_string(fname),
677  // L10N: Options for: File %s exists, (o)verwrite, (a)ppend, or (c)ancel?
678  _("File exists, (o)verwrite, (a)ppend, or (c)ancel?"));
679  switch (mutt_multi_choice(buf, _("oac")))
680  {
681  case -1: /* abort */
682  return -1;
683  case 3: /* cancel */
684  return 1;
685 
686  case 2: /* append */
687  *opt = MUTT_SAVE_APPEND;
688  break;
689  case 1: /* overwrite */
690  *opt = MUTT_SAVE_OVERWRITE;
691  break;
692  }
693  }
694  return 0;
695 }
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:374
int mutt_buffer_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: curs_lib.c:337
#define FREE(x)
Definition: memory.h:40
#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:326
#define MUTT_COMP_FILE
File completion (in browser)
Definition: mutt.h:55
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
@ MUTT_SAVE_APPEND
Append to existing file.
Definition: mutt_attach.h:58
@ MUTT_SAVE_OVERWRITE
Overwrite existing file.
Definition: mutt_attach.h:59
@ MUTT_SAVE_NO_FLAGS
No flags set.
Definition: mutt_attach.h:57
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 706 of file muttlib.c.

707 {
708  if (addr && addr->mailbox)
709  {
710  mutt_str_copy(buf, addr->mailbox, buflen);
711  const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
712  if (!c_save_address)
713  {
714  char *p = strpbrk(buf, "%@");
715  if (p)
716  *p = '\0';
717  }
718  mutt_str_lower(buf);
719  }
720  else
721  *buf = '\0';
722 }
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:384
char * mailbox
Mailbox and host address.
Definition: address.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_buffer_save_path()

void mutt_buffer_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 729 of file muttlib.c.

730 {
731  if (a && a->mailbox)
732  {
733  mutt_buffer_strcpy(dest, a->mailbox);
734  const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
735  if (!c_save_address)
736  {
737  char *p = strpbrk(dest->data, "%@");
738  if (p)
739  {
740  *p = '\0';
741  mutt_buffer_fix_dptr(dest);
742  }
743  }
744  mutt_str_lower(dest->data);
745  }
746  else
747  mutt_buffer_reset(dest);
748 }
+ 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 757 of file muttlib.c.

758 {
759  mutt_buffer_save_path(dest, a);
760  for (char *p = dest->data; *p; p++)
761  if ((*p == '/') || IS_SPACE(*p) || !IsPrint((unsigned char) *p))
762  *p = '_';
763 }
#define IsPrint(ch)
Definition: mbyte.h:38
void mutt_buffer_save_path(struct Buffer *dest, const struct Address *a)
Make a safe filename from an email address.
Definition: muttlib.c:729
#define IS_SPACE(ch)
Definition: string2.h:38
+ 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 1310 of file muttlib.c.

1311 {
1312  FILE *fp = NULL;
1313  struct stat st = { 0 };
1314 
1315  size_t len = mutt_str_len(path);
1316  if (len == 0)
1317  {
1318  return NULL;
1319  }
1320 
1321  if (path[len - 1] == '|')
1322  {
1323  /* read from a pipe */
1324 
1325  char *p = mutt_str_dup(path);
1326 
1327  p[len - 1] = 0;
1328  mutt_endwin();
1329  *thepid = filter_create(p, NULL, &fp, NULL);
1330  FREE(&p);
1331  }
1332  else
1333  {
1334  if (stat(path, &st) < 0)
1335  return NULL;
1336  if (S_ISDIR(st.st_mode))
1337  {
1338  errno = EINVAL;
1339  return NULL;
1340  }
1341  fp = fopen(path, "r");
1342  *thepid = -1;
1343  }
1344  return fp;
1345 }
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:465
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:250
+ 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 1355 of file muttlib.c.

1356 {
1357  int rc = 0;
1358 
1359  enum MailboxType type = mx_path_probe(s);
1360 
1361 #ifdef USE_POP
1362  if (type == MUTT_POP)
1363  {
1364  mutt_error(_("Can't save message to POP mailbox"));
1365  return 1;
1366  }
1367 #endif
1368 
1369  if ((type != MUTT_MAILBOX_ERROR) && (type != MUTT_UNKNOWN) && (mx_access(s, W_OK) == 0))
1370  {
1371  const bool c_confirm_append = cs_subset_bool(NeoMutt->sub, "confirm_append");
1372  if (c_confirm_append)
1373  {
1374  struct Buffer *tmp = mutt_buffer_pool_get();
1375  mutt_buffer_printf(tmp, _("Append messages to %s?"), s);
1377  if (ans == MUTT_NO)
1378  rc = 1;
1379  else if (ans == MUTT_ABORT)
1380  rc = -1;
1382  }
1383  }
1384 
1385 #ifdef USE_NNTP
1386  if (type == MUTT_NNTP)
1387  {
1388  mutt_error(_("Can't save message to news server"));
1389  return 0;
1390  }
1391 #endif
1392 
1393  if (stat(s, st) != -1)
1394  {
1395  if (type == MUTT_MAILBOX_ERROR)
1396  {
1397  mutt_error(_("%s is not a mailbox"), s);
1398  return 1;
1399  }
1400  }
1401  else if (type != MUTT_IMAP)
1402  {
1403  st->st_mtime = 0;
1404  st->st_atime = 0;
1405 
1406  /* pathname does not exist */
1407  if (errno == ENOENT)
1408  {
1409  const bool c_confirm_create = cs_subset_bool(NeoMutt->sub, "confirm_create");
1410  if (c_confirm_create)
1411  {
1412  struct Buffer *tmp = mutt_buffer_pool_get();
1413  mutt_buffer_printf(tmp, _("Create %s?"), s);
1415  if (ans == MUTT_NO)
1416  rc = 1;
1417  else if (ans == MUTT_ABORT)
1418  rc = -1;
1420  }
1421 
1422  /* user confirmed with MUTT_YES or set `$confirm_create` */
1423  if (rc == 0)
1424  {
1425  /* create dir recursively */
1426  char *tmp_path = mutt_path_dirname(s);
1427  if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1)
1428  {
1429  /* report failure & abort */
1430  mutt_perror(s);
1431  FREE(&tmp_path);
1432  return 1;
1433  }
1434  FREE(&tmp_path);
1435  }
1436  }
1437  else
1438  {
1439  mutt_perror(s);
1440  return 1;
1441  }
1442  }
1443 
1445  return rc;
1446 }
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:930
#define mutt_error(...)
Definition: logging.h:87
#define mutt_perror(...)
Definition: logging.h:88
@ 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:248
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:184
@ 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 1454 of file muttlib.c.

1455 {
1456  const short c_sleep_time = cs_subset_number(NeoMutt->sub, "sleep_time");
1457  if (c_sleep_time > s)
1458  sleep(c_sleep_time);
1459  else if (s)
1460  sleep(s);
1461 }
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 1469 of file muttlib.c.

1470 {
1471  static char vstring[256];
1472  snprintf(vstring, sizeof(vstring), "NeoMutt %s%s", PACKAGE_VERSION, GitVer);
1473  return vstring;
1474 }
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 1483 of file muttlib.c.

1484 {
1485  char *p = mutt_str_dup(src);
1486  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
1487  int rc = mutt_ch_convert_string(&p, c_charset, "us-ascii", MUTT_ICONV_NO_FLAGS);
1488  size_t len = mutt_buffer_strcpy(buf, (rc == 0) ? NONULL(p) : NONULL(src));
1489 
1490  /* convert the path to POSIX "Portable Filename Character Set" */
1491  for (size_t i = 0; i < len; i++)
1492  {
1493  if (!isalnum(buf->data[i]) && !strchr("/.-_", buf->data[i]))
1494  {
1495  buf->data[i] = '_';
1496  }
1497  }
1498  FREE(&p);
1499 }
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:752
#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 1509 of file muttlib.c.

1510 {
1511  const char *xdg_env = mutt_str_getenv(xdg_env_vars[type]);
1512  char *xdg = xdg_env ? mutt_str_dup(xdg_env) : mutt_str_dup(xdg_defaults[type]);
1513  char *x = xdg; /* mutt_str_sep() changes xdg, so free x instead later */
1514  char *token = NULL;
1515  int rc = 0;
1516 
1517  while ((token = mutt_str_sep(&xdg, ":")))
1518  {
1519  if (mutt_buffer_printf(buf, "%s/%s/neomuttrc", token, PACKAGE) < 0)
1520  continue;
1522  if (access(mutt_buffer_string(buf), F_OK) == 0)
1523  {
1524  rc = 1;
1525  break;
1526  }
1527 
1528  if (mutt_buffer_printf(buf, "%s/%s/Muttrc", token, PACKAGE) < 0)
1529  continue;
1531  if (access(mutt_buffer_string(buf), F_OK) == 0)
1532  {
1533  rc = 1;
1534  break;
1535  }
1536  }
1537 
1538  FREE(&x);
1539  return rc;
1540 }
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:904
char * mutt_str_sep(char **stringp, const char *delim)
Find first occurance of any of delim characters in *stringp.
Definition: string.c:183
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:321
static const char * xdg_env_vars[]
Definition: muttlib.c:65
static const char * xdg_defaults[]
Definition: muttlib.c:70
+ 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 1548 of file muttlib.c.

1549 {
1550  enum MailboxType mb_type = mx_path_probe(path);
1551 
1552  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1553  if (mb_type == MUTT_IMAP)
1554  imap_get_parent_path(path, buf, buflen);
1555  else if (mb_type == MUTT_NOTMUCH)
1556  mutt_str_copy(buf, c_folder, buflen);
1557  else
1558  {
1559  mutt_str_copy(buf, path, buflen);
1560  int n = mutt_str_len(buf);
1561  if (n == 0)
1562  return;
1563 
1564  /* remove any final trailing '/' */
1565  if (buf[n - 1] == '/')
1566  buf[n - 1] = '\0';
1567 
1568  /* Remove everything until the next slash */
1569  for (n--; ((n >= 0) && (buf[n] != '/')); n--)
1570  ; // do nothing
1571 
1572  if (n > 0)
1573  buf[n] = '\0';
1574  else
1575  {
1576  buf[0] = '/';
1577  buf[1] = '\0';
1578  }
1579  }
1580 }
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:161
+ 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 1604 of file muttlib.c.

1605 {
1606  /* fast-track in case the paths have been mutt_pretty_mailbox'ified */
1607  if ((a[0] == '+') && (b[0] == '+'))
1608  {
1609  return mutt_istr_equal(a + 1, "inbox") ? -1 :
1610  mutt_istr_equal(b + 1, "inbox") ? 1 :
1611  0;
1612  }
1613 
1614  const char *a_end = strrchr(a, '/');
1615  const char *b_end = strrchr(b, '/');
1616 
1617  /* If one path contains a '/', but not the other */
1618  if ((!a_end) ^ (!b_end))
1619  return 0;
1620 
1621  /* If neither path contains a '/' */
1622  if (!a_end)
1623  return 0;
1624 
1625  /* Compare the subpaths */
1626  size_t a_len = a_end - a;
1627  size_t b_len = b_end - b;
1628  size_t min = MIN(a_len, b_len);
1629  int same = (a[min] == '/') && (b[min] == '/') && (a[min + 1] != '\0') &&
1630  (b[min + 1] != '\0') && mutt_istrn_equal(a, b, min);
1631 
1632  if (!same)
1633  return 0;
1634 
1635  if (mutt_istr_equal(&a[min + 1], "inbox"))
1636  return -1;
1637 
1638  if (mutt_istr_equal(&b[min + 1], "inbox"))
1639  return 1;
1640 
1641  return 0;
1642 }
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:501
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_buffer_sanitize_filename()

void mutt_buffer_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 1650 of file muttlib.c.

1651 {
1652  if (!buf || !path)
1653  return;
1654 
1655  mutt_buffer_reset(buf);
1656 
1657  for (; *path; path++)
1658  {
1659  if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path))
1660  mutt_buffer_addch(buf, '_');
1661  else
1662  mutt_buffer_addch(buf, *path);
1663  }
1664 }
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
const char filename_safe_chars[]
Definition: file.c:61
+ 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 1672 of file muttlib.c.

1673 {
1674  if (!buf || (buflen == 0))
1675  return;
1676 
1677  const bool c_size_show_bytes = cs_subset_bool(NeoMutt->sub, "size_show_bytes");
1678  const bool c_size_show_fractions = cs_subset_bool(NeoMutt->sub, "size_show_fractions");
1679  const bool c_size_show_mb = cs_subset_bool(NeoMutt->sub, "size_show_mb");
1680  const bool c_size_units_on_left = cs_subset_bool(NeoMutt->sub, "size_units_on_left");
1681 
1682  if (c_size_show_bytes && (num < 1024))
1683  {
1684  snprintf(buf, buflen, "%d", (int) num);
1685  }
1686  else if (num == 0)
1687  {
1688  mutt_str_copy(buf, c_size_units_on_left ? "K0" : "0K", buflen);
1689  }
1690  else if (c_size_show_fractions && (num < 10189)) /* 0.1K - 9.9K */
1691  {
1692  snprintf(buf, buflen, c_size_units_on_left ? "K%3.1f" : "%3.1fK",
1693  (num < 103) ? 0.1 : (num / 1024.0));
1694  }
1695  else if (!c_size_show_mb || (num < 1023949)) /* 10K - 999K */
1696  {
1697  /* 51 is magic which causes 10189/10240 to be rounded up to 10 */
1698  snprintf(buf, buflen, c_size_units_on_left ? ("K%zu") : ("%zuK"), (num + 51) / 1024);
1699  }
1700  else if (c_size_show_fractions && (num < 10433332)) /* 1.0M - 9.9M */
1701  {
1702  snprintf(buf, buflen, c_size_units_on_left ? "M%3.1f" : "%3.1fM", num / 1048576.0);
1703  }
1704  else /* 10M+ */
1705  {
1706  /* (10433332 + 52428) / 1048576 = 10 */
1707  snprintf(buf, buflen, c_size_units_on_left ? ("M%zu") : ("%zuM"), (num + 52428) / 1048576);
1708  }
1709 }
+ 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 1718 of file muttlib.c.

1719 {
1720  /* don't add a NULL or empty string to the list */
1721  if (!str || (*str == '\0'))
1722  return;
1723 
1724  /* check to make sure the item is not already on this list */
1725  struct ListNode *np = NULL;
1726  STAILQ_FOREACH(np, head, entries)
1727  {
1728  if (mutt_istr_equal(str, np->data))
1729  {
1730  return;
1731  }
1732  }
1733  mutt_list_insert_tail(head, mutt_str_dup(str));
1734 }
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 1743 of file muttlib.c.

1744 {
1745  if (mutt_str_equal("*", str))
1746  mutt_list_free(head); /* "unCMD *" means delete all current entries */
1747  else
1748  {
1749  struct ListNode *np = NULL, *tmp = NULL;
1750  STAILQ_FOREACH_SAFE(np, head, entries, tmp)
1751  {
1752  if (mutt_istr_equal(str, np->data))
1753  {
1754  STAILQ_REMOVE(head, np, ListNode, entries);
1755  FREE(&np->data);
1756  FREE(&np);
1757  break;
1758  }
1759  }
1760  }
1761 }
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:784
#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:

Variable Documentation

◆ xdg_env_vars

const char* xdg_env_vars[]
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

Definition at line 65 of file muttlib.c.

◆ xdg_defaults

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

Definition at line 70 of file muttlib.c.