NeoMutt  2018-07-16 +2225-8687db
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 <regex.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/mutt.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "conn/conn.h"
#include "mutt.h"
#include "muttlib.h"
#include "alias.h"
#include "curs_lib.h"
#include "filter.h"
#include "format_flags.h"
#include "globals.h"
#include "hook.h"
#include "mutt_window.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "protos.h"
#include "imap/imap.h"

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...
 
int mutt_randbuf (void *buf, size_t buflen)
 Fill a buffer with randomness. More...
 
void mutt_rand_base32 (void *buf, size_t buflen)
 Fill a buffer with a base32-encoded random string. More...
 
uint32_t mutt_rand32 (void)
 Create a 32-bit random number. More...
 
uint64_t mutt_rand64 (void)
 Create a 64-bit random number. 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, char *fname, size_t flen, 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_safe_path (char *buf, size_t buflen, 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, unsigned long 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 (char *buf, size_t buflen, const char *src)
 Convert a path into the user's preferred character set. More...
 
int mutt_set_xdg_path (enum XdgType type, char *buf, size_t bufsize)
 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...
 

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 []
 
static FILE * fp_random
 
static const unsigned char base32 [] = "abcdefghijklmnopqrstuvwxyz234567"
 

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

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]))
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 = strrchr(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:79
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:75
#define mutt_buffer_mktemp_pfx_sfx(buf, prefix, suffix)
Definition: muttlib.h:80
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
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:191
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:614
#define mutt_b2s(buf)
Definition: buffer.h:42
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:314
char * data
Pointer to data.
Definition: buffer.h:35
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:52
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
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, NULL);
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 = mutt_alias_lookup(s + 1);
222  if (!TAILQ_EMPTY(al))
223  {
224  struct Email *e = mutt_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  mutt_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_strcpy(buf, mutt_b2s(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:76
struct AddressList * mutt_alias_lookup(const char *s)
Find an Alias.
Definition: alias.c:272
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:75
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2432
void mutt_buffer_increase_size(struct Buffer *buf, size_t new_size)
Increase the allocated size of a buffer.
Definition: buffer.c:339
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:724
String manipulation buffer.
Definition: buffer.h:33
WHERE char * LastFolder
Previously selected mailbox.
Definition: globals.h:54
struct Email * mutt_email_new(void)
Create a new Email.
Definition: email.c:63
WHERE char * C_Record
Config: Folder to save &#39;sent&#39; messages.
Definition: globals.h:129
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:191
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:662
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:2478
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:43
WHERE char * C_Mbox
Config: Folder that receives read emails (see Move)
Definition: globals.h:112
struct Envelope * env
Envelope information.
Definition: email.h:89
WHERE char * HomeDir
User&#39;s home directory.
Definition: globals.h:48
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: globals.h:53
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:41
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:212
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition: file.c:633
#define mutt_b2s(buf)
Definition: buffer.h:42
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:314
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:114
#define PATH_MAX
Definition: mutt.h:50
char * data
Pointer to data.
Definition: buffer.h:35
void mutt_email_free(struct Email **e)
Free an Email.
Definition: email.c:41
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
WHERE char * C_Spoolfile
Config: Inbox.
Definition: globals.h:142
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:44
#define TAILQ_EMPTY(head)
Definition: queue.h:715
enum MailboxType mx_path_probe(const char *path, struct stat *st)
Find a mailbox that understands a path.
Definition: mx.c:1241
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
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
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_strfcpy(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:75
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
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:256
#define mutt_b2s(buf)
Definition: buffer.h:42
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
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 (C_GecosMask && C_GecosMask->regex)
374  {
375  if (regexec(C_GecosMask->regex, pw->pw_gecos, 1, pat_match, 0) == 0)
376  {
377  mutt_str_strfcpy(dest, pw->pw_gecos + pat_match[0].rm_so,
378  MIN(pat_match[0].rm_eo - pat_match[0].rm_so + 1, destlen));
379  }
380  }
381  else if ((p = strchr(pw->pw_gecos, ',')))
382  mutt_str_strfcpy(dest, pw->pw_gecos, MIN(destlen, p - pw->pw_gecos + 1));
383  else
384  mutt_str_strfcpy(dest, pw->pw_gecos, destlen);
385 
386  pwnl = strlen(pw->pw_name);
387 
388  for (int idx = 0; dest[idx]; idx++)
389  {
390  if (dest[idx] == '&')
391  {
392  memmove(&dest[idx + pwnl], &dest[idx + 1],
393  MAX((ssize_t)(destlen - idx - pwnl - 1), 0));
394  memcpy(&dest[idx], pw->pw_name, MIN(destlen - idx - 1, pwnl));
395  dest[idx] = toupper((unsigned char) dest[idx]);
396  }
397  }
398 
399  return dest;
400 }
#define MIN(a, b)
Definition: memory.h:31
regex_t * regex
compiled expression
Definition: regex3.h:60
#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
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
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 408 of file muttlib.c.

409 {
410  switch (m->type)
411  {
412  case TYPE_TEXT:
413  if (mutt_str_strcasecmp("plain", m->subtype) == 0)
414  return false;
415  break;
416  case TYPE_APPLICATION:
418  return false;
420  return false;
421  break;
422 
423  case TYPE_MULTIPART:
424  case TYPE_MESSAGE:
425  return false;
426  }
427 
428  return true;
429 }
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:527
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:586
unsigned int type
content-type primary type
Definition: body.h:65
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:130
Type: &#39;message/*&#39;.
Definition: mime.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
#define WithCrypto
Definition: ncrypt.h:156
Type: &#39;application/*&#39;.
Definition: mime.h:33
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: ncrypt.h:131
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 436 of file muttlib.c.

437 {
438  int t = b->type;
439  char *s = b->subtype;
440 
442  return false;
443 
444  if (t == TYPE_TEXT)
445  return true;
446 
447  if (t == TYPE_MESSAGE)
448  {
449  if (mutt_str_strcasecmp("delivery-status", s) == 0)
450  return true;
451  }
452 
453  if (((WithCrypto & APPLICATION_PGP) != 0) && (t == TYPE_APPLICATION))
454  {
455  if (mutt_str_strcasecmp("pgp-keys", s) == 0)
456  return true;
457  }
458 
459  return false;
460 }
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:527
Type: &#39;text/*&#39;.
Definition: mime.h:38
unsigned int type
content-type primary type
Definition: body.h:65
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:130
Type: &#39;message/*&#39;.
Definition: mime.h:35
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
#define WithCrypto
Definition: ncrypt.h:156
Type: &#39;application/*&#39;.
Definition: mime.h:33
int mutt_randbuf ( void *  buf,
size_t  buflen 
)

Fill a buffer with randomness.

Parameters
bufBuffer for result
buflenSize of buffer
Return values
0Success
-1Error

Definition at line 471 of file muttlib.c.

472 {
473  if (buflen > 1048576)
474  {
475  mutt_error(_("mutt_randbuf buflen=%zu"), buflen);
476  return -1;
477  }
478 /* XXX switch to HAVE_GETRANDOM and getrandom() in about 2017 */
479 #if defined(SYS_getrandom) && defined(__linux__)
480  long ret;
481  do
482  {
483  ret = syscall(SYS_getrandom, buf, buflen, 0, 0, 0, 0);
484  } while ((ret == -1) && (errno == EINTR));
485  if (ret == buflen)
486  return 0;
487 #endif
488  /* let's try urandom in case we're on an old kernel, or the user has
489  * configured selinux, seccomp or something to not allow getrandom */
490  if (!fp_random)
491  {
492  fp_random = fopen("/dev/urandom", "rb");
493  if (!fp_random)
494  {
495  mutt_error(_("open /dev/urandom: %s"), strerror(errno));
496  return -1;
497  }
498  setbuf(fp_random, NULL);
499  }
500  if (fread(buf, 1, buflen, fp_random) != buflen)
501  {
502  mutt_error(_("read /dev/urandom: %s"), strerror(errno));
503  return -1;
504  }
505 
506  return 0;
507 }
#define _(a)
Definition: message.h:28
static FILE * fp_random
Definition: muttlib.c:462
#define mutt_error(...)
Definition: logging.h:84
void mutt_rand_base32 ( void *  buf,
size_t  buflen 
)

Fill a buffer with a base32-encoded random string.

Parameters
bufBuffer for result
buflenLength of buffer

Definition at line 516 of file muttlib.c.

517 {
518  uint8_t *p = buf;
519 
520  if (mutt_randbuf(p, buflen) < 0)
521  mutt_exit(1);
522  for (size_t pos = 0; pos < buflen; pos++)
523  p[pos] = base32[p[pos] % 32];
524 }
int mutt_randbuf(void *buf, size_t buflen)
Fill a buffer with randomness.
Definition: muttlib.c:471
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:203
static const unsigned char base32[]
Definition: muttlib.c:509
uint32_t mutt_rand32 ( void  )

Create a 32-bit random number.

Return values
numRandom number

Definition at line 530 of file muttlib.c.

531 {
532  uint32_t num = 0;
533 
534  if (mutt_randbuf(&num, sizeof(num)) < 0)
535  mutt_exit(1);
536  return num;
537 }
int mutt_randbuf(void *buf, size_t buflen)
Fill a buffer with randomness.
Definition: muttlib.c:471
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:203
uint64_t mutt_rand64 ( void  )

Create a 64-bit random number.

Return values
numRandom number

Definition at line 543 of file muttlib.c.

544 {
545  uint64_t num = 0;
546 
547  if (mutt_randbuf(&num, sizeof(num)) < 0)
548  mutt_exit(1);
549  return num;
550 }
int mutt_randbuf(void *buf, size_t buflen)
Fill a buffer with randomness.
Definition: muttlib.c:471
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:203
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 560 of file muttlib.c.

562 {
563  mutt_buffer_printf(buf, "%s/%s-%s-%d-%d-%" PRIu64 "%s%s", NONULL(C_Tmpdir),
564  NONULL(prefix), NONULL(ShortHostname), (int) getuid(),
565  (int) getpid(), mutt_rand64(), suffix ? "." : "", NONULL(suffix));
566 
567  mutt_debug(LL_DEBUG3, "%s:%d: mutt_mktemp returns \"%s\"\n", src, line, mutt_b2s(buf));
568  if (unlink(mutt_b2s(buf)) && (errno != ENOENT))
569  {
570  mutt_debug(LL_DEBUG1, "%s:%d: ERROR: unlink(\"%s\"): %s (errno %d)\n", src,
571  line, mutt_b2s(buf), strerror(errno), errno);
572  }
573 }
#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:191
#define mutt_b2s(buf)
Definition: buffer.h:42
const char * line
Definition: common.c:36
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: muttlib.c:543
Log at debug level 1.
Definition: logging.h:56
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:52
WHERE char * ShortHostname
Short version of the hostname.
Definition: globals.h:49
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:58
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 586 of file muttlib.c.

588 {
589  size_t n =
590  snprintf(buf, buflen, "%s/%s-%s-%d-%d-%" PRIu64 "%s%s", NONULL(C_Tmpdir),
591  NONULL(prefix), NONULL(ShortHostname), (int) getuid(),
592  (int) getpid(), mutt_rand64(), suffix ? "." : "", NONULL(suffix));
593  if (n >= buflen)
594  {
596  "%s:%d: ERROR: insufficient buffer space to hold temporary "
597  "filename! buflen=%zu but need %zu\n",
598  src, line, buflen, n);
599  }
600  mutt_debug(LL_DEBUG3, "%s:%d: mutt_mktemp returns \"%s\"\n", src, line, buf);
601  if (unlink(buf) && (errno != ENOENT))
602  {
603  mutt_debug(LL_DEBUG1, "%s:%d: ERROR: unlink(\"%s\"): %s (errno %d)\n", src,
604  line, buf, strerror(errno), errno);
605  }
606 }
#define NONULL(x)
Definition: string2.h:37
const char * line
Definition: common.c:36
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: muttlib.c:543
Log at debug level 1.
Definition: logging.h:56
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:52
WHERE char * ShortHostname
Short version of the hostname.
Definition: globals.h:49
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:58
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 615 of file muttlib.c.

616 {
617  if (!buf)
618  return;
619 
620  char *p = buf, *q = buf;
621  size_t len;
622  enum UrlScheme scheme;
623  char tmp[PATH_MAX];
624 
625  scheme = url_check_scheme(buf);
626 
627  if ((scheme == U_IMAP) || (scheme == U_IMAPS))
628  {
629  imap_pretty_mailbox(buf, buflen, C_Folder);
630  return;
631  }
632 
633  if (scheme == U_NOTMUCH)
634  return;
635 
636  /* if buf is an url, only collapse path component */
637  if (scheme != U_UNKNOWN)
638  {
639  p = strchr(buf, ':') + 1;
640  if (strncmp(p, "//", 2) == 0)
641  q = strchr(p + 2, '/');
642  if (!q)
643  q = strchr(p, '\0');
644  p = q;
645  }
646 
647  /* cleanup path */
648  if (strstr(p, "//") || strstr(p, "/./"))
649  {
650  /* first attempt to collapse the pathname, this is more
651  * lightweight than realpath() and doesn't resolve links */
652  while (*p)
653  {
654  if ((p[0] == '/') && (p[1] == '/'))
655  {
656  *q++ = '/';
657  p += 2;
658  }
659  else if ((p[0] == '/') && (p[1] == '.') && (p[2] == '/'))
660  {
661  *q++ = '/';
662  p += 3;
663  }
664  else
665  *q++ = *p++;
666  }
667  *q = '\0';
668  }
669  else if (strstr(p, "..") && ((scheme == U_UNKNOWN) || (scheme == U_FILE)) &&
670  realpath(p, tmp))
671  {
672  mutt_str_strfcpy(p, tmp, buflen - (p - buf));
673  }
674 
675  if ((len = mutt_str_startswith(buf, C_Folder, CASE_MATCH)) && (buf[len] == '/'))
676  {
677  *buf++ = '=';
678  memmove(buf, buf + len, mutt_str_strlen(buf + len) + 1);
679  }
680  else if ((len = mutt_str_startswith(buf, HomeDir, CASE_MATCH)) && (buf[len] == '/'))
681  {
682  *buf++ = '~';
683  memmove(buf, buf + len - 1, mutt_str_strlen(buf + len - 1) + 1);
684  }
685 }
Url is notmuch://.
Definition: url.h:45
Url is imaps://.
Definition: url.h:39
Url wasn&#39;t recognised.
Definition: url.h:34
Url is imap://.
Definition: url.h:38
Match case when comparing strings.
Definition: string2.h:67
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
enum UrlScheme url_check_scheme(const char *s)
Check the protocol of a URL.
Definition: url.c:132
UrlScheme
All recognised Url types.
Definition: url.h:32
WHERE char * HomeDir
User&#39;s home directory.
Definition: globals.h:48
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:114
#define PATH_MAX
Definition: mutt.h:50
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
void imap_pretty_mailbox(char *path, size_t pathlen, const char *folder)
Prettify an IMAP mailbox name.
Definition: util.c:689
Url is file://.
Definition: url.h:35
void mutt_buffer_pretty_mailbox ( struct Buffer buf)

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

Parameters
bufBuffer containing Mailbox name

Definition at line 691 of file muttlib.c.

692 {
693  if (!buf || !buf->data)
694  return;
695  /* This reduces the size of the Buffer, so we can pass it through.
696  * We adjust the size just to make sure buf->data is not NULL though */
698  mutt_pretty_mailbox(buf->data, buf->dsize);
700 }
void mutt_buffer_increase_size(struct Buffer *buf, size_t new_size)
Increase the allocated size of a buffer.
Definition: buffer.c:339
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:615
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:212
#define PATH_MAX
Definition: mutt.h:50
char * data
Pointer to data.
Definition: buffer.h:35
int mutt_check_overwrite ( const char *  attname,
const char *  path,
char *  fname,
size_t  flen,
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]flenLength of buffer
[out]optSave option, see SaveAttach
[out]directoryDirectory to save under (OPTIONAL)
Return values
0Success
-1Abort
1Error

Definition at line 714 of file muttlib.c.

716 {
717  struct stat st;
718 
719  mutt_str_strfcpy(fname, path, flen);
720  if (access(fname, F_OK) != 0)
721  return 0;
722  if (stat(fname, &st) != 0)
723  return -1;
724  if (S_ISDIR(st.st_mode))
725  {
726  enum QuadOption ans = MUTT_NO;
727  if (directory)
728  {
729  switch (mutt_multi_choice
730  /* L10N: Means "The path you specified as the destination file is a directory."
731  See the msgid "Save to file: " (alias.c, recvattach.c)
732  These three letters correspond to the choices in the string. */
733  (_("File is a directory, save under it: (y)es, (n)o, (a)ll?"), _("yna")))
734  {
735  case 3: /* all */
736  mutt_str_replace(directory, fname);
737  break;
738  case 1: /* yes */
739  FREE(directory);
740  break;
741  case -1: /* abort */
742  FREE(directory);
743  return -1;
744  case 2: /* no */
745  FREE(directory);
746  return 1;
747  }
748  }
749  /* L10N: Means "The path you specified as the destination file is a directory."
750  See the msgid "Save to file: " (alias.c, recvattach.c) */
751  else if ((ans = mutt_yesorno(_("File is a directory, save under it?"), MUTT_YES)) != MUTT_YES)
752  return (ans == MUTT_NO) ? 1 : -1;
753 
754  char tmp[PATH_MAX];
755  mutt_str_strfcpy(tmp, mutt_path_basename(NONULL(attname)), sizeof(tmp));
756  if ((mutt_get_field(_("File under directory: "), tmp, sizeof(tmp),
757  MUTT_FILE | MUTT_CLEAR) != 0) ||
758  !tmp[0])
759  {
760  return -1;
761  }
762  mutt_path_concat(fname, path, tmp, flen);
763  }
764 
765  if ((*opt == MUTT_SAVE_NO_FLAGS) && (access(fname, F_OK) == 0))
766  {
767  switch (
768  mutt_multi_choice(_("File exists, (o)verwrite, (a)ppend, or (c)ancel?"),
769  // L10N: Options for: File exists, (o)verwrite, (a)ppend, or (c)ancel?
770  _("oac")))
771  {
772  case -1: /* abort */
773  return -1;
774  case 3: /* cancel */
775  return 1;
776 
777  case 2: /* append */
778  *opt = MUTT_SAVE_APPEND;
779  break;
780  case 1: /* overwrite */
781  *opt = MUTT_SAVE_OVERWRITE;
782  break;
783  }
784  }
785  return 0;
786 }
char * mutt_path_concat(char *d, const char *dir, const char *fname, size_t l)
Join a directory name and a filename.
Definition: path.c:329
#define NONULL(x)
Definition: string2.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:68
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
No flags set.
Definition: mutt_attach.h:54
Overwrite existing file.
Definition: mutt_attach.h:56
#define _(a)
Definition: message.h:28
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:86
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:306
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:839
#define PATH_MAX
Definition: mutt.h:50
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
#define MUTT_FILE
Do file completion.
Definition: mutt.h:64
Append to existing file.
Definition: mutt_attach.h:55
#define FREE(x)
Definition: memory.h:40
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
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 797 of file muttlib.c.

798 {
799  if (addr && addr->mailbox)
800  {
801  mutt_str_strfcpy(buf, addr->mailbox, buflen);
802  if (!C_SaveAddress)
803  {
804  char *p = strpbrk(buf, "%@");
805  if (p)
806  *p = '\0';
807  }
808  mutt_str_strlower(buf);
809  }
810  else
811  *buf = '\0';
812 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
char * mutt_str_strlower(char *s)
convert all characters in the string to lowercase
Definition: string.c:509
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
WHERE bool C_SaveAddress
Config: Use sender&#39;s full address as a default save folder.
Definition: globals.h:246
void mutt_safe_path ( char *  buf,
size_t  buflen,
const struct Address a 
)

Make a safe filename from an email address.

Parameters
bufBuffer for the result
buflenLength of buffer
aAddress to use

The filename will be stripped of '/', space, etc to make it safe.

Definition at line 822 of file muttlib.c.

823 {
824  mutt_save_path(buf, buflen, a);
825  for (char *p = buf; *p; p++)
826  if ((*p == '/') || IS_SPACE(*p) || !IsPrint((unsigned char) *p))
827  *p = '_';
828 }
#define IsPrint(ch)
Definition: mbyte.h:38
#define IS_SPACE(ch)
Definition: string2.h:38
void mutt_save_path(char *buf, size_t buflen, const struct Address *addr)
Turn an email address into a filename (for saving)
Definition: muttlib.c:797
void mutt_expando_format ( char *  buf,
size_t  buflen,
size_t  col,
int  cols,
const char *  src,
format_t callback,
unsigned long  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 841 of file muttlib.c.

843 {
844  char prefix[128], tmp[1024];
845  char *cp = NULL, *wptr = buf;
846  char ch;
847  char if_str[128], else_str[128];
848  size_t wlen, count, len, wid;
849  FILE *fp_filter = NULL;
850  char *recycler = NULL;
851 
852  char src2[256];
853  mutt_str_strfcpy(src2, src, mutt_str_strlen(src) + 1);
854  src = src2;
855 
856  prefix[0] = '\0';
857  buflen--; /* save room for the terminal \0 */
858  wlen = ((flags & MUTT_FORMAT_ARROWCURSOR) && C_ArrowCursor) ? 3 : 0;
859  col += wlen;
860 
861  if ((flags & MUTT_FORMAT_NOFILTER) == 0)
862  {
863  int off = -1;
864 
865  /* Do not consider filters if no pipe at end */
866  int n = mutt_str_strlen(src);
867  if ((n > 1) && (src[n - 1] == '|'))
868  {
869  /* Scan backwards for backslashes */
870  off = n;
871  while ((off > 0) && (src[off - 2] == '\\'))
872  off--;
873  }
874 
875  /* If number of backslashes is even, the pipe is real. */
876  /* n-off is the number of backslashes. */
877  if ((off > 0) && (((n - off) % 2) == 0))
878  {
879  char srccopy[1024];
880  int i = 0;
881 
882  mutt_debug(LL_DEBUG3, "fmtpipe = %s\n", src);
883 
884  strncpy(srccopy, src, n);
885  srccopy[n - 1] = '\0';
886 
887  /* prepare Buffers */
888  struct Buffer *srcbuf = mutt_buffer_from(srccopy);
889  /* note: we are resetting dptr and *reading* from the buffer, so we don't
890  * want to use mutt_buffer_reset(). */
891  srcbuf->dptr = srcbuf->data;
892  struct Buffer *word = mutt_buffer_new();
893  struct Buffer *cmd = mutt_buffer_new();
894 
895  /* Iterate expansions across successive arguments */
896  do
897  {
898  /* Extract the command name and copy to command line */
899  mutt_debug(LL_DEBUG3, "fmtpipe +++: %s\n", srcbuf->dptr);
900  if (word->data)
901  *word->data = '\0';
903  mutt_debug(LL_DEBUG3, "fmtpipe %2d: %s\n", i++, word->data);
904  mutt_buffer_addch(cmd, '\'');
905  mutt_expando_format(tmp, sizeof(tmp), 0, cols, word->data, callback,
906  data, flags | MUTT_FORMAT_NOFILTER);
907  for (char *p = tmp; p && *p; p++)
908  {
909  if (*p == '\'')
910  {
911  /* shell quoting doesn't permit escaping a single quote within
912  * single-quoted material. double-quoting instead will lead
913  * shell variable expansions, so break out of the single-quoted
914  * span, insert a double-quoted single quote, and resume. */
915  mutt_buffer_addstr(cmd, "'\"'\"'");
916  }
917  else
918  mutt_buffer_addch(cmd, *p);
919  }
920  mutt_buffer_addch(cmd, '\'');
921  mutt_buffer_addch(cmd, ' ');
922  } while (MoreArgs(srcbuf));
923 
924  mutt_debug(LL_DEBUG3, "fmtpipe > %s\n", cmd->data);
925 
926  col -= wlen; /* reset to passed in value */
927  wptr = buf; /* reset write ptr */
928  pid_t pid = mutt_create_filter(cmd->data, NULL, &fp_filter, NULL);
929  if (pid != -1)
930  {
931  int rc;
932 
933  n = fread(buf, 1, buflen /* already decremented */, fp_filter);
934  mutt_file_fclose(&fp_filter);
935  rc = mutt_wait_filter(pid);
936  if (rc != 0)
937  mutt_debug(LL_DEBUG1, "format pipe cmd exited code %d\n", rc);
938  if (n > 0)
939  {
940  buf[n] = '\0';
941  while ((n > 0) && ((buf[n - 1] == '\n') || (buf[n - 1] == '\r')))
942  buf[--n] = '\0';
943  mutt_debug(LL_DEBUG5, "fmtpipe < %s\n", buf);
944 
945  /* If the result ends with '%', this indicates that the filter
946  * generated %-tokens that neomutt can expand. Eliminate the '%'
947  * marker and recycle the string through mutt_expando_format().
948  * To literally end with "%", use "%%". */
949  if ((n > 0) && (buf[n - 1] == '%'))
950  {
951  n--;
952  buf[n] = '\0'; /* remove '%' */
953  if ((n > 0) && (buf[n - 1] != '%'))
954  {
955  recycler = mutt_str_strdup(buf);
956  if (recycler)
957  {
958  /* buflen is decremented at the start of this function
959  * to save space for the terminal nul char. We can add
960  * it back for the recursive call since the expansion of
961  * format pipes does not try to append a nul itself. */
962  mutt_expando_format(buf, buflen + 1, col, cols, recycler,
963  callback, data, flags);
964  FREE(&recycler);
965  }
966  }
967  }
968  }
969  else
970  {
971  /* read error */
972  mutt_debug(LL_DEBUG1, "error reading from fmtpipe: %s (errno=%d)\n",
973  strerror(errno), errno);
974  *wptr = '\0';
975  }
976  }
977  else
978  {
979  /* Filter failed; erase write buffer */
980  *wptr = '\0';
981  }
982 
983  mutt_buffer_free(&cmd);
984  mutt_buffer_free(&srcbuf);
985  mutt_buffer_free(&word);
986  return;
987  }
988  }
989 
990  while (*src && (wlen < buflen))
991  {
992  if (*src == '%')
993  {
994  if (*++src == '%')
995  {
996  *wptr++ = '%';
997  wlen++;
998  col++;
999  src++;
1000  continue;
1001  }
1002 
1003  if (*src == '?')
1004  {
1005  /* change original %? to new %< notation */
1006  /* %?x?y&z? to %<x?y&z> where y and z are nestable */
1007  char *p = (char *) src;
1008  *p = '<';
1009  /* skip over "x" */
1010  for (; *p && *p != '?'; p++)
1011  ;
1012  /* nothing */
1013  if (*p == '?')
1014  p++;
1015  /* fix up the "y&z" section */
1016  for (; *p && *p != '?'; p++)
1017  {
1018  /* escape '<' and '>' to work inside nested-if */
1019  if ((*p == '<') || (*p == '>'))
1020  {
1021  memmove(p + 2, p, mutt_str_strlen(p) + 1);
1022  *p++ = '\\';
1023  *p++ = '\\';
1024  }
1025  }
1026  if (*p == '?')
1027  *p = '>';
1028  }
1029 
1030  if (*src == '<')
1031  {
1032  flags |= MUTT_FORMAT_OPTIONAL;
1033  ch = *(++src); /* save the character to switch on */
1034  src++;
1035  cp = prefix;
1036  count = 0;
1037  while ((count < sizeof(prefix)) && (*src != '?'))
1038  {
1039  *cp++ = *src++;
1040  count++;
1041  }
1042  *cp = '\0';
1043  }
1044  else
1045  {
1046  flags &= ~MUTT_FORMAT_OPTIONAL;
1047 
1048  /* eat the format string */
1049  cp = prefix;
1050  count = 0;
1051  while ((count < sizeof(prefix)) && (isdigit((unsigned char) *src) || (*src == '.') ||
1052  (*src == '-') || (*src == '=')))
1053  {
1054  *cp++ = *src++;
1055  count++;
1056  }
1057  *cp = '\0';
1058 
1059  if (!*src)
1060  break; /* bad format */
1061 
1062  ch = *src++; /* save the character to switch on */
1063  }
1064 
1065  if (flags & MUTT_FORMAT_OPTIONAL)
1066  {
1067  int lrbalance;
1068 
1069  if (*src != '?')
1070  break; /* bad format */
1071  src++;
1072 
1073  /* eat the 'if' part of the string */
1074  cp = if_str;
1075  count = 0;
1076  lrbalance = 1;
1077  while ((lrbalance > 0) && (count < sizeof(if_str)) && *src)
1078  {
1079  if ((src[0] == '%') && (src[1] == '>'))
1080  {
1081  /* This is a padding expando; copy two chars and carry on */
1082  *cp++ = *src++;
1083  *cp++ = *src++;
1084  count += 2;
1085  continue;
1086  }
1087 
1088  if (*src == '\\')
1089  {
1090  src++;
1091  *cp++ = *src++;
1092  }
1093  else if ((src[0] == '%') && (src[1] == '<'))
1094  {
1095  lrbalance++;
1096  }
1097  else if (src[0] == '>')
1098  {
1099  lrbalance--;
1100  }
1101  if (lrbalance == 0)
1102  break;
1103  if ((lrbalance == 1) && (src[0] == '&'))
1104  break;
1105  *cp++ = *src++;
1106  count++;
1107  }
1108  *cp = '\0';
1109 
1110  /* eat the 'else' part of the string (optional) */
1111  if (*src == '&')
1112  src++; /* skip the & */
1113  cp = else_str;
1114  count = 0;
1115  while ((lrbalance > 0) && (count < sizeof(else_str)) && *src)
1116  {
1117  if ((src[0] == '%') && (src[1] == '>'))
1118  {
1119  /* This is a padding expando; copy two chars and carry on */
1120  *cp++ = *src++;
1121  *cp++ = *src++;
1122  count += 2;
1123  continue;
1124  }
1125 
1126  if (*src == '\\')
1127  {
1128  src++;
1129  *cp++ = *src++;
1130  }
1131  else if ((src[0] == '%') && (src[1] == '<'))
1132  {
1133  lrbalance++;
1134  }
1135  else if (src[0] == '>')
1136  {
1137  lrbalance--;
1138  }
1139  if (lrbalance == 0)
1140  break;
1141  if ((lrbalance == 1) && (src[0] == '&'))
1142  break;
1143  *cp++ = *src++;
1144  count++;
1145  }
1146  *cp = '\0';
1147 
1148  if (!*src)
1149  break; /* bad format */
1150 
1151  src++; /* move past the trailing '>' (formerly '?') */
1152  }
1153 
1154  /* handle generic cases first */
1155  if ((ch == '>') || (ch == '*'))
1156  {
1157  /* %>X: right justify to EOL, left takes precedence
1158  * %*X: right justify to EOL, right takes precedence */
1159  int soft = ch == '*';
1160  int pl, pw;
1161  pl = mutt_mb_charlen(src, &pw);
1162  if (pl <= 0)
1163  {
1164  pl = 1;
1165  pw = 1;
1166  }
1167 
1168  /* see if there's room to add content, else ignore */
1169  if (((col < cols) && (wlen < buflen)) || soft)
1170  {
1171  int pad;
1172 
1173  /* get contents after padding */
1174  mutt_expando_format(tmp, sizeof(tmp), 0, cols, src + pl, callback, data, flags);
1175  len = mutt_str_strlen(tmp);
1176  wid = mutt_strwidth(tmp);
1177 
1178  pad = (cols - col - wid) / pw;
1179  if (pad >= 0)
1180  {
1181  /* try to consume as many columns as we can, if we don't have
1182  * memory for that, use as much memory as possible */
1183  if (wlen + (pad * pl) + len > buflen)
1184  pad = (buflen > (wlen + len)) ? ((buflen - wlen - len) / pl) : 0;
1185  else
1186  {
1187  /* Add pre-spacing to make multi-column pad characters and
1188  * the contents after padding line up */
1189  while ((col + (pad * pw) + wid < cols) && (wlen + (pad * pl) + len < buflen))
1190  {
1191  *wptr++ = ' ';
1192  wlen++;
1193  col++;
1194  }
1195  }
1196  while (pad-- > 0)
1197  {
1198  memcpy(wptr, src, pl);
1199  wptr += pl;
1200  wlen += pl;
1201  col += pw;
1202  }
1203  }
1204  else if (soft)
1205  {
1206  int offset = ((flags & MUTT_FORMAT_ARROWCURSOR) && C_ArrowCursor) ? 3 : 0;
1207  int avail_cols = (cols > offset) ? (cols - offset) : 0;
1208  /* \0-terminate buf for length computation in mutt_wstr_trunc() */
1209  *wptr = '\0';
1210  /* make sure right part is at most as wide as display */
1211  len = mutt_wstr_trunc(tmp, buflen, avail_cols, &wid);
1212  /* truncate left so that right part fits completely in */
1213  wlen = mutt_wstr_trunc(buf, buflen - len, avail_cols - wid, &col);
1214  wptr = buf + wlen;
1215  /* Multi-column characters may be truncated in the middle.
1216  * Add spacing so the right hand side lines up. */
1217  while ((col + wid < avail_cols) && (wlen + len < buflen))
1218  {
1219  *wptr++ = ' ';
1220  wlen++;
1221  col++;
1222  }
1223  }
1224  if ((len + wlen) > buflen)
1225  len = mutt_wstr_trunc(tmp, buflen - wlen, cols - col, NULL);
1226  memcpy(wptr, tmp, len);
1227  wptr += len;
1228  }
1229  break; /* skip rest of input */
1230  }
1231  else if (ch == '|')
1232  {
1233  /* pad to EOL */
1234  int pl, pw;
1235  pl = mutt_mb_charlen(src, &pw);
1236  if (pl <= 0)
1237  {
1238  pl = 1;
1239  pw = 1;
1240  }
1241 
1242  /* see if there's room to add content, else ignore */
1243  if ((col < cols) && (wlen < buflen))
1244  {
1245  int c = (cols - col) / pw;
1246  if ((c > 0) && (wlen + (c * pl) > buflen))
1247  c = ((signed) (buflen - wlen)) / pl;
1248  while (c > 0)
1249  {
1250  memcpy(wptr, src, pl);
1251  wptr += pl;
1252  wlen += pl;
1253  col += pw;
1254  c--;
1255  }
1256  }
1257  break; /* skip rest of input */
1258  }
1259  else
1260  {
1261  bool to_lower = false;
1262  bool no_dots = false;
1263 
1264  while ((ch == '_') || (ch == ':'))
1265  {
1266  if (ch == '_')
1267  to_lower = true;
1268  else if (ch == ':')
1269  no_dots = true;
1270 
1271  ch = *src++;
1272  }
1273 
1274  /* use callback function to handle this case */
1275  src = callback(tmp, sizeof(tmp), col, cols, ch, src, prefix, if_str,
1276  else_str, data, flags);
1277 
1278  if (to_lower)
1279  mutt_str_strlower(tmp);
1280  if (no_dots)
1281  {
1282  char *p = tmp;
1283  for (; *p; p++)
1284  if (*p == '.')
1285  *p = '_';
1286  }
1287 
1288  len = mutt_str_strlen(tmp);
1289  if ((len + wlen) > buflen)
1290  len = mutt_wstr_trunc(tmp, buflen - wlen, cols - col, NULL);
1291 
1292  memcpy(wptr, tmp, len);
1293  wptr += len;
1294  wlen += len;
1295  col += mutt_strwidth(tmp);
1296  }
1297  }
1298  else if (*src == '\\')
1299  {
1300  if (!*++src)
1301  break;
1302  switch (*src)
1303  {
1304  case 'f':
1305  *wptr = '\f';
1306  break;
1307  case 'n':
1308  *wptr = '\n';
1309  break;
1310  case 'r':
1311  *wptr = '\r';
1312  break;
1313  case 't':
1314  *wptr = '\t';
1315  break;
1316  case 'v':
1317  *wptr = '\v';
1318  break;
1319  default:
1320  *wptr = *src;
1321  break;
1322  }
1323  src++;
1324  wptr++;
1325  wlen++;
1326  col++;
1327  }
1328  else
1329  {
1330  int bytes, width;
1331  /* in case of error, simply copy byte */
1332  bytes = mutt_mb_charlen(src, &width);
1333  if (bytes < 0)
1334  {
1335  bytes = 1;
1336  width = 1;
1337  }
1338  if ((bytes > 0) && ((wlen + bytes) < buflen))
1339  {
1340  memcpy(wptr, src, bytes);
1341  wptr += bytes;
1342  src += bytes;
1343  wlen += bytes;
1344  col += width;
1345  }
1346  else
1347  {
1348  src += buflen - wlen;
1349  wlen = buflen;
1350  }
1351  }
1352  }
1353  *wptr = '\0';
1354 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:216
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t *callback, unsigned long data, MuttFormatFlags flags)
Expand expandos (x) in a string.
Definition: muttlib.c:841
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
String manipulation buffer.
Definition: buffer.h:33
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
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:44
char * mutt_str_strlower(char *s)
convert all characters in the string to lowercase
Definition: string.c:509
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
void mutt_buffer_free(struct Buffer **p)
Release a Buffer and its contents.
Definition: buffer.c:134
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:256
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1254
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:2614
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:1204
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:271
struct Buffer * mutt_buffer_from(const char *seed)
Create Buffer from an existing string.
Definition: buffer.c:92
struct Buffer * mutt_buffer_new(void)
Create and initialise a Buffer.
Definition: buffer.c:45
Log at debug level 1.
Definition: logging.h:56
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#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:60
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:227
static int pad(FILE *fp, int col, int i)
Write some padding to a file.
Definition: help.c:256
Log at debug level 3.
Definition: logging.h:58
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:76
WHERE bool C_ArrowCursor
Config: Use an arrow &#39;->&#39; instead of highlighting in the index.
Definition: globals.h:195
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 1366 of file muttlib.c.

1367 {
1368  FILE *fp = NULL;
1369  struct stat s;
1370 
1371  size_t len = mutt_str_strlen(path);
1372  if (len == 0)
1373  {
1374  return NULL;
1375  }
1376 
1377  if (path[len - 1] == '|')
1378  {
1379  /* read from a pipe */
1380 
1381  char *p = mutt_str_strdup(path);
1382 
1383  p[len - 1] = 0;
1384  mutt_endwin();
1385  *thepid = mutt_create_filter(p, NULL, &fp, NULL);
1386  FREE(&p);
1387  }
1388  else
1389  {
1390  if (stat(path, &s) < 0)
1391  return NULL;
1392  if (S_ISDIR(s.st_mode))
1393  {
1394  errno = EINVAL;
1395  return NULL;
1396  }
1397  fp = fopen(path, "r");
1398  *thepid = -1;
1399  }
1400  return fp;
1401 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:216
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define FREE(x)
Definition: memory.h:40
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 1411 of file muttlib.c.

1412 {
1413  char tmp[PATH_MAX];
1414  int ret = 0;
1415 
1416  enum MailboxType magic = mx_path_probe(s, NULL);
1417 
1418 #ifdef USE_POP
1419  if (magic == MUTT_POP)
1420  {
1421  mutt_error(_("Can't save message to POP mailbox"));
1422  return 1;
1423  }
1424 #endif
1425 
1426  if ((magic != MUTT_MAILBOX_ERROR) && (magic != MUTT_UNKNOWN) && !mx_access(s, W_OK))
1427  {
1428  if (C_Confirmappend)
1429  {
1430  snprintf(tmp, sizeof(tmp), _("Append messages to %s?"), s);
1431  enum QuadOption ans = mutt_yesorno(tmp, MUTT_YES);
1432  if (ans == MUTT_NO)
1433  ret = 1;
1434  else if (ans == MUTT_ABORT)
1435  ret = -1;
1436  }
1437  }
1438 
1439 #ifdef USE_NNTP
1440  if (magic == MUTT_NNTP)
1441  {
1442  mutt_error(_("Can't save message to news server"));
1443  return 0;
1444  }
1445 #endif
1446 
1447  if (stat(s, st) != -1)
1448  {
1449  if (magic == MUTT_MAILBOX_ERROR)
1450  {
1451  mutt_error(_("%s is not a mailbox"), s);
1452  return 1;
1453  }
1454  }
1455  else if (magic != MUTT_IMAP)
1456  {
1457  st->st_mtime = 0;
1458  st->st_atime = 0;
1459 
1460  /* pathname does not exist */
1461  if (errno == ENOENT)
1462  {
1463  if (C_Confirmcreate)
1464  {
1465  snprintf(tmp, sizeof(tmp), _("Create %s?"), s);
1466  enum QuadOption ans = mutt_yesorno(tmp, MUTT_YES);
1467  if (ans == MUTT_NO)
1468  ret = 1;
1469  else if (ans == MUTT_ABORT)
1470  ret = -1;
1471  }
1472 
1473  /* user confirmed with MUTT_YES or set C_Confirmcreate */
1474  if (ret == 0)
1475  {
1476  /* create dir recursively */
1477  char *tmp_path = mutt_path_dirname(s);
1478  if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1)
1479  {
1480  /* report failure & abort */
1481  mutt_perror(s);
1482  FREE(&tmp_path);
1483  return 1;
1484  }
1485  FREE(&tmp_path);
1486  }
1487  }
1488  else
1489  {
1490  mutt_perror(s);
1491  return 1;
1492  }
1493  }
1494 
1496  return ret;
1497 }
#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:37
WHERE bool C_Confirmappend
Config: Confirm before appending emails to a mailbox.
Definition: globals.h:205
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
char * mutt_path_dirname(const char *path)
Return a path up to, but not including, the final &#39;/&#39;.
Definition: path.c:409
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
Error occurred examining Mailbox.
Definition: mailbox.h:46
WHERE bool C_Confirmcreate
Config: Confirm before creating a new mailbox.
Definition: globals.h:206
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:872
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:69
&#39;POP3&#39; Mailbox type
Definition: mailbox.h:55
#define PATH_MAX
Definition: mutt.h:50
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
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:180
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:41
enum MailboxType mx_path_probe(const char *path, struct stat *st)
Find a mailbox that understands a path.
Definition: mx.c:1241
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
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 1505 of file muttlib.c.

1506 {
1507  if (C_SleepTime > s)
1508  sleep(C_SleepTime);
1509  else if (s)
1510  sleep(s);
1511 }
WHERE short C_SleepTime
Config: Time to pause after certain info messages.
Definition: globals.h:149
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 1519 of file muttlib.c.

1520 {
1521  static char vstring[256];
1522  snprintf(vstring, sizeof(vstring), "NeoMutt %s%s", PACKAGE_VERSION, GitVer);
1523  return vstring;
1524 }
const char * GitVer
void mutt_encode_path ( char *  buf,
size_t  buflen,
const char *  src 
)

Convert a path into the user's preferred character set.

Parameters
bufBuffer for the result
buflenLength of buffer
srcPath to convert (OPTIONAL)

If src is NULL, the path in buf will be converted in-place.

Definition at line 1534 of file muttlib.c.

1535 {
1536  char *p = mutt_str_strdup(src);
1537  int rc = mutt_ch_convert_string(&p, C_Charset, "us-ascii", 0);
1538  /* 'src' may be NULL, such as when called from the pop3 driver. */
1539  size_t len = mutt_str_strfcpy(buf, (rc == 0) ? p : src, buflen);
1540 
1541  /* convert the path to POSIX "Portable Filename Character Set" */
1542  for (size_t i = 0; i < len; i++)
1543  {
1544  if (!isalnum(buf[i]) && !strchr("/.-_", buf[i]))
1545  {
1546  buf[i] = '_';
1547  }
1548  }
1549  FREE(&p);
1550 }
int mutt_ch_convert_string(char **ps, const char *from, const char *to, int flags)
Convert a string between encodings.
Definition: charset.c:724
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define FREE(x)
Definition: memory.h:40
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:54
int mutt_set_xdg_path ( enum XdgType  type,
char *  buf,
size_t  bufsize 
)

Find an XDG path or its fallback.

Parameters
typeType of XDG variable, e.g. XDG_CONFIG_HOME
bufBuffer to save path
bufsizeBuffer length
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 1561 of file muttlib.c.

1562 {
1563  const char *xdg_env = mutt_str_getenv(xdg_env_vars[type]);
1564  char *xdg = xdg_env ? mutt_str_strdup(xdg_env) : mutt_str_strdup(xdg_defaults[type]);
1565  char *x = xdg; /* strsep() changes xdg, so free x instead later */
1566  char *token = NULL;
1567  int rc = 0;
1568 
1569  while ((token = strsep(&xdg, ":")))
1570  {
1571  if (snprintf(buf, bufsize, "%s/%s/neomuttrc", token, PACKAGE) < 0)
1572  continue;
1573  mutt_expand_path(buf, bufsize);
1574  if (access(buf, F_OK) == 0)
1575  {
1576  rc = 1;
1577  break;
1578  }
1579 
1580  if (snprintf(buf, bufsize, "%s/%s/Muttrc", token, PACKAGE) < 0)
1581  continue;
1582  mutt_expand_path(buf, bufsize);
1583  if (access(buf, F_OK) == 0)
1584  {
1585  rc = 1;
1586  break;
1587  }
1588  }
1589 
1590  FREE(&x);
1591  return rc;
1592 }
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:1084
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define FREE(x)
Definition: memory.h:40
static const char * xdg_defaults[]
Definition: muttlib.c:77
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 1600 of file muttlib.c.

1601 {
1602  enum MailboxType mb_magic = mx_path_probe(path, NULL);
1603 
1604  if (mb_magic == MUTT_IMAP)
1605  imap_get_parent_path(path, buf, buflen);
1606  else if (mb_magic == MUTT_NOTMUCH)
1607  mutt_str_strfcpy(buf, C_Folder, buflen);
1608  else
1609  {
1610  mutt_str_strfcpy(buf, path, buflen);
1611  int n = mutt_str_strlen(buf);
1612  if (n == 0)
1613  return;
1614 
1615  /* remove any final trailing '/' */
1616  if (buf[n - 1] == '/')
1617  buf[n - 1] = '\0';
1618 
1619  /* Remove everything until the next slash */
1620  for (n--; ((n >= 0) && (buf[n] != '/')); n--)
1621  ;
1622 
1623  if (n > 0)
1624  buf[n] = '\0';
1625  else
1626  {
1627  buf[0] = '/';
1628  buf[1] = '\0';
1629  }
1630  }
1631 }
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:300
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:114
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
enum MailboxType mx_path_probe(const char *path, struct stat *st)
Find a mailbox that understands a path.
Definition: mx.c:1241
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
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 1655 of file muttlib.c.

1656 {
1657  /* fast-track in case the paths have been mutt_pretty_mailbox'ified */
1658  if ((a[0] == '+') && (b[0] == '+'))
1659  {
1660  return (mutt_str_strcasecmp(a + 1, "inbox") == 0) ?
1661  -1 :
1662  (mutt_str_strcasecmp(b + 1, "inbox") == 0) ? 1 : 0;
1663  }
1664 
1665  const char *a_end = strrchr(a, '/');
1666  const char *b_end = strrchr(b, '/');
1667 
1668  /* If one path contains a '/', but not the other */
1669  if ((!a_end) ^ (!b_end))
1670  return 0;
1671 
1672  /* If neither path contains a '/' */
1673  if (!a_end)
1674  return 0;
1675 
1676  /* Compare the subpaths */
1677  size_t a_len = a_end - a;
1678  size_t b_len = b_end - b;
1679  size_t min = MIN(a_len, b_len);
1680  int same = (a[min] == '/') && (b[min] == '/') && (a[min + 1] != '\0') &&
1681  (b[min + 1] != '\0') && (mutt_str_strncasecmp(a, b, min) == 0);
1682 
1683  if (!same)
1684  return 0;
1685 
1686  if (mutt_str_strcasecmp(&a[min + 1], "inbox") == 0)
1687  return -1;
1688 
1689  if (mutt_str_strcasecmp(&b[min + 1], "inbox") == 0)
1690  return 1;
1691 
1692  return 0;
1693 }
#define MIN(a, b)
Definition: memory.h:31
int mutt_str_strncasecmp(const char *a, const char *b, size_t l)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:656
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
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 1701 of file muttlib.c.

1702 {
1703  if (!buf || !path)
1704  return;
1705 
1706  mutt_buffer_reset(buf);
1707 
1708  for (; *path; path++)
1709  {
1710  if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path))
1711  mutt_buffer_addch(buf, '_');
1712  else
1713  mutt_buffer_addch(buf, *path);
1714  }
1715 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:271
const char filename_safe_chars[]
Definition: file.c:57

Variable Documentation

struct Regex* C_GecosMask

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

Definition at line 70 of file muttlib.c.

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.

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.

FILE* fp_random
static

Definition at line 462 of file muttlib.c.

const unsigned char base32[] = "abcdefghijklmnopqrstuvwxyz234567"
static

Definition at line 509 of file muttlib.c.