NeoMutt  2021-02-05
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 "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

struct RegexC_GecosMask
 Config: Regex for parsing GECOS field of /etc/passwd. More...
 
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 90 of file muttlib.c.

91 {
92  if (!(buf->data && (buf->data[0] != '\0')))
93  {
94  mutt_buffer_mktemp(buf);
95  }
96  else
97  {
98  struct Buffer *prefix = mutt_buffer_pool_get();
99  mutt_buffer_strcpy(prefix, buf->data);
100  mutt_file_sanitize_filename(prefix->data, true);
101  mutt_buffer_printf(buf, "%s/%s", NONULL(C_Tmpdir), mutt_buffer_string(prefix));
102 
103  struct stat sb;
104  if ((lstat(mutt_buffer_string(buf), &sb) == -1) && (errno == ENOENT))
105  goto out;
106 
107  char *suffix = strchr(prefix->data, '.');
108  if (suffix)
109  {
110  *suffix = '\0';
111  suffix++;
112  }
113  mutt_buffer_mktemp_pfx_sfx(buf, prefix->data, suffix);
114 
115  out:
116  mutt_buffer_pool_release(&prefix);
117  }
118 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_buffer_mktemp_pfx_sfx(buf, prefix, suffix)
Definition: muttlib.h:78
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
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:618
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:56
+ 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 128 of file muttlib.c.

129 {
130  return mutt_expand_path_regex(buf, buflen, false);
131 }
char * mutt_expand_path_regex(char *buf, size_t buflen, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:337
+ 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 140 of file muttlib.c.

141 {
142  const char *s = NULL;
143  const char *tail = "";
144 
145  bool recurse = false;
146 
147  struct Buffer *p = mutt_buffer_pool_get();
148  struct Buffer *q = mutt_buffer_pool_get();
149  struct Buffer *tmp = mutt_buffer_pool_get();
150 
151  do
152  {
153  recurse = false;
154  s = mutt_buffer_string(buf);
155 
156  switch (*s)
157  {
158  case '~':
159  {
160  if ((s[1] == '/') || (s[1] == '\0'))
161  {
163  tail = s + 1;
164  }
165  else
166  {
167  char *t = strchr(s + 1, '/');
168  if (t)
169  *t = '\0';
170 
171  struct passwd *pw = getpwnam(s + 1);
172  if (pw)
173  {
174  mutt_buffer_strcpy(p, pw->pw_dir);
175  if (t)
176  {
177  *t = '/';
178  tail = t;
179  }
180  else
181  tail = "";
182  }
183  else
184  {
185  /* user not found! */
186  if (t)
187  *t = '/';
189  tail = s;
190  }
191  }
192  break;
193  }
194 
195  case '=':
196  case '+':
197  {
198  enum MailboxType mb_type = mx_path_probe(C_Folder);
199 
200  /* if folder = {host} or imap[s]://host/: don't append slash */
201  if ((mb_type == MUTT_IMAP) && ((C_Folder[strlen(C_Folder) - 1] == '}') ||
202  (C_Folder[strlen(C_Folder) - 1] == '/')))
203  {
205  }
206  else if (mb_type == MUTT_NOTMUCH)
208  else if (C_Folder && (C_Folder[strlen(C_Folder) - 1] == '/'))
210  else
211  mutt_buffer_printf(p, "%s/", NONULL(C_Folder));
212 
213  tail = s + 1;
214  break;
215  }
216 
217  /* elm compatibility, @ expands alias to user name */
218 
219  case '@':
220  {
221  struct AddressList *al = alias_lookup(s + 1);
222  if (al && !TAILQ_EMPTY(al))
223  {
224  struct Email *e = email_new();
225  e->env = mutt_env_new();
226  mutt_addrlist_copy(&e->env->from, al, false);
227  mutt_addrlist_copy(&e->env->to, al, false);
228 
229  /* TODO: fix mutt_default_save() to use Buffer */
231  mutt_default_save(p->data, p->dsize, e);
233 
234  email_free(&e);
235  /* Avoid infinite recursion if the resulting folder starts with '@' */
236  if (*p->data != '@')
237  recurse = true;
238 
239  tail = "";
240  }
241  break;
242  }
243 
244  case '>':
245  {
247  tail = s + 1;
248  break;
249  }
250 
251  case '<':
252  {
254  tail = s + 1;
255  break;
256  }
257 
258  case '!':
259  {
260  if (s[1] == '!')
261  {
263  tail = s + 2;
264  }
265  else
266  {
268  tail = s + 1;
269  }
270  break;
271  }
272 
273  case '-':
274  {
276  tail = s + 1;
277  break;
278  }
279 
280  case '^':
281  {
283  tail = s + 1;
284  break;
285  }
286 
287  default:
288  {
290  tail = s;
291  }
292  }
293 
294  if (regex && *(mutt_buffer_string(p)) && !recurse)
295  {
297  mutt_buffer_printf(tmp, "%s%s", mutt_buffer_string(q), tail);
298  }
299  else
300  mutt_buffer_printf(tmp, "%s%s", mutt_buffer_string(p), tail);
301 
302  mutt_buffer_copy(buf, tmp);
303  } while (recurse);
304 
308 
309 #ifdef USE_IMAP
310  /* Rewrite IMAP path in canonical form - aids in string comparisons of
311  * folders. May possibly fail, in which case buf should be the same. */
312  if (imap_path_probe(mutt_buffer_string(buf), NULL) == MUTT_IMAP)
313  imap_expand_path(buf);
314 #endif
315 }
#define NONULL(x)
Definition: string2.h:37
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
The envelope/body of an email.
Definition: email.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void email_free(struct Email **ptr)
Free an Email.
Definition: email.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:2367
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer&#39;s contents to another Buffer.
Definition: buffer.c:445
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
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
String manipulation buffer.
Definition: buffer.h:33
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:654
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:49
struct Email * email_new(void)
Create a new Email.
Definition: email.c:72
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
size_t dsize
Length of data.
Definition: buffer.h:37
int imap_expand_path(struct Buffer *buf)
Buffer wrapper around imap_path_canon()
Definition: imap.c:2407
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:276
struct Envelope * env
Envelope information.
Definition: email.h:90
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition: file.c:637
#define PATH_MAX
Definition: mutt.h:44
char * data
Pointer to data.
Definition: buffer.h:35
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
WHERE char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
WHERE char * C_Record
Config: Folder to save &#39;sent&#39; messages.
Definition: mutt_globals.h:98
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1336
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
WHERE char * C_Spoolfile
Config: Inbox.
Definition: mutt_globals.h:108
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:714
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
WHERE char * C_Mbox
Config: Folder that receives read emails (see Move)
Definition: mutt_globals.h:94
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
+ 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 323 of file muttlib.c.

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

338 {
339  struct Buffer *tmp = mutt_buffer_pool_get();
340 
341  mutt_buffer_addstr(tmp, NONULL(buf));
342  mutt_buffer_expand_path_regex(tmp, regex);
343  mutt_str_copy(buf, mutt_buffer_string(tmp), buflen);
344 
346 
347  return buf;
348 }
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
void mutt_buffer_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:140
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
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:716
+ 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 362 of file muttlib.c.

363 {
364  regmatch_t pat_match[1];
365  size_t pwnl;
366  char *p = NULL;
367 
368  if (!pw || !pw->pw_gecos)
369  return NULL;
370 
371  memset(dest, 0, destlen);
372 
373  if (mutt_regex_capture(C_GecosMask, pw->pw_gecos, 1, pat_match))
374  {
375  mutt_str_copy(dest, pw->pw_gecos + pat_match[0].rm_so,
376  MIN(pat_match[0].rm_eo - pat_match[0].rm_so + 1, destlen));
377  }
378  else if ((p = strchr(pw->pw_gecos, ',')))
379  mutt_str_copy(dest, pw->pw_gecos, MIN(destlen, p - pw->pw_gecos + 1));
380  else
381  mutt_str_copy(dest, pw->pw_gecos, destlen);
382 
383  pwnl = strlen(pw->pw_name);
384 
385  for (int idx = 0; dest[idx]; idx++)
386  {
387  if (dest[idx] == '&')
388  {
389  memmove(&dest[idx + pwnl], &dest[idx + 1],
390  MAX((ssize_t)(destlen - idx - pwnl - 1), 0));
391  memcpy(&dest[idx], pw->pw_name, MIN(destlen - idx - 1, pwnl));
392  dest[idx] = toupper((unsigned char) dest[idx]);
393  }
394  }
395 
396  return dest;
397 }
#define MIN(a, b)
Definition: memory.h:31
#define MAX(a, b)
Definition: memory.h:30
struct Regex * C_GecosMask
Config: Regex for parsing GECOS field of /etc/passwd.
Definition: muttlib.c:70
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:595
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:716
+ 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 405 of file muttlib.c.

406 {
407  switch (m->type)
408  {
409  case TYPE_TEXT:
410  if (mutt_istr_equal("plain", m->subtype))
411  return false;
412  break;
413  case TYPE_APPLICATION:
415  return false;
417  return false;
418  break;
419 
420  case TYPE_MULTIPART:
421  case TYPE_MESSAGE:
422  return false;
423  }
424 
425  return true;
426 }
#define WithCrypto
Definition: lib.h:123
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
char * subtype
content-type subtype
Definition: body.h:37
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:98
SecurityFlags mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:552
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
Type: &#39;text/*&#39;.
Definition: mime.h:38
SecurityFlags mutt_is_application_smime(struct Body *m)
Does the message use S/MIME?
Definition: crypt.c:610
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Type: &#39;application/*&#39;.
Definition: mime.h:33
+ 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
trueIf part is in plain text

Definition at line 433 of file muttlib.c.

434 {
435  int t = b->type;
436  char *s = b->subtype;
437 
439  return false;
440 
441  if (t == TYPE_TEXT)
442  return true;
443 
444  if (t == TYPE_MESSAGE)
445  {
446  if (mutt_istr_equal("delivery-status", s))
447  return true;
448  }
449 
450  if (((WithCrypto & APPLICATION_PGP) != 0) && (t == TYPE_APPLICATION))
451  {
452  if (mutt_istr_equal("pgp-keys", s))
453  return true;
454  }
455 
456  return false;
457 }
#define WithCrypto
Definition: lib.h:123
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
char * subtype
content-type subtype
Definition: body.h:37
SecurityFlags mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:552
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
Type: &#39;text/*&#39;.
Definition: mime.h:38
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
Type: &#39;application/*&#39;.
Definition: mime.h:33
+ 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 467 of file muttlib.c.

469 {
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 NONULL(x)
Definition: string2.h:37
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
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:129
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
Log at debug level 1.
Definition: logging.h:40
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:56
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:42
+ 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  size_t n =
498  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  {
504  "%s:%d: ERROR: insufficient buffer space to hold temporary "
505  "filename! buflen=%zu but need %zu\n",
506  src, line, buflen, n);
507  }
508  mutt_debug(LL_DEBUG3, "%s:%d: mutt_mktemp returns \"%s\"\n", src, line, buf);
509  if ((unlink(buf) != 0) && (errno != ENOENT))
510  {
511  mutt_debug(LL_DEBUG1, "%s:%d: ERROR: unlink(\"%s\"): %s (errno %d)\n", src,
512  line, buf, strerror(errno), errno);
513  }
514 }
#define NONULL(x)
Definition: string2.h:37
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:129
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
Log at debug level 1.
Definition: logging.h:40
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:56
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:42
+ 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 523 of file muttlib.c.

524 {
525  if (!buf)
526  return;
527 
528  char *p = buf, *q = buf;
529  size_t len;
530  enum UrlScheme scheme;
531  char tmp[PATH_MAX];
532 
533  scheme = url_check_scheme(buf);
534 
535  if ((scheme == U_IMAP) || (scheme == U_IMAPS))
536  {
537  imap_pretty_mailbox(buf, buflen, C_Folder);
538  return;
539  }
540 
541  if (scheme == U_NOTMUCH)
542  return;
543 
544  /* if buf is an url, only collapse path component */
545  if (scheme != U_UNKNOWN)
546  {
547  p = strchr(buf, ':') + 1;
548  if (mutt_strn_equal(p, "//", 2))
549  q = strchr(p + 2, '/');
550  if (!q)
551  q = strchr(p, '\0');
552  p = q;
553  }
554 
555  /* cleanup path */
556  if (strstr(p, "//") || strstr(p, "/./"))
557  {
558  /* first attempt to collapse the pathname, this is more
559  * lightweight than realpath() and doesn't resolve links */
560  while (*p)
561  {
562  if ((p[0] == '/') && (p[1] == '/'))
563  {
564  *q++ = '/';
565  p += 2;
566  }
567  else if ((p[0] == '/') && (p[1] == '.') && (p[2] == '/'))
568  {
569  *q++ = '/';
570  p += 3;
571  }
572  else
573  *q++ = *p++;
574  }
575  *q = '\0';
576  }
577  else if (strstr(p, "..") && ((scheme == U_UNKNOWN) || (scheme == U_FILE)) &&
578  realpath(p, tmp))
579  {
580  mutt_str_copy(p, tmp, buflen - (p - buf));
581  }
582 
583  if ((len = mutt_str_startswith(buf, C_Folder)) && (buf[len] == '/'))
584  {
585  *buf++ = '=';
586  memmove(buf, buf + len, mutt_str_len(buf + len) + 1);
587  }
588  else if ((len = mutt_str_startswith(buf, HomeDir)) && (buf[len] == '/'))
589  {
590  *buf++ = '~';
591  memmove(buf, buf + len - 1, mutt_str_len(buf + len - 1) + 1);
592  }
593 }
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:221
Url is notmuch://.
Definition: url.h:45
Url is imaps://.
Definition: url.h:39
Url wasn&#39;t recognised.
Definition: url.h:34
void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
Prettify an IMAP mailbox name.
Definition: util.c:726
Url is imap://.
Definition: url.h:38
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:49
UrlScheme
All recognised Url types.
Definition: url.h:32
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
#define PATH_MAX
Definition: mutt.h:44
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
bool mutt_strn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:593
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
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:716
Url is file://.
Definition: url.h:35
+ 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 599 of file muttlib.c.

600 {
601  if (!buf || !buf->data)
602  return;
603  /* This reduces the size of the Buffer, so we can pass it through.
604  * We adjust the size just to make sure buf->data is not NULL though */
606  mutt_pretty_mailbox(buf->data, buf->dsize);
608 }
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:523
size_t dsize
Length of data.
Definition: buffer.h:37
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
#define PATH_MAX
Definition: mutt.h:44
char * data
Pointer to data.
Definition: buffer.h:35
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
+ 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 621 of file muttlib.c.

623 {
624  struct stat st;
625 
626  mutt_buffer_strcpy(fname, path);
627  if (access(mutt_buffer_string(fname), F_OK) != 0)
628  return 0;
629  if (stat(mutt_buffer_string(fname), &st) != 0)
630  return -1;
631  if (S_ISDIR(st.st_mode))
632  {
633  enum QuadOption ans = MUTT_NO;
634  if (directory)
635  {
636  switch (mutt_multi_choice
637  /* L10N: Means "The path you specified as the destination file is a directory."
638  See the msgid "Save to file: " (alias.c, recvattach.c)
639  These three letters correspond to the choices in the string. */
640  (_("File is a directory, save under it: (y)es, (n)o, (a)ll?"), _("yna")))
641  {
642  case 3: /* all */
643  mutt_str_replace(directory, mutt_buffer_string(fname));
644  break;
645  case 1: /* yes */
646  FREE(directory);
647  break;
648  case -1: /* abort */
649  FREE(directory);
650  return -1;
651  case 2: /* no */
652  FREE(directory);
653  return 1;
654  }
655  }
656  /* L10N: Means "The path you specified as the destination file is a directory."
657  See the msgid "Save to file: " (alias.c, recvattach.c) */
658  else if ((ans = mutt_yesorno(_("File is a directory, save under it?"), MUTT_YES)) != MUTT_YES)
659  return (ans == MUTT_NO) ? 1 : -1;
660 
661  struct Buffer *tmp = mutt_buffer_pool_get();
663  if ((mutt_buffer_get_field(_("File under directory: "), tmp, MUTT_FILE | MUTT_CLEAR) != 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  switch (
676  mutt_multi_choice(_("File exists, (o)verwrite, (a)ppend, or (c)ancel?"),
677  // L10N: Options for: File exists, (o)verwrite, (a)ppend, or (c)ancel?
678  _("oac")))
679  {
680  case -1: /* abort */
681  return -1;
682  case 3: /* cancel */
683  return 1;
684 
685  case 2: /* append */
686  *opt = MUTT_SAVE_APPEND;
687  break;
688  case 1: /* overwrite */
689  *opt = MUTT_SAVE_OVERWRITE;
690  break;
691  }
692  }
693  return 0;
694 }
#define NONULL(x)
Definition: string2.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:329
No flags set.
Definition: mutt_attach.h:56
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
Overwrite existing file.
Definition: mutt_attach.h:58
#define _(a)
Definition: message.h:28
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:379
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:933
#define MUTT_FILE
Do file completion.
Definition: mutt.h:58
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
#define mutt_buffer_get_field(field, buf, complete)
Definition: curs_lib.h:85
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
Append to existing file.
Definition: mutt_attach.h:57
#define FREE(x)
Definition: memory.h:40
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
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.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 705 of file muttlib.c.

706 {
707  if (addr && addr->mailbox)
708  {
709  mutt_str_copy(buf, addr->mailbox, buflen);
710  if (!C_SaveAddress)
711  {
712  char *p = strpbrk(buf, "%@");
713  if (p)
714  *p = '\0';
715  }
716  mutt_str_lower(buf);
717  }
718  else
719  *buf = '\0';
720 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
char * mutt_str_lower(char *s)
Convert all characters in the string to lowercase.
Definition: string.c:504
WHERE bool C_SaveAddress
Config: Use sender&#39;s full address as a default save folder.
Definition: mutt_globals.h:157
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:716
+ 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 727 of file muttlib.c.

728 {
729  if (a && a->mailbox)
730  {
731  mutt_buffer_strcpy(dest, a->mailbox);
732  if (!C_SaveAddress)
733  {
734  char *p = strpbrk(dest->data, "%@");
735  if (p)
736  {
737  *p = '\0';
738  mutt_buffer_fix_dptr(dest);
739  }
740  }
741  mutt_str_lower(dest->data);
742  }
743  else
744  mutt_buffer_reset(dest);
745 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
char * mailbox
Mailbox and host address.
Definition: address.h:37
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
char * mutt_str_lower(char *s)
Convert all characters in the string to lowercase.
Definition: string.c:504
WHERE bool C_SaveAddress
Config: Use sender&#39;s full address as a default save folder.
Definition: mutt_globals.h:157
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
+ 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 754 of file muttlib.c.

755 {
756  mutt_buffer_save_path(dest, a);
757  for (char *p = dest->data; *p; p++)
758  if ((*p == '/') || IS_SPACE(*p) || !IsPrint((unsigned char) *p))
759  *p = '_';
760 }
void mutt_buffer_save_path(struct Buffer *dest, const struct Address *a)
Make a safe filename from an email address.
Definition: muttlib.c:727
#define IsPrint(ch)
Definition: mbyte.h:39
char * data
Pointer to data.
Definition: buffer.h:35
#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_expando_format()

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.

Parameters
[out]bufBuffer in which to save string
[in]buflenBuffer length
[in]colStarting column
[in]colsNumber of screen columns
[in]srcPrintf-like format string
[in]callbackCallback - Implements format_t
[in]dataCallback data
[in]flagsCallback flags

Definition at line 773 of file muttlib.c.

775 {
776  char prefix[128], tmp[1024];
777  char *cp = NULL, *wptr = buf;
778  char ch;
779  char if_str[128], else_str[128];
780  size_t wlen, count, len, wid;
781  FILE *fp_filter = NULL;
782  char *recycler = NULL;
783 
784  char src2[256];
785  mutt_str_copy(src2, src, mutt_str_len(src) + 1);
786  src = src2;
787 
788  prefix[0] = '\0';
789  buflen--; /* save room for the terminal \0 */
790  wlen = ((flags & MUTT_FORMAT_ARROWCURSOR) && C_ArrowCursor) ?
792  0;
793  col += wlen;
794 
795  if ((flags & MUTT_FORMAT_NOFILTER) == 0)
796  {
797  int off = -1;
798 
799  /* Do not consider filters if no pipe at end */
800  int n = mutt_str_len(src);
801  if ((n > 1) && (src[n - 1] == '|'))
802  {
803  /* Scan backwards for backslashes */
804  off = n;
805  while ((off > 0) && (src[off - 2] == '\\'))
806  off--;
807  }
808 
809  /* If number of backslashes is even, the pipe is real. */
810  /* n-off is the number of backslashes. */
811  if ((off > 0) && (((n - off) % 2) == 0))
812  {
813  char srccopy[1024];
814  int i = 0;
815 
816  mutt_debug(LL_DEBUG3, "fmtpipe = %s\n", src);
817 
818  strncpy(srccopy, src, n);
819  srccopy[n - 1] = '\0';
820 
821  /* prepare Buffers */
822  struct Buffer srcbuf = mutt_buffer_make(0);
823  mutt_buffer_addstr(&srcbuf, srccopy);
824  /* note: we are resetting dptr and *reading* from the buffer, so we don't
825  * want to use mutt_buffer_reset(). */
826  mutt_buffer_seek(&srcbuf, 0);
827  struct Buffer word = mutt_buffer_make(0);
828  struct Buffer cmd = mutt_buffer_make(0);
829 
830  /* Iterate expansions across successive arguments */
831  do
832  {
833  /* Extract the command name and copy to command line */
834  mutt_debug(LL_DEBUG3, "fmtpipe +++: %s\n", srcbuf.dptr);
835  if (word.data)
836  *word.data = '\0';
837  mutt_extract_token(&word, &srcbuf, MUTT_TOKEN_NO_FLAGS);
838  mutt_debug(LL_DEBUG3, "fmtpipe %2d: %s\n", i++, word.data);
839  mutt_buffer_addch(&cmd, '\'');
840  mutt_expando_format(tmp, sizeof(tmp), 0, cols, word.data, callback,
841  data, flags | MUTT_FORMAT_NOFILTER);
842  for (char *p = tmp; p && (*p != '\0'); p++)
843  {
844  if (*p == '\'')
845  {
846  /* shell quoting doesn't permit escaping a single quote within
847  * single-quoted material. double-quoting instead will lead
848  * shell variable expansions, so break out of the single-quoted
849  * span, insert a double-quoted single quote, and resume. */
850  mutt_buffer_addstr(&cmd, "'\"'\"'");
851  }
852  else
853  mutt_buffer_addch(&cmd, *p);
854  }
855  mutt_buffer_addch(&cmd, '\'');
856  mutt_buffer_addch(&cmd, ' ');
857  } while (MoreArgs(&srcbuf));
858 
859  mutt_debug(LL_DEBUG3, "fmtpipe > %s\n", cmd.data);
860 
861  col -= wlen; /* reset to passed in value */
862  wptr = buf; /* reset write ptr */
863  pid_t pid = filter_create(cmd.data, NULL, &fp_filter, NULL);
864  if (pid != -1)
865  {
866  int rc;
867 
868  n = fread(buf, 1, buflen /* already decremented */, fp_filter);
869  mutt_file_fclose(&fp_filter);
870  rc = filter_wait(pid);
871  if (rc != 0)
872  mutt_debug(LL_DEBUG1, "format pipe cmd exited code %d\n", rc);
873  if (n > 0)
874  {
875  buf[n] = '\0';
876  while ((n > 0) && ((buf[n - 1] == '\n') || (buf[n - 1] == '\r')))
877  buf[--n] = '\0';
878  mutt_debug(LL_DEBUG5, "fmtpipe < %s\n", buf);
879 
880  /* If the result ends with '%', this indicates that the filter
881  * generated %-tokens that neomutt can expand. Eliminate the '%'
882  * marker and recycle the string through mutt_expando_format().
883  * To literally end with "%", use "%%". */
884  if ((n > 0) && (buf[n - 1] == '%'))
885  {
886  n--;
887  buf[n] = '\0'; /* remove '%' */
888  if ((n > 0) && (buf[n - 1] != '%'))
889  {
890  recycler = mutt_str_dup(buf);
891  if (recycler)
892  {
893  /* buflen is decremented at the start of this function
894  * to save space for the terminal nul char. We can add
895  * it back for the recursive call since the expansion of
896  * format pipes does not try to append a nul itself. */
897  mutt_expando_format(buf, buflen + 1, col, cols, recycler,
898  callback, data, flags);
899  FREE(&recycler);
900  }
901  }
902  }
903  }
904  else
905  {
906  /* read error */
907  mutt_debug(LL_DEBUG1, "error reading from fmtpipe: %s (errno=%d)\n",
908  strerror(errno), errno);
909  *wptr = '\0';
910  }
911  }
912  else
913  {
914  /* Filter failed; erase write buffer */
915  *wptr = '\0';
916  }
917 
918  mutt_buffer_dealloc(&cmd);
919  mutt_buffer_dealloc(&srcbuf);
920  mutt_buffer_dealloc(&word);
921  return;
922  }
923  }
924 
925  while (*src && (wlen < buflen))
926  {
927  if (*src == '%')
928  {
929  if (*++src == '%')
930  {
931  *wptr++ = '%';
932  wlen++;
933  col++;
934  src++;
935  continue;
936  }
937 
938  if (*src == '?')
939  {
940  /* change original %? to new %< notation */
941  /* %?x?y&z? to %<x?y&z> where y and z are nestable */
942  char *p = (char *) src;
943  *p = '<';
944  /* skip over "x" */
945  for (; *p && (*p != '?'); p++)
946  ; // do nothing
947 
948  /* nothing */
949  if (*p == '?')
950  p++;
951  /* fix up the "y&z" section */
952  for (; *p && (*p != '?'); p++)
953  {
954  /* escape '<' and '>' to work inside nested-if */
955  if ((*p == '<') || (*p == '>'))
956  {
957  memmove(p + 2, p, mutt_str_len(p) + 1);
958  *p++ = '\\';
959  *p++ = '\\';
960  }
961  }
962  if (*p == '?')
963  *p = '>';
964  }
965 
966  if (*src == '<')
967  {
968  flags |= MUTT_FORMAT_OPTIONAL;
969  ch = *(++src); /* save the character to switch on */
970  src++;
971  cp = prefix;
972  count = 0;
973  while ((count < sizeof(prefix)) && (*src != '?'))
974  {
975  *cp++ = *src++;
976  count++;
977  }
978  *cp = '\0';
979  }
980  else
981  {
982  flags &= ~MUTT_FORMAT_OPTIONAL;
983 
984  /* eat the format string */
985  cp = prefix;
986  count = 0;
987  while ((count < sizeof(prefix)) && (isdigit((unsigned char) *src) || (*src == '.') ||
988  (*src == '-') || (*src == '=')))
989  {
990  *cp++ = *src++;
991  count++;
992  }
993  *cp = '\0';
994 
995  if (*src == '\0')
996  break; /* bad format */
997 
998  ch = *src++; /* save the character to switch on */
999  }
1000 
1001  if (flags & MUTT_FORMAT_OPTIONAL)
1002  {
1003  int lrbalance;
1004 
1005  if (*src != '?')
1006  break; /* bad format */
1007  src++;
1008 
1009  /* eat the 'if' part of the string */
1010  cp = if_str;
1011  count = 0;
1012  lrbalance = 1;
1013  while ((lrbalance > 0) && (count < sizeof(if_str)) && *src)
1014  {
1015  if ((src[0] == '%') && (src[1] == '>'))
1016  {
1017  /* This is a padding expando; copy two chars and carry on */
1018  *cp++ = *src++;
1019  *cp++ = *src++;
1020  count += 2;
1021  continue;
1022  }
1023 
1024  if (*src == '\\')
1025  {
1026  src++;
1027  *cp++ = *src++;
1028  }
1029  else if ((src[0] == '%') && (src[1] == '<'))
1030  {
1031  lrbalance++;
1032  }
1033  else if (src[0] == '>')
1034  {
1035  lrbalance--;
1036  }
1037  if (lrbalance == 0)
1038  break;
1039  if ((lrbalance == 1) && (src[0] == '&'))
1040  break;
1041  *cp++ = *src++;
1042  count++;
1043  }
1044  *cp = '\0';
1045 
1046  /* eat the 'else' part of the string (optional) */
1047  if (*src == '&')
1048  src++; /* skip the & */
1049  cp = else_str;
1050  count = 0;
1051  while ((lrbalance > 0) && (count < sizeof(else_str)) && (*src != '\0'))
1052  {
1053  if ((src[0] == '%') && (src[1] == '>'))
1054  {
1055  /* This is a padding expando; copy two chars and carry on */
1056  *cp++ = *src++;
1057  *cp++ = *src++;
1058  count += 2;
1059  continue;
1060  }
1061 
1062  if (*src == '\\')
1063  {
1064  src++;
1065  *cp++ = *src++;
1066  }
1067  else if ((src[0] == '%') && (src[1] == '<'))
1068  {
1069  lrbalance++;
1070  }
1071  else if (src[0] == '>')
1072  {
1073  lrbalance--;
1074  }
1075  if (lrbalance == 0)
1076  break;
1077  if ((lrbalance == 1) && (src[0] == '&'))
1078  break;
1079  *cp++ = *src++;
1080  count++;
1081  }
1082  *cp = '\0';
1083 
1084  if ((*src == '\0'))
1085  break; /* bad format */
1086 
1087  src++; /* move past the trailing '>' (formerly '?') */
1088  }
1089 
1090  /* handle generic cases first */
1091  if ((ch == '>') || (ch == '*'))
1092  {
1093  /* %>X: right justify to EOL, left takes precedence
1094  * %*X: right justify to EOL, right takes precedence */
1095  int soft = ch == '*';
1096  int pl, pw;
1097  pl = mutt_mb_charlen(src, &pw);
1098  if (pl <= 0)
1099  {
1100  pl = 1;
1101  pw = 1;
1102  }
1103 
1104  /* see if there's room to add content, else ignore */
1105  if (((col < cols) && (wlen < buflen)) || soft)
1106  {
1107  int pad;
1108 
1109  /* get contents after padding */
1110  mutt_expando_format(tmp, sizeof(tmp), 0, cols, src + pl, callback, data, flags);
1111  len = mutt_str_len(tmp);
1112  wid = mutt_strwidth(tmp);
1113 
1114  pad = (cols - col - wid) / pw;
1115  if (pad >= 0)
1116  {
1117  /* try to consume as many columns as we can, if we don't have
1118  * memory for that, use as much memory as possible */
1119  if (wlen + (pad * pl) + len > buflen)
1120  pad = (buflen > (wlen + len)) ? ((buflen - wlen - len) / pl) : 0;
1121  else
1122  {
1123  /* Add pre-spacing to make multi-column pad characters and
1124  * the contents after padding line up */
1125  while (((col + (pad * pw) + wid) < cols) && ((wlen + (pad * pl) + len) < buflen))
1126  {
1127  *wptr++ = ' ';
1128  wlen++;
1129  col++;
1130  }
1131  }
1132  while (pad-- > 0)
1133  {
1134  memcpy(wptr, src, pl);
1135  wptr += pl;
1136  wlen += pl;
1137  col += pw;
1138  }
1139  }
1140  else if (soft)
1141  {
1142  int offset = ((flags & MUTT_FORMAT_ARROWCURSOR) && C_ArrowCursor) ?
1144  0;
1145  int avail_cols = (cols > offset) ? (cols - offset) : 0;
1146  /* \0-terminate buf for length computation in mutt_wstr_trunc() */
1147  *wptr = '\0';
1148  /* make sure right part is at most as wide as display */
1149  len = mutt_wstr_trunc(tmp, buflen, avail_cols, &wid);
1150  /* truncate left so that right part fits completely in */
1151  wlen = mutt_wstr_trunc(buf, buflen - len, avail_cols - wid, &col);
1152  wptr = buf + wlen;
1153  /* Multi-column characters may be truncated in the middle.
1154  * Add spacing so the right hand side lines up. */
1155  while (((col + wid) < avail_cols) && ((wlen + len) < buflen))
1156  {
1157  *wptr++ = ' ';
1158  wlen++;
1159  col++;
1160  }
1161  }
1162  if ((len + wlen) > buflen)
1163  len = mutt_wstr_trunc(tmp, buflen - wlen, cols - col, NULL);
1164  memcpy(wptr, tmp, len);
1165  wptr += len;
1166  }
1167  break; /* skip rest of input */
1168  }
1169  else if (ch == '|')
1170  {
1171  /* pad to EOL */
1172  int pl, pw;
1173  pl = mutt_mb_charlen(src, &pw);
1174  if (pl <= 0)
1175  {
1176  pl = 1;
1177  pw = 1;
1178  }
1179 
1180  /* see if there's room to add content, else ignore */
1181  if ((col < cols) && (wlen < buflen))
1182  {
1183  int c = (cols - col) / pw;
1184  if ((c > 0) && ((wlen + (c * pl)) > buflen))
1185  c = ((signed) (buflen - wlen)) / pl;
1186  while (c > 0)
1187  {
1188  memcpy(wptr, src, pl);
1189  wptr += pl;
1190  wlen += pl;
1191  col += pw;
1192  c--;
1193  }
1194  }
1195  break; /* skip rest of input */
1196  }
1197  else
1198  {
1199  bool to_lower = false;
1200  bool no_dots = false;
1201 
1202  while ((ch == '_') || (ch == ':'))
1203  {
1204  if (ch == '_')
1205  to_lower = true;
1206  else if (ch == ':')
1207  no_dots = true;
1208 
1209  ch = *src++;
1210  }
1211 
1212  /* use callback function to handle this case */
1213  *tmp = '\0';
1214  src = callback(tmp, sizeof(tmp), col, cols, ch, src, prefix, if_str,
1215  else_str, data, flags);
1216 
1217  if (to_lower)
1218  mutt_str_lower(tmp);
1219  if (no_dots)
1220  {
1221  char *p = tmp;
1222  for (; *p; p++)
1223  if (*p == '.')
1224  *p = '_';
1225  }
1226 
1227  len = mutt_str_len(tmp);
1228  if ((len + wlen) > buflen)
1229  len = mutt_wstr_trunc(tmp, buflen - wlen, cols - col, NULL);
1230 
1231  memcpy(wptr, tmp, len);
1232  wptr += len;
1233  wlen += len;
1234  col += mutt_strwidth(tmp);
1235  }
1236  }
1237  else if (*src == '\\')
1238  {
1239  if (!*++src)
1240  break;
1241  switch (*src)
1242  {
1243  case 'f':
1244  *wptr = '\f';
1245  break;
1246  case 'n':
1247  *wptr = '\n';
1248  break;
1249  case 'r':
1250  *wptr = '\r';
1251  break;
1252  case 't':
1253  *wptr = '\t';
1254  break;
1255  case 'v':
1256  *wptr = '\v';
1257  break;
1258  default:
1259  *wptr = *src;
1260  break;
1261  }
1262  src++;
1263  wptr++;
1264  wlen++;
1265  col++;
1266  }
1267  else
1268  {
1269  int bytes, width;
1270  /* in case of error, simply copy byte */
1271  bytes = mutt_mb_charlen(src, &width);
1272  if (bytes < 0)
1273  {
1274  bytes = 1;
1275  width = 1;
1276  }
1277  if ((bytes > 0) && ((wlen + bytes) < buflen))
1278  {
1279  memcpy(wptr, src, bytes);
1280  wptr += bytes;
1281  src += bytes;
1282  wlen += bytes;
1283  col += width;
1284  }
1285  else
1286  {
1287  src += buflen - wlen;
1288  wlen = buflen;
1289  }
1290  }
1291  }
1292  *wptr = '\0';
1293 }
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
int mutt_mb_charlen(const char *s, int *width)
Count the bytes in a (multibyte) character.
Definition: mbyte.c:55
#define MoreArgs(buf)
Definition: buffer.h:40
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
char * mutt_str_lower(char *s)
Convert all characters in the string to lowercase.
Definition: string.c:504
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1359
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:395
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
Work out how to truncate a widechar string.
Definition: curs_lib.c:1309
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
WHERE bool C_ArrowCursor
Config: Use an arrow &#39;->&#39; instead of highlighting in the index.
Definition: mutt_globals.h:131
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
Log at debug level 1.
Definition: logging.h:40
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:716
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.
Definition: muttlib.c:773
#define FREE(x)
Definition: memory.h:40
#define MUTT_FORMAT_NOFILTER
Do not allow filtering on this pass.
Definition: format_flags.h:37
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
void mutt_buffer_seek(struct Buffer *buf, size_t offset)
set current read/write position to offset from beginning
Definition: buffer.c:466
Log at debug level 5.
Definition: logging.h:44
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
static int pad(FILE *fp, int col, int i)
Write some padding to a file.
Definition: help.c:198
Log at debug level 3.
Definition: logging.h:42
WHERE char * C_ArrowString
Config: Use an custom string for arrow_cursor.
Definition: mutt_globals.h:132
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:70
+ 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 1305 of file muttlib.c.

1306 {
1307  FILE *fp = NULL;
1308  struct stat s;
1309 
1310  size_t len = mutt_str_len(path);
1311  if (len == 0)
1312  {
1313  return NULL;
1314  }
1315 
1316  if (path[len - 1] == '|')
1317  {
1318  /* read from a pipe */
1319 
1320  char *p = mutt_str_dup(path);
1321 
1322  p[len - 1] = 0;
1323  mutt_endwin();
1324  *thepid = filter_create(p, NULL, &fp, NULL);
1325  FREE(&p);
1326  }
1327  else
1328  {
1329  if (stat(path, &s) < 0)
1330  return NULL;
1331  if (S_ISDIR(s.st_mode))
1332  {
1333  errno = EINVAL;
1334  return NULL;
1335  }
1336  fp = fopen(path, "r");
1337  *thepid = -1;
1338  }
1339  return fp;
1340 }
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:370
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:571
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
#define FREE(x)
Definition: memory.h:40
+ 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
0if OK to proceed
-1to abort
1to retry

Definition at line 1350 of file muttlib.c.

1351 {
1352  int ret = 0;
1353 
1354  enum MailboxType type = mx_path_probe(s);
1355 
1356 #ifdef USE_POP
1357  if (type == MUTT_POP)
1358  {
1359  mutt_error(_("Can't save message to POP mailbox"));
1360  return 1;
1361  }
1362 #endif
1363 
1364  if ((type != MUTT_MAILBOX_ERROR) && (type != MUTT_UNKNOWN) && (mx_access(s, W_OK) == 0))
1365  {
1366  if (C_Confirmappend)
1367  {
1368  struct Buffer *tmp = mutt_buffer_pool_get();
1369  mutt_buffer_printf(tmp, _("Append messages to %s?"), s);
1371  if (ans == MUTT_NO)
1372  ret = 1;
1373  else if (ans == MUTT_ABORT)
1374  ret = -1;
1376  }
1377  }
1378 
1379 #ifdef USE_NNTP
1380  if (type == MUTT_NNTP)
1381  {
1382  mutt_error(_("Can't save message to news server"));
1383  return 0;
1384  }
1385 #endif
1386 
1387  if (stat(s, st) != -1)
1388  {
1389  if (type == MUTT_MAILBOX_ERROR)
1390  {
1391  mutt_error(_("%s is not a mailbox"), s);
1392  return 1;
1393  }
1394  }
1395  else if (type != MUTT_IMAP)
1396  {
1397  st->st_mtime = 0;
1398  st->st_atime = 0;
1399 
1400  /* pathname does not exist */
1401  if (errno == ENOENT)
1402  {
1403  if (C_Confirmcreate)
1404  {
1405  struct Buffer *tmp = mutt_buffer_pool_get();
1406  mutt_buffer_printf(tmp, _("Create %s?"), s);
1408  if (ans == MUTT_NO)
1409  ret = 1;
1410  else if (ans == MUTT_ABORT)
1411  ret = -1;
1413  }
1414 
1415  /* user confirmed with MUTT_YES or set `$confirmcreate` */
1416  if (ret == 0)
1417  {
1418  /* create dir recursively */
1419  char *tmp_path = mutt_path_dirname(s);
1420  if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1)
1421  {
1422  /* report failure & abort */
1423  mutt_perror(s);
1424  FREE(&tmp_path);
1425  return 1;
1426  }
1427  FREE(&tmp_path);
1428  }
1429  }
1430  else
1431  {
1432  mutt_perror(s);
1433  return 1;
1434  }
1435  }
1436 
1438  return ret;
1439 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_perror(...)
Definition: logging.h:85
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
char * mutt_path_dirname(const char *path)
Return a path up to, but not including, the final &#39;/&#39;.
Definition: path.c:376
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
Error occurred examining Mailbox.
Definition: mailbox.h:46
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:379
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:875
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:232
User aborted the question (with Ctrl-G)
Definition: quad.h:38
&#39;POP3&#39; Mailbox type
Definition: mailbox.h:55
struct MuttWindow * MessageWindow
Message Window, ":set", etc.
Definition: mutt_window.c:47
WHERE bool C_Confirmcreate
Config: Confirm before creating a new mailbox.
Definition: mutt_globals.h:142
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1336
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
#define mutt_error(...)
Definition: logging.h:84
#define FREE(x)
Definition: memory.h:40
int mx_access(const char *path, int flags)
Wrapper for access, checks permissions on a given mailbox.
Definition: mx.c:183
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
WHERE bool C_Confirmappend
Config: Confirm before appending emails to a mailbox.
Definition: mutt_globals.h:141
+ 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 1447 of file muttlib.c.

1448 {
1449  if (C_SleepTime > s)
1450  sleep(C_SleepTime);
1451  else if (s)
1452  sleep(s);
1453 }
WHERE short C_SleepTime
Config: Time to pause after certain info messages.
Definition: mutt_globals.h:114
+ 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 1461 of file muttlib.c.

1462 {
1463  static char vstring[256];
1464  snprintf(vstring, sizeof(vstring), "NeoMutt %s%s", PACKAGE_VERSION, GitVer);
1465  return vstring;
1466 }
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 1475 of file muttlib.c.

1476 {
1477  char *p = mutt_str_dup(src);
1478  int rc = mutt_ch_convert_string(&p, C_Charset, "us-ascii", MUTT_ICONV_NO_FLAGS);
1479  size_t len = mutt_buffer_strcpy(buf, (rc == 0) ? NONULL(p) : NONULL(src));
1480 
1481  /* convert the path to POSIX "Portable Filename Character Set" */
1482  for (size_t i = 0; i < len; i++)
1483  {
1484  if (!isalnum(buf->data[i]) && !strchr("/.-_", buf->data[i]))
1485  {
1486  buf->data[i] = '_';
1487  }
1488  }
1489  FREE(&p);
1490 }
#define NONULL(x)
Definition: string2.h:37
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:754
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:73
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
#define FREE(x)
Definition: memory.h:40
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:53
+ 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
1if an entry was found that actually exists on disk and 0 otherwise

Process an XDG environment variable or its fallback.

Definition at line 1500 of file muttlib.c.

1501 {
1502  const char *xdg_env = mutt_str_getenv(xdg_env_vars[type]);
1503  char *xdg = xdg_env ? mutt_str_dup(xdg_env) : mutt_str_dup(xdg_defaults[type]);
1504  char *x = xdg; /* strsep() changes xdg, so free x instead later */
1505  char *token = NULL;
1506  int rc = 0;
1507 
1508  while ((token = strsep(&xdg, ":")))
1509  {
1510  if (mutt_buffer_printf(buf, "%s/%s/neomuttrc", token, PACKAGE) < 0)
1511  continue;
1513  if (access(mutt_buffer_string(buf), F_OK) == 0)
1514  {
1515  rc = 1;
1516  break;
1517  }
1518 
1519  if (mutt_buffer_printf(buf, "%s/%s/Muttrc", token, PACKAGE) < 0)
1520  continue;
1522  if (access(mutt_buffer_string(buf), F_OK) == 0)
1523  {
1524  rc = 1;
1525  break;
1526  }
1527  }
1528 
1529  FREE(&x);
1530  return rc;
1531 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
static const char * xdg_env_vars[]
Definition: muttlib.c:72
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:991
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
#define FREE(x)
Definition: memory.h:40
static const char * xdg_defaults[]
Definition: muttlib.c:77
+ 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 1539 of file muttlib.c.

1540 {
1541  enum MailboxType mb_type = mx_path_probe(path);
1542 
1543  if (mb_type == MUTT_IMAP)
1544  imap_get_parent_path(path, buf, buflen);
1545  else if (mb_type == MUTT_NOTMUCH)
1546  mutt_str_copy(buf, C_Folder, buflen);
1547  else
1548  {
1549  mutt_str_copy(buf, path, buflen);
1550  int n = mutt_str_len(buf);
1551  if (n == 0)
1552  return;
1553 
1554  /* remove any final trailing '/' */
1555  if (buf[n - 1] == '/')
1556  buf[n - 1] = '\0';
1557 
1558  /* Remove everything until the next slash */
1559  for (n--; ((n >= 0) && (buf[n] != '/')); n--)
1560  ; // do nothing
1561 
1562  if (n > 0)
1563  buf[n] = '\0';
1564  else
1565  {
1566  buf[0] = '/';
1567  buf[1] = '\0';
1568  }
1569  }
1570 }
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:299
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1336
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
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:716
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
+ 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
-1if a is INBOX of b
0if none is INBOX
1if b 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 1594 of file muttlib.c.

1595 {
1596  /* fast-track in case the paths have been mutt_pretty_mailbox'ified */
1597  if ((a[0] == '+') && (b[0] == '+'))
1598  {
1599  return mutt_istr_equal(a + 1, "inbox") ? -1 :
1600  mutt_istr_equal(b + 1, "inbox") ? 1 :
1601  0;
1602  }
1603 
1604  const char *a_end = strrchr(a, '/');
1605  const char *b_end = strrchr(b, '/');
1606 
1607  /* If one path contains a '/', but not the other */
1608  if ((!a_end) ^ (!b_end))
1609  return 0;
1610 
1611  /* If neither path contains a '/' */
1612  if (!a_end)
1613  return 0;
1614 
1615  /* Compare the subpaths */
1616  size_t a_len = a_end - a;
1617  size_t b_len = b_end - b;
1618  size_t min = MIN(a_len, b_len);
1619  int same = (a[min] == '/') && (b[min] == '/') && (a[min + 1] != '\0') &&
1620  (b[min + 1] != '\0') && mutt_istrn_equal(a, b, min);
1621 
1622  if (!same)
1623  return 0;
1624 
1625  if (mutt_istr_equal(&a[min + 1], "inbox"))
1626  return -1;
1627 
1628  if (mutt_istr_equal(&b[min + 1], "inbox"))
1629  return 1;
1630 
1631  return 0;
1632 }
#define MIN(a, b)
Definition: memory.h:31
bool mutt_istrn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:621
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
+ 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 1640 of file muttlib.c.

1641 {
1642  if (!buf || !path)
1643  return;
1644 
1645  mutt_buffer_reset(buf);
1646 
1647  for (; *path; path++)
1648  {
1649  if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path))
1650  mutt_buffer_addch(buf, '_');
1651  else
1652  mutt_buffer_addch(buf, *path);
1653  }
1654 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
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 1662 of file muttlib.c.

1663 {
1664  if (!buf || (buflen == 0))
1665  return;
1666 
1667  if (C_SizeShowBytes && (num < 1024))
1668  {
1669  snprintf(buf, buflen, "%d", (int) num);
1670  }
1671  else if (num == 0)
1672  {
1673  mutt_str_copy(buf, C_SizeUnitsOnLeft ? "K0" : "0K", buflen);
1674  }
1675  else if (C_SizeShowFractions && (num < 10189)) /* 0.1K - 9.9K */
1676  {
1677  snprintf(buf, buflen, C_SizeUnitsOnLeft ? "K%3.1f" : "%3.1fK",
1678  (num < 103) ? 0.1 : (num / 1024.0));
1679  }
1680  else if (!C_SizeShowMb || (num < 1023949)) /* 10K - 999K */
1681  {
1682  /* 51 is magic which causes 10189/10240 to be rounded up to 10 */
1683  snprintf(buf, buflen, C_SizeUnitsOnLeft ? ("K%zu") : ("%zuK"), (num + 51) / 1024);
1684  }
1685  else if (C_SizeShowFractions && (num < 10433332)) /* 1.0M - 9.9M */
1686  {
1687  snprintf(buf, buflen, C_SizeUnitsOnLeft ? "M%3.1f" : "%3.1fM", num / 1048576.0);
1688  }
1689  else /* 10M+ */
1690  {
1691  /* (10433332 + 52428) / 1048576 = 10 */
1692  snprintf(buf, buflen, C_SizeUnitsOnLeft ? ("M%zu") : ("%zuM"), (num + 52428) / 1048576);
1693  }
1694 }
WHERE bool C_SizeUnitsOnLeft
Config: Show the units as a prefix to the size.
Definition: mutt_globals.h:163
WHERE bool C_SizeShowBytes
Config: Show smaller sizes in bytes.
Definition: mutt_globals.h:160
WHERE bool C_SizeShowFractions
Config: Show size fractions with a single decimal place.
Definition: mutt_globals.h:161
WHERE bool C_SizeShowMb
Config: Show sizes in megabytes for sizes greater than 1 megabyte.
Definition: mutt_globals.h:162
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:716
+ 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 1703 of file muttlib.c.

1704 {
1705  /* don't add a NULL or empty string to the list */
1706  if (!str || (*str == '\0'))
1707  return;
1708 
1709  /* check to make sure the item is not already on this list */
1710  struct ListNode *np = NULL;
1711  STAILQ_FOREACH(np, head, entries)
1712  {
1713  if (mutt_istr_equal(str, np->data))
1714  {
1715  return;
1716  }
1717  }
1718  mutt_list_insert_tail(head, mutt_str_dup(str));
1719 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
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:349
char * data
String.
Definition: list.h:36
A List node for strings.
Definition: list.h:34
+ 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 1728 of file muttlib.c.

1729 {
1730  if (mutt_str_equal("*", str))
1731  mutt_list_free(head); /* "unCMD *" means delete all current entries */
1732  else
1733  {
1734  struct ListNode *np = NULL, *tmp = NULL;
1735  STAILQ_FOREACH_SAFE(np, head, entries, tmp)
1736  {
1737  if (mutt_istr_equal(str, np->data))
1738  {
1739  STAILQ_REMOVE(head, np, ListNode, entries);
1740  FREE(&np->data);
1741  FREE(&np);
1742  break;
1743  }
1744  }
1745  }
1746 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:399
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:359
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
char * data
String.
Definition: list.h:36
#define FREE(x)
Definition: memory.h:40
A List node for strings.
Definition: list.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ C_GecosMask

struct Regex* C_GecosMask

Config: Regex for parsing GECOS field of /etc/passwd.

Definition at line 70 of file muttlib.c.

◆ xdg_env_vars

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

Definition at line 72 of file muttlib.c.

◆ xdg_defaults

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

Definition at line 77 of file muttlib.c.