NeoMutt  2020-06-26-89-g172cd3
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 "format_flags.h"
#include "hook.h"
#include "init.h"
#include "mutt_globals.h"
#include "mx.h"
#include "protos.h"
#include "ncrypt/lib.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_b2s(prefix));
102 
103  struct stat sb;
104  if ((lstat(mutt_b2s(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
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:618
#define mutt_b2s(buf)
Definition: buffer.h:41
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_b2s(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_b2s(p)) && !recurse)
295  {
297  mutt_buffer_printf(tmp, "%s%s", mutt_b2s(q), tail);
298  }
299  else
300  mutt_buffer_printf(tmp, "%s%s", mutt_b2s(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_b2s(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
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2344
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:653
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:50
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:2390
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:277
struct Envelope * env
Envelope information.
Definition: email.h:89
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 mutt_b2s(buf)
Definition: buffer.h:41
#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:99
WHERE char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:56
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:101
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1327
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
WHERE char * C_Spoolfile
Config: Inbox.
Definition: mutt_globals.h:111
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:55
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
struct Email * email_new(void)
Create a new Email.
Definition: email.c:68
#define TAILQ_EMPTY(head)
Definition: queue.h:714
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
&#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:97
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_b2s(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
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define mutt_b2s(buf)
Definition: buffer.h:41
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:721
+ 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 C_GecosMask, 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:593
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:721
+ 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:118
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
char * subtype
content-type subtype
Definition: body.h:37
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:93
SecurityFlags mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:550
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:92
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:608
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:118
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
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:550
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:92
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, mutt_b2s(buf));
475  if (unlink(mutt_b2s(buf)) && (errno != ENOENT))
476  {
477  mutt_debug(LL_DEBUG1, "%s:%d: ERROR: unlink(\"%s\"): %s (errno %d)\n", src,
478  line, mutt_b2s(buf), strerror(errno), errno);
479  }
480 }
#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
#define mutt_b2s(buf)
Definition: buffer.h:41
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:128
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:51
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
int const char int line
Definition: acutest.h:617
Log at debug level 3.
Definition: logging.h:42

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

495 {
496  size_t n =
497  snprintf(buf, buflen, "%s/%s-%s-%d-%d-%" PRIu64 "%s%s", NONULL(C_Tmpdir),
498  NONULL(prefix), NONULL(ShortHostname), (int) getuid(),
499  (int) getpid(), mutt_rand64(), suffix ? "." : "", NONULL(suffix));
500  if (n >= buflen)
501  {
503  "%s:%d: ERROR: insufficient buffer space to hold temporary "
504  "filename! buflen=%zu but need %zu\n",
505  src, line, buflen, n);
506  }
507  mutt_debug(LL_DEBUG3, "%s:%d: mutt_mktemp returns \"%s\"\n", src, line, buf);
508  if ((unlink(buf) != 0) && (errno != ENOENT))
509  {
510  mutt_debug(LL_DEBUG1, "%s:%d: ERROR: unlink(\"%s\"): %s (errno %d)\n", src,
511  line, buf, strerror(errno), errno);
512  }
513 }
#define NONULL(x)
Definition: string2.h:37
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: random.c:128
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:51
Log at debug level 1.
Definition: logging.h:40
int n
Definition: acutest.h:492
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:56
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int const char int line
Definition: acutest.h:617
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 522 of file muttlib.c.

523 {
524  if (!buf)
525  return;
526 
527  char *p = buf, *q = buf;
528  size_t len;
529  enum UrlScheme scheme;
530  char tmp[PATH_MAX];
531 
532  scheme = url_check_scheme(buf);
533 
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 }
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:727
Url is imap://.
Definition: url.h:38
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:50
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:165
#define PATH_MAX
Definition: mutt.h:44
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:99
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:598
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
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:721
Url is file://.
Definition: url.h:35
+ 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 &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:522
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 620 of file muttlib.c.

622 {
623  struct stat st;
624 
625  mutt_buffer_strcpy(fname, path);
626  if (access(mutt_b2s(fname), F_OK) != 0)
627  return 0;
628  if (stat(mutt_b2s(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_b2s(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_FILE | MUTT_CLEAR) != 0) ||
664  {
666  return (-1);
667  }
668  mutt_buffer_concat_path(fname, path, mutt_b2s(tmp));
670  }
671 
672  if ((*opt == MUTT_SAVE_NO_FLAGS) && (access(mutt_b2s(fname), F_OK) == 0))
673  {
674  switch (
675  mutt_multi_choice(_("File exists, (o)verwrite, (a)ppend, or (c)ancel?"),
676  // L10N: Options for: File exists, (o)verwrite, (a)ppend, or (c)ancel?
677  _("oac")))
678  {
679  case -1: /* abort */
680  return -1;
681  case 3: /* cancel */
682  return 1;
683 
684  case 2: /* append */
685  *opt = MUTT_SAVE_APPEND;
686  break;
687  case 1: /* overwrite */
688  *opt = MUTT_SAVE_OVERWRITE;
689  break;
690  }
691  }
692  return 0;
693 }
#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
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
No flags set.
Definition: mutt_attach.h:55
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:57
#define _(a)
Definition: message.h:28
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:377
#define mutt_b2s(buf)
Definition: buffer.h:41
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:930
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
#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:451
Append to existing file.
Definition: mutt_attach.h:56
#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
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
+ 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 704 of file muttlib.c.

705 {
706  if (addr && addr->mailbox)
707  {
708  mutt_str_copy(buf, addr->mailbox, buflen);
709  if (!C_SaveAddress)
710  {
711  char *p = strpbrk(buf, "%@");
712  if (p)
713  *p = '\0';
714  }
715  mutt_str_lower(buf);
716  }
717  else
718  *buf = '\0';
719 }
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:509
WHERE bool C_SaveAddress
Config: Use sender&#39;s full address as a default save folder.
Definition: mutt_globals.h:159
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:721
+ 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 726 of file muttlib.c.

727 {
728  if (a && a->mailbox)
729  {
730  mutt_buffer_strcpy(dest, a->mailbox);
731  if (!C_SaveAddress)
732  {
733  char *p = strpbrk(dest->data, "%@");
734  if (p)
735  {
736  *p = '\0';
737  mutt_buffer_fix_dptr(dest);
738  }
739  }
740  mutt_str_lower(dest->data);
741  }
742  else
743  mutt_buffer_reset(dest);
744 }
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:509
WHERE bool C_SaveAddress
Config: Use sender&#39;s full address as a default save folder.
Definition: mutt_globals.h:159
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 753 of file muttlib.c.

754 {
755  mutt_buffer_save_path(dest, a);
756  for (char *p = dest->data; *p; p++)
757  if ((*p == '/') || IS_SPACE(*p) || !IsPrint((unsigned char) *p))
758  *p = '_';
759 }
void mutt_buffer_save_path(struct Buffer *dest, const struct Address *a)
Make a safe filename from an email address.
Definition: muttlib.c:726
#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 772 of file muttlib.c.

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

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

1350 {
1351  int ret = 0;
1352 
1353  enum MailboxType type = mx_path_probe(s);
1354 
1355 #ifdef USE_POP
1356  if (type == MUTT_POP)
1357  {
1358  mutt_error(_("Can't save message to POP mailbox"));
1359  return 1;
1360  }
1361 #endif
1362 
1363  if ((type != MUTT_MAILBOX_ERROR) && (type != MUTT_UNKNOWN) && (mx_access(s, W_OK) == 0))
1364  {
1365  if (C_Confirmappend)
1366  {
1367  struct Buffer *tmp = mutt_buffer_pool_get();
1368  mutt_buffer_printf(tmp, _("Append messages to %s?"), s);
1369  enum QuadOption ans = mutt_yesorno(mutt_b2s(tmp), MUTT_YES);
1370  if (ans == MUTT_NO)
1371  ret = 1;
1372  else if (ans == MUTT_ABORT)
1373  ret = -1;
1375  }
1376  }
1377 
1378 #ifdef USE_NNTP
1379  if (type == MUTT_NNTP)
1380  {
1381  mutt_error(_("Can't save message to news server"));
1382  return 0;
1383  }
1384 #endif
1385 
1386  if (stat(s, st) != -1)
1387  {
1388  if (type == MUTT_MAILBOX_ERROR)
1389  {
1390  mutt_error(_("%s is not a mailbox"), s);
1391  return 1;
1392  }
1393  }
1394  else if (type != MUTT_IMAP)
1395  {
1396  st->st_mtime = 0;
1397  st->st_atime = 0;
1398 
1399  /* pathname does not exist */
1400  if (errno == ENOENT)
1401  {
1402  if (C_Confirmcreate)
1403  {
1404  struct Buffer *tmp = mutt_buffer_pool_get();
1405  mutt_buffer_printf(tmp, _("Create %s?"), s);
1406  enum QuadOption ans = mutt_yesorno(mutt_b2s(tmp), MUTT_YES);
1407  if (ans == MUTT_NO)
1408  ret = 1;
1409  else if (ans == MUTT_ABORT)
1410  ret = -1;
1412  }
1413 
1414  /* user confirmed with MUTT_YES or set C_Confirmcreate */
1415  if (ret == 0)
1416  {
1417  /* create dir recursively */
1418  char *tmp_path = mutt_path_dirname(s);
1419  if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1)
1420  {
1421  /* report failure & abort */
1422  mutt_perror(s);
1423  FREE(&tmp_path);
1424  return 1;
1425  }
1426  FREE(&tmp_path);
1427  }
1428  }
1429  else
1430  {
1431  mutt_perror(s);
1432  return 1;
1433  }
1434  }
1435 
1437  return ret;
1438 }
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
User aborted the question (with Ctrl-G)
Definition: quad.h:38
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
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
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:377
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:194
#define mutt_b2s(buf)
Definition: buffer.h:41
&#39;POP3&#39; Mailbox type
Definition: mailbox.h:55
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
WHERE bool C_Confirmcreate
Config: Confirm before creating a new mailbox.
Definition: mutt_globals.h:146
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1327
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
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:46
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
WHERE bool C_Confirmappend
Config: Confirm before appending emails to a mailbox.
Definition: mutt_globals.h:145
+ 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 1446 of file muttlib.c.

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

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

1475 {
1476  char *p = mutt_str_dup(src);
1477  int rc = mutt_ch_convert_string(&p, C_Charset, "us-ascii", 0);
1478  size_t len = mutt_buffer_strcpy(buf, (rc == 0) ? NONULL(p) : NONULL(src));
1479 
1480  /* convert the path to POSIX "Portable Filename Character Set" */
1481  for (size_t i = 0; i < len; i++)
1482  {
1483  if (!isalnum(buf->data[i]) && !strchr("/.-_", buf->data[i]))
1484  {
1485  buf->data[i] = '_';
1486  }
1487  }
1488  FREE(&p);
1489 }
#define NONULL(x)
Definition: string2.h:37
int mutt_ch_convert_string(char **ps, const char *from, const char *to, int flags)
Convert a string between encodings.
Definition: charset.c:754
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
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 1499 of file muttlib.c.

1500 {
1501  const char *xdg_env = mutt_str_getenv(xdg_env_vars[type]);
1502  char *xdg = xdg_env ? mutt_str_dup(xdg_env) : mutt_str_dup(xdg_defaults[type]);
1503  char *x = xdg; /* strsep() changes xdg, so free x instead later */
1504  char *token = NULL;
1505  int rc = 0;
1506 
1507  while ((token = strsep(&xdg, ":")))
1508  {
1509  if (mutt_buffer_printf(buf, "%s/%s/neomuttrc", token, PACKAGE) < 0)
1510  continue;
1512  if (access(mutt_b2s(buf), F_OK) == 0)
1513  {
1514  rc = 1;
1515  break;
1516  }
1517 
1518  if (mutt_buffer_printf(buf, "%s/%s/Muttrc", token, PACKAGE) < 0)
1519  continue;
1521  if (access(mutt_b2s(buf), F_OK) == 0)
1522  {
1523  rc = 1;
1524  break;
1525  }
1526  }
1527 
1528  FREE(&x);
1529  return rc;
1530 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
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:996
#define mutt_b2s(buf)
Definition: buffer.h:41
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 1538 of file muttlib.c.

1539 {
1540  enum MailboxType mb_type = mx_path_probe(path);
1541 
1542  if (mb_type == MUTT_IMAP)
1543  imap_get_parent_path(path, buf, buflen);
1544  else if (mb_type == MUTT_NOTMUCH)
1545  mutt_str_copy(buf, C_Folder, buflen);
1546  else
1547  {
1548  mutt_str_copy(buf, path, buflen);
1549  int n = mutt_str_len(buf);
1550  if (n == 0)
1551  return;
1552 
1553  /* remove any final trailing '/' */
1554  if (buf[n - 1] == '/')
1555  buf[n - 1] = '\0';
1556 
1557  /* Remove everything until the next slash */
1558  for (n--; ((n >= 0) && (buf[n] != '/')); n--)
1559  ; // do nothing
1560 
1561  if (n > 0)
1562  buf[n] = '\0';
1563  else
1564  {
1565  buf[0] = '/';
1566  buf[1] = '\0';
1567  }
1568  }
1569 }
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:302
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:99
&#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:636
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1327
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
int n
Definition: acutest.h:492
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:721
&#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 1593 of file muttlib.c.

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

1638 {
1639  if (!buf || !path)
1640  return;
1641 
1642  mutt_buffer_reset(buf);
1643 
1644  for (; *path; path++)
1645  {
1646  if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path))
1647  mutt_buffer_addch(buf, '_');
1648  else
1649  mutt_buffer_addch(buf, *path);
1650  }
1651 }
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 1659 of file muttlib.c.

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

1701 {
1702  /* don't add a NULL or empty string to the list */
1703  if (!str || (*str == '\0'))
1704  return;
1705 
1706  /* check to make sure the item is not already on this list */
1707  struct ListNode *np = NULL;
1708  STAILQ_FOREACH(np, head, entries)
1709  {
1710  if (mutt_istr_equal(str, np->data))
1711  {
1712  return;
1713  }
1714  }
1715  mutt_list_insert_tail(head, mutt_str_dup(str));
1716 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
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 1725 of file muttlib.c.

1726 {
1727  if (mutt_str_equal("*", str))
1728  mutt_list_free(head); /* "unCMD *" means delete all current entries */
1729  else
1730  {
1731  struct ListNode *np = NULL, *tmp = NULL;
1732  STAILQ_FOREACH_SAFE(np, head, entries, tmp)
1733  {
1734  if (mutt_istr_equal(str, np->data))
1735  {
1736  STAILQ_REMOVE(head, np, ListNode, entries);
1737  FREE(&np->data);
1738  FREE(&np);
1739  break;
1740  }
1741  }
1742  }
1743 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
#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:888
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.