NeoMutt  2018-07-16 +1783-b00bd9
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"
+ 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...
 
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 *s)
 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, struct Address *addr)
 Turn an email address into a filename (for saving) More...
 
void mutt_safe_path (char *buf, size_t buflen, 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...
 

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

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

90 {
91  if (!(buf->data && buf->data[0]))
92  {
93  mutt_buffer_mktemp(buf);
94  }
95  else
96  {
97  struct Buffer *prefix = mutt_buffer_pool_get();
98  mutt_buffer_strcpy(prefix, buf->data);
100  mutt_buffer_printf(buf, "%s/%s", NONULL(C_Tmpdir), mutt_b2s(prefix));
101 
102  struct stat sb;
103  if ((lstat(mutt_b2s(buf), &sb) == -1) && (errno == ENOENT))
104  goto out;
105 
106  char *suffix = strrchr(prefix->data, '.');
107  if (suffix)
108  {
109  *suffix = '\0';
110  suffix++;
111  }
112  mutt_buffer_mktemp_pfx_sfx(buf, mutt_b2s(prefix), suffix);
113 
114  out:
115  mutt_buffer_pool_release(&prefix);
116  }
117 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
#define NONULL(x)
Definition: string2.h:36
#define mutt_buffer_mktemp_pfx_sfx(buf, prefix, suffix)
Definition: muttlib.h:78
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:200
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:608
#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:322
char * data
pointer to data
Definition: buffer.h:35
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:52
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: buffer.c:409
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: buffer.c:398

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

128 {
129  return mutt_expand_path_regex(buf, buflen, false);
130 }
char * mutt_expand_path_regex(char *buf, size_t buflen, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:338

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

140 {
141  const char *s = NULL;
142  const char *tail = "";
143 
144  bool recurse = false;
145 
146  struct Buffer *p = mutt_buffer_pool_get();
147  struct Buffer *q = mutt_buffer_pool_get();
148  struct Buffer *tmp = mutt_buffer_pool_get();
149 
150  do
151  {
152  recurse = false;
153  s = mutt_b2s(buf);
154 
155  switch (*s)
156  {
157  case '~':
158  {
159  if ((*(s + 1) == '/') || (*(s + 1) == 0))
160  {
162  tail = s + 1;
163  }
164  else
165  {
166  char *t = strchr(s + 1, '/');
167  if (t)
168  *t = '\0';
169 
170  struct passwd *pw = getpwnam(s + 1);
171  if (pw)
172  {
173  mutt_buffer_strcpy(p, pw->pw_dir);
174  if (t)
175  {
176  *t = '/';
177  tail = t;
178  }
179  else
180  tail = "";
181  }
182  else
183  {
184  /* user not found! */
185  if (t)
186  *t = '/';
188  tail = s;
189  }
190  }
191  break;
192  }
193 
194  case '=':
195  case '+':
196  {
197  enum MailboxType mb_type = mx_path_probe(C_Folder, NULL);
198 
199  /* if folder = {host} or imap[s]://host/: don't append slash */
200  if ((mb_type == MUTT_IMAP) && ((C_Folder[strlen(C_Folder) - 1] == '}') ||
201  (C_Folder[strlen(C_Folder) - 1] == '/')))
202  {
204  }
205  else if (mb_type == MUTT_NOTMUCH)
207  else if (C_Folder && *C_Folder && (C_Folder[strlen(C_Folder) - 1] == '/'))
209  else
210  mutt_buffer_printf(p, "%s/", NONULL(C_Folder));
211 
212  tail = s + 1;
213  break;
214  }
215 
216  /* elm compatibility, @ expands alias to user name */
217 
218  case '@':
219  {
220  struct Address *alias = mutt_alias_lookup(s + 1);
221  if (alias)
222  {
223  struct Email *e = mutt_email_new();
224  e->env = mutt_env_new();
225  e->env->from = alias;
226  e->env->to = alias;
227 
228  /* TODO: fix mutt_default_save() to use Buffer */
230  mutt_default_save(p->data, p->dsize, e);
232 
233  e->env->from = NULL;
234  e->env->to = NULL;
235  mutt_email_free(&e);
236  /* Avoid infinite recursion if the resulting folder starts with '@' */
237  if (*(mutt_b2s(p)) != '@')
238  recurse = true;
239 
240  tail = "";
241  }
242  break;
243  }
244 
245  case '>':
246  {
248  tail = s + 1;
249  break;
250  }
251 
252  case '<':
253  {
255  tail = s + 1;
256  break;
257  }
258 
259  case '!':
260  {
261  if (*(s + 1) == '!')
262  {
264  tail = s + 2;
265  }
266  else
267  {
269  tail = s + 1;
270  }
271  break;
272  }
273 
274  case '-':
275  {
277  tail = s + 1;
278  break;
279  }
280 
281  case '^':
282  {
284  tail = s + 1;
285  break;
286  }
287 
288  default:
289  {
291  tail = s;
292  }
293  }
294 
295  if (regex && *(mutt_b2s(p)) && !recurse)
296  {
298  mutt_buffer_printf(tmp, "%s%s", mutt_b2s(q), tail);
299  }
300  else
301  mutt_buffer_printf(tmp, "%s%s", mutt_b2s(p), tail);
302 
303  mutt_buffer_strcpy(buf, mutt_b2s(tmp));
304  } while (recurse);
305 
309 
310 #ifdef USE_IMAP
311  /* Rewrite IMAP path in canonical form - aids in string comparisons of
312  * folders. May possibly fail, in which case buf should be the same. */
313  if (imap_path_probe(mutt_b2s(buf), NULL) == MUTT_IMAP)
314  imap_expand_path(buf);
315 #endif
316 }
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: magic.h:43
#define NONULL(x)
Definition: string2.h:36
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:83
The envelope/body of an email.
Definition: email.h:37
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2440
void mutt_buffer_increase_size(struct Buffer *buf, size_t new_size)
Increase the allocated size of a buffer.
Definition: buffer.c:347
struct Address * to
Definition: envelope.h:42
String manipulation buffer.
Definition: buffer.h:33
An email address.
Definition: address.h:32
WHERE char * LastFolder
Previously selected mailbox.
Definition: globals.h:54
&#39;IMAP&#39; Mailbox type
Definition: magic.h:42
struct Email * mutt_email_new(void)
Create a new Email.
Definition: email.c:63
struct Address * mutt_alias_lookup(const char *s)
Find an Alias.
Definition: alias.c:279
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:200
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:661
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:2485
WHERE char * C_Mbox
Config: Folder that receives read emails (see Move)
Definition: globals.h:112
struct Envelope * env
envelope information
Definition: email.h:92
WHERE char * HomeDir
User&#39;s home directory.
Definition: globals.h:48
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: globals.h:53
struct Address * from
Definition: envelope.h:41
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:40
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:221
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition: file.c:627
#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:322
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:114
#define PATH_MAX
Definition: mutt.h:49
MailboxType
Supported mailbox formats.
Definition: magic.h:33
char * data
pointer to data
Definition: buffer.h:35
void mutt_email_free(struct Email **e)
Free an Email.
Definition: email.c:41
WHERE char * C_Spoolfile
Config: Inbox.
Definition: globals.h:142
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: buffer.c:409
enum MailboxType mx_path_probe(const char *path, struct stat *st)
Find a mailbox that understands a path.
Definition: mx.c:1226
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: buffer.c:398

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

325 {
326  mutt_buffer_expand_path_regex(buf, false);
327 }
void mutt_buffer_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:139

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

339 {
340  struct Buffer *tmp = mutt_buffer_pool_get();
341 
342  mutt_buffer_addstr(tmp, NONULL(buf));
343  mutt_buffer_expand_path_regex(tmp, regex);
344  mutt_str_strfcpy(buf, mutt_b2s(tmp), buflen);
345 
347 
348  return buf;
349 }
#define NONULL(x)
Definition: string2.h:36
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:139
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:264
#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:753
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: buffer.c:409
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: buffer.c:398

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

364 {
365  regmatch_t pat_match[1];
366  size_t pwnl;
367  char *p = NULL;
368 
369  if (!pw || !pw->pw_gecos)
370  return NULL;
371 
372  memset(dest, 0, destlen);
373 
374  if (C_GecosMask && C_GecosMask->regex)
375  {
376  if (regexec(C_GecosMask->regex, pw->pw_gecos, 1, pat_match, 0) == 0)
377  {
378  mutt_str_strfcpy(dest, pw->pw_gecos + pat_match[0].rm_so,
379  MIN(pat_match[0].rm_eo - pat_match[0].rm_so + 1, destlen));
380  }
381  }
382  else if ((p = strchr(pw->pw_gecos, ',')))
383  mutt_str_strfcpy(dest, pw->pw_gecos, MIN(destlen, p - pw->pw_gecos + 1));
384  else
385  mutt_str_strfcpy(dest, pw->pw_gecos, destlen);
386 
387  pwnl = strlen(pw->pw_name);
388 
389  for (int idx = 0; dest[idx]; idx++)
390  {
391  if (dest[idx] == '&')
392  {
393  memmove(&dest[idx + pwnl], &dest[idx + 1],
394  MAX((ssize_t)(destlen - idx - pwnl - 1), 0));
395  memcpy(&dest[idx], pw->pw_name, MIN(destlen - idx - 1, pwnl));
396  dest[idx] = toupper((unsigned char) dest[idx]);
397  }
398  }
399 
400  return dest;
401 }
#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:69
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:753

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

410 {
411  switch (m->type)
412  {
413  case TYPE_TEXT:
414  if (mutt_str_strcasecmp("plain", m->subtype) == 0)
415  return false;
416  break;
417  case TYPE_APPLICATION:
419  return false;
421  return false;
422  break;
423 
424  case TYPE_MULTIPART:
425  case TYPE_MESSAGE:
426  return false;
427  }
428 
429  return true;
430 }
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:524
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:583
unsigned int type
content-type primary type
Definition: body.h:72
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:129
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:631
#define WithCrypto
Definition: ncrypt.h:155
Type: &#39;application/*&#39;.
Definition: mime.h:33
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: ncrypt.h:130

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

438 {
439  int t = b->type;
440  char *s = b->subtype;
441 
443  return false;
444 
445  if (t == TYPE_TEXT)
446  return true;
447 
448  if (t == TYPE_MESSAGE)
449  {
450  if (mutt_str_strcasecmp("delivery-status", s) == 0)
451  return true;
452  }
453 
454  if (((WithCrypto & APPLICATION_PGP) != 0) && (t == TYPE_APPLICATION))
455  {
456  if (mutt_str_strcasecmp("pgp-keys", s) == 0)
457  return true;
458  }
459 
460  return false;
461 }
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:524
Type: &#39;text/*&#39;.
Definition: mime.h:38
unsigned int type
content-type primary type
Definition: body.h:72
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:129
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:631
#define WithCrypto
Definition: ncrypt.h:155
Type: &#39;application/*&#39;.
Definition: mime.h:33

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

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

+ Here is the caller graph for this function:

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

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

uint32_t mutt_rand32 ( void  )

Create a 32-bit random number.

Return values
numRandom number

Definition at line 531 of file muttlib.c.

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

+ Here is the call graph for this function:

uint64_t mutt_rand64 ( void  )

Create a 64-bit random number.

Return values
numRandom number

Definition at line 544 of file muttlib.c.

545 {
546  uint64_t num = 0;
547 
548  if (mutt_randbuf(&num, sizeof(num)) < 0)
549  mutt_exit(1);
550  return num;
551 }
int mutt_randbuf(void *buf, size_t buflen)
Fill a buffer with randomness.
Definition: muttlib.c:472
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:202

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

563 {
564  mutt_buffer_printf(buf, "%s/%s-%s-%d-%d-%ld%ld%s%s", NONULL(C_Tmpdir), NONULL(prefix),
565  NONULL(C_Hostname), (int) getuid(), (int) getpid(),
566  random(), random(), suffix ? "." : "", NONULL(suffix));
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:36
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:200
#define mutt_b2s(buf)
Definition: buffer.h:42
const char * line
Definition: common.c:35
Log at debug level 1.
Definition: logging.h:56
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:52
WHERE char * C_Hostname
Config: Fully-qualified domain name of this machine.
Definition: globals.h:106
#define mutt_debug(LEVEL,...)
Definition: logging.h:80
Log at debug level 3.
Definition: logging.h:58

+ Here is the call graph for this function:

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:36
const char * line
Definition: common.c:35
uint64_t mutt_rand64(void)
Create a 64-bit random number.
Definition: muttlib.c:544
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:80
Log at debug level 3.
Definition: logging.h:58

+ Here is the call graph for this function:

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  char *p = buf, *q = buf;
618  size_t len;
619  enum UrlScheme scheme;
620  char tmp[PATH_MAX];
621 
622  scheme = url_check_scheme(buf);
623 
624  if ((scheme == U_IMAP) || (scheme == U_IMAPS))
625  {
626  imap_pretty_mailbox(buf, buflen, C_Folder);
627  return;
628  }
629 
630  if (scheme == U_NOTMUCH)
631  return;
632 
633  /* if buf is an url, only collapse path component */
634  if (scheme != U_UNKNOWN)
635  {
636  p = strchr(buf, ':') + 1;
637  if (strncmp(p, "//", 2) == 0)
638  q = strchr(p + 2, '/');
639  if (!q)
640  q = strchr(p, '\0');
641  p = q;
642  }
643 
644  /* cleanup path */
645  if (strstr(p, "//") || strstr(p, "/./"))
646  {
647  /* first attempt to collapse the pathname, this is more
648  * lightweight than realpath() and doesn't resolve links */
649  while (*p)
650  {
651  if ((p[0] == '/') && (p[1] == '/'))
652  {
653  *q++ = '/';
654  p += 2;
655  }
656  else if ((p[0] == '/') && (p[1] == '.') && (p[2] == '/'))
657  {
658  *q++ = '/';
659  p += 3;
660  }
661  else
662  *q++ = *p++;
663  }
664  *q = '\0';
665  }
666  else if (strstr(p, "..") && ((scheme == U_UNKNOWN) || (scheme == U_FILE)) &&
667  realpath(p, tmp))
668  {
669  mutt_str_strfcpy(p, tmp, buflen - (p - buf));
670  }
671 
672  if ((len = mutt_str_startswith(buf, C_Folder, CASE_MATCH)) && (buf[len] == '/'))
673  {
674  *buf++ = '=';
675  memmove(buf, buf + len, mutt_str_strlen(buf + len) + 1);
676  }
677  else if ((len = mutt_str_startswith(buf, HomeDir, CASE_MATCH)) && (buf[len] == '/'))
678  {
679  *buf++ = '~';
680  memmove(buf, buf + len - 1, mutt_str_strlen(buf + len - 1) + 1);
681  }
682 }
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:66
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:669
enum UrlScheme url_check_scheme(const char *s)
Check the protocol of a URL.
Definition: url.c:133
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:49
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:753
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:687
Url is file://.
Definition: url.h:35

+ Here is the caller graph for this function:

void mutt_buffer_pretty_mailbox ( struct Buffer s)

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

Parameters
sBuffer containing Mailbox name

Definition at line 688 of file muttlib.c.

689 {
690  /* This reduces the size of the Buffer, so we can pass it through.
691  * We adjust the size just to make sure s->data is not NULL though */
695 }
void mutt_buffer_increase_size(struct Buffer *buf, size_t new_size)
Increase the allocated size of a buffer.
Definition: buffer.c:347
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:221
#define PATH_MAX
Definition: mutt.h:49
char * data
pointer to data
Definition: buffer.h:35

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

711 {
712  struct stat st;
713 
714  mutt_str_strfcpy(fname, path, flen);
715  if (access(fname, F_OK) != 0)
716  return 0;
717  if (stat(fname, &st) != 0)
718  return -1;
719  if (S_ISDIR(st.st_mode))
720  {
721  enum QuadOption ans = MUTT_NO;
722  if (directory)
723  {
724  switch (mutt_multi_choice
725  /* L10N: Means "The path you specified as the destination file is a directory."
726  See the msgid "Save to file: " (alias.c, recvattach.c)
727  These three letters correspond to the choices in the string. */
728  (_("File is a directory, save under it: (y)es, (n)o, (a)ll?"), _("yna")))
729  {
730  case 3: /* all */
731  mutt_str_replace(directory, fname);
732  break;
733  case 1: /* yes */
734  FREE(directory);
735  break;
736  case -1: /* abort */
737  FREE(directory);
738  return -1;
739  case 2: /* no */
740  FREE(directory);
741  return 1;
742  }
743  }
744  /* L10N: Means "The path you specified as the destination file is a directory."
745  See the msgid "Save to file: " (alias.c, recvattach.c) */
746  else if ((ans = mutt_yesorno(_("File is a directory, save under it?"), MUTT_YES)) != MUTT_YES)
747  return (ans == MUTT_NO) ? 1 : -1;
748 
749  char tmp[PATH_MAX];
750  mutt_str_strfcpy(tmp, mutt_path_basename(NONULL(attname)), sizeof(tmp));
751  if ((mutt_get_field(_("File under directory: "), tmp, sizeof(tmp),
752  MUTT_FILE | MUTT_CLEAR) != 0) ||
753  !tmp[0])
754  {
755  return -1;
756  }
757  mutt_path_concat(fname, path, tmp, flen);
758  }
759 
760  if ((*opt == MUTT_SAVE_NO_FLAGS) && (access(fname, F_OK) == 0))
761  {
762  switch (
763  mutt_multi_choice(_("File exists, (o)verwrite, (a)ppend, or (c)ancel?"),
764  // L10N: Options for: File exists, (o)verwrite, (a)ppend, or (c)ancel?
765  _("oac")))
766  {
767  case -1: /* abort */
768  return -1;
769  case 3: /* cancel */
770  return 1;
771 
772  case 2: /* append */
773  *opt = MUTT_SAVE_APPEND;
774  break;
775  case 1: /* overwrite */
776  *opt = MUTT_SAVE_OVERWRITE;
777  break;
778  }
779  }
780  return 0;
781 }
#define NONULL(x)
Definition: string2.h:36
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:67
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:306
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
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:824
#define PATH_MAX
Definition: mutt.h:49
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:753
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:456
#define MUTT_FILE
Do file completion.
Definition: mutt.h:63
Append to existing file.
Definition: mutt_attach.h:55
#define FREE(x)
Definition: memory.h:40
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
QuadOption
Possible values for a quad-option.
Definition: quad.h:35

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_save_path ( char *  buf,
size_t  buflen,
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 792 of file muttlib.c.

793 {
794  if (addr && addr->mailbox)
795  {
796  mutt_str_strfcpy(buf, addr->mailbox, buflen);
797  if (!C_SaveAddress)
798  {
799  char *p = strpbrk(buf, "%@");
800  if (p)
801  *p = '\0';
802  }
803  mutt_str_strlower(buf);
804  }
805  else
806  *buf = '\0';
807 }
char * mailbox
mailbox and host address
Definition: address.h:35
char * mutt_str_strlower(char *s)
convert all characters in the string to lowercase
Definition: string.c:512
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:753
WHERE bool C_SaveAddress
Config: Use sender&#39;s full address as a default save folder.
Definition: globals.h:246

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_safe_path ( char *  buf,
size_t  buflen,
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 817 of file muttlib.c.

818 {
819  mutt_save_path(buf, buflen, a);
820  for (char *p = buf; *p; p++)
821  if ((*p == '/') || IS_SPACE(*p) || !IsPrint((unsigned char) *p))
822  *p = '_';
823 }
#define IsPrint(ch)
Definition: mbyte.h:38
#define IS_SPACE(ch)
Definition: string2.h:37
void mutt_save_path(char *buf, size_t buflen, struct Address *addr)
Turn an email address into a filename (for saving)
Definition: muttlib.c:792

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1360 {
1361  FILE *fp = NULL;
1362  struct stat s;
1363 
1364  size_t len = mutt_str_strlen(path);
1365  if (len == 0)
1366  {
1367  return NULL;
1368  }
1369 
1370  if (path[len - 1] == '|')
1371  {
1372  /* read from a pipe */
1373 
1374  char *p = mutt_str_strdup(path);
1375 
1376  p[len - 1] = 0;
1377  mutt_endwin();
1378  *thepid = mutt_create_filter(p, NULL, &fp, NULL);
1379  FREE(&p);
1380  }
1381  else
1382  {
1383  if (stat(path, &s) < 0)
1384  return NULL;
1385  if (S_ISDIR(s.st_mode))
1386  {
1387  errno = EINVAL;
1388  return NULL;
1389  }
1390  fp = fopen(path, "r");
1391  *thepid = -1;
1392  }
1393  return fp;
1394 }
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:669
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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1405 {
1406  char tmp[PATH_MAX];
1407  int ret = 0;
1408 
1409  enum MailboxType magic = mx_path_probe(s, NULL);
1410 
1411 #ifdef USE_POP
1412  if (magic == MUTT_POP)
1413  {
1414  mutt_error(_("Can't save message to POP mailbox"));
1415  return 1;
1416  }
1417 #endif
1418 
1419  if ((magic != MUTT_MAILBOX_ERROR) && (magic != MUTT_UNKNOWN) && !mx_access(s, W_OK))
1420  {
1421  if (C_Confirmappend)
1422  {
1423  snprintf(tmp, sizeof(tmp), _("Append messages to %s?"), s);
1424  enum QuadOption ans = mutt_yesorno(tmp, MUTT_YES);
1425  if (ans == MUTT_NO)
1426  ret = 1;
1427  else if (ans == MUTT_ABORT)
1428  ret = -1;
1429  }
1430  }
1431 
1432 #ifdef USE_NNTP
1433  if (magic == MUTT_NNTP)
1434  {
1435  mutt_error(_("Can't save message to news server"));
1436  return 0;
1437  }
1438 #endif
1439 
1440  if (stat(s, st) != -1)
1441  {
1442  if (magic == MUTT_MAILBOX_ERROR)
1443  {
1444  mutt_error(_("%s is not a mailbox"), s);
1445  return 1;
1446  }
1447  }
1448  else if (magic != MUTT_IMAP)
1449  {
1450  st->st_mtime = 0;
1451  st->st_atime = 0;
1452 
1453  /* pathname does not exist */
1454  if (errno == ENOENT)
1455  {
1456  if (C_Confirmcreate)
1457  {
1458  snprintf(tmp, sizeof(tmp), _("Create %s?"), s);
1459  enum QuadOption ans = mutt_yesorno(tmp, MUTT_YES);
1460  if (ans == MUTT_NO)
1461  ret = 1;
1462  else if (ans == MUTT_ABORT)
1463  ret = -1;
1464  }
1465 
1466  /* user confirmed with MUTT_YES or set C_Confirmcreate */
1467  if (ret == 0)
1468  {
1469  /* create dir recursively */
1470  char *tmp_path = mutt_path_dirname(s);
1471  if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1)
1472  {
1473  /* report failure & abort */
1474  mutt_perror(s);
1475  FREE(&tmp_path);
1476  return 1;
1477  }
1478  FREE(&tmp_path);
1479  }
1480  }
1481  else
1482  {
1483  mutt_perror(s);
1484  return 1;
1485  }
1486  }
1487 
1489  return ret;
1490 }
#define mutt_perror(...)
Definition: logging.h:84
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: magic.h:41
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
&#39;IMAP&#39; Mailbox type
Definition: magic.h:42
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:866
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:69
#define PATH_MAX
Definition: mutt.h:49
MailboxType
Supported mailbox formats.
Definition: magic.h:33
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
Error occurred examining mailbox.
Definition: magic.h:35
Mailbox wasn&#39;t recognised.
Definition: magic.h:36
#define mutt_error(...)
Definition: logging.h:83
#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:163
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:1226
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
&#39;POP3&#39; Mailbox type
Definition: magic.h:44

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1499 {
1500  if (C_SleepTime > s)
1501  sleep(C_SleepTime);
1502  else if (s)
1503  sleep(s);
1504 }
WHERE short C_SleepTime
Config: Time to pause after certain info messages.
Definition: globals.h:149

+ Here is the caller graph for this function:

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

1513 {
1514  static char vstring[256];
1515  snprintf(vstring, sizeof(vstring), "NeoMutt %s%s", PACKAGE_VERSION, GitVer);
1516  return vstring;
1517 }
const char * GitVer

+ Here is the caller graph for this function:

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

1528 {
1529  char *p = mutt_str_strdup(src);
1530  int rc = mutt_ch_convert_string(&p, C_Charset, "us-ascii", 0);
1531  /* 'src' may be NULL, such as when called from the pop3 driver. */
1532  size_t len = mutt_str_strfcpy(buf, (rc == 0) ? p : src, buflen);
1533 
1534  /* convert the path to POSIX "Portable Filename Character Set" */
1535  for (size_t i = 0; i < len; i++)
1536  {
1537  if (!isalnum(buf[i]) && !strchr("/.-_", buf[i]))
1538  {
1539  buf[i] = '_';
1540  }
1541  }
1542  FREE(&p);
1543 }
int mutt_ch_convert_string(char **ps, const char *from, const char *to, int flags)
Convert a string between encodings.
Definition: charset.c:723
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:753
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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1555 {
1556  const char *xdg_env = mutt_str_getenv(xdg_env_vars[type]);
1557  char *xdg = xdg_env ? mutt_str_strdup(xdg_env) : mutt_str_strdup(xdg_defaults[type]);
1558  char *x = xdg; /* strsep() changes xdg, so free x instead later */
1559  char *token = NULL;
1560  int rc = 0;
1561 
1562  while ((token = strsep(&xdg, ":")))
1563  {
1564  if (snprintf(buf, bufsize, "%s/%s/neomuttrc", token, PACKAGE) < 0)
1565  continue;
1566  mutt_expand_path(buf, bufsize);
1567  if (access(buf, F_OK) == 0)
1568  {
1569  rc = 1;
1570  break;
1571  }
1572 
1573  if (snprintf(buf, bufsize, "%s/%s/Muttrc", token, PACKAGE) < 0)
1574  continue;
1575  mutt_expand_path(buf, bufsize);
1576  if (access(buf, F_OK) == 0)
1577  {
1578  rc = 1;
1579  break;
1580  }
1581  }
1582 
1583  FREE(&x);
1584  return rc;
1585 }
static const char * xdg_env_vars[]
Definition: muttlib.c:71
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:1086
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:127
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:76

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1594 {
1595  enum MailboxType mb_magic = mx_path_probe(path, NULL);
1596 
1597  if (mb_magic == MUTT_IMAP)
1598  imap_get_parent_path(path, buf, buflen);
1599  else if (mb_magic == MUTT_NOTMUCH)
1600  mutt_str_strfcpy(buf, C_Folder, buflen);
1601  else
1602  {
1603  mutt_str_strfcpy(buf, path, buflen);
1604  int n = mutt_str_strlen(buf);
1605  if (n == 0)
1606  return;
1607 
1608  /* remove any final trailing '/' */
1609  if (buf[n - 1] == '/')
1610  buf[n - 1] = '\0';
1611 
1612  /* Remove everything until the next slash */
1613  for (n--; ((n >= 0) && (buf[n] != '/')); n--)
1614  ;
1615 
1616  if (n > 0)
1617  buf[n] = '\0';
1618  else
1619  {
1620  buf[0] = '/';
1621  buf[1] = '\0';
1622  }
1623  }
1624 }
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: magic.h:43
&#39;IMAP&#39; Mailbox type
Definition: magic.h:42
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:669
void imap_get_parent_path(const char *path, char *buf, size_t buflen)
Get the path of the parent folder.
Definition: util.c:301
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:114
MailboxType
Supported mailbox formats.
Definition: magic.h:33
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:753
enum MailboxType mx_path_probe(const char *path, struct stat *st)
Find a mailbox that understands a path.
Definition: mx.c:1226

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1649 {
1650  /* fast-track in case the paths have been mutt_pretty_mailbox'ified */
1651  if ((a[0] == '+') && (b[0] == '+'))
1652  {
1653  return (mutt_str_strcasecmp(a + 1, "inbox") == 0) ?
1654  -1 :
1655  (mutt_str_strcasecmp(b + 1, "inbox") == 0) ? 1 : 0;
1656  }
1657 
1658  const char *a_end = strrchr(a, '/');
1659  const char *b_end = strrchr(b, '/');
1660 
1661  /* If one path contains a '/', but not the other */
1662  if (!a_end ^ !b_end)
1663  return 0;
1664 
1665  /* If neither path contains a '/' */
1666  if (!a_end)
1667  return 0;
1668 
1669  /* Compare the subpaths */
1670  size_t a_len = a_end - a;
1671  size_t b_len = b_end - b;
1672  size_t min = MIN(a_len, b_len);
1673  int same = (a[min] == '/') && (b[min] == '/') && (a[min + 1] != '\0') &&
1674  (b[min + 1] != '\0') && (mutt_str_strncasecmp(a, b, min) == 0);
1675 
1676  if (!same)
1677  return 0;
1678 
1679  if (mutt_str_strcasecmp(&a[min + 1], "inbox") == 0)
1680  return -1;
1681 
1682  if (mutt_str_strcasecmp(&b[min + 1], "inbox") == 0)
1683  return 1;
1684 
1685  return 0;
1686 }
#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:659
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:631

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

struct Regex* C_GecosMask

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

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

FILE* fp_random
static

Definition at line 463 of file muttlib.c.

const unsigned char base32[] = "abcdefghijklmnopqrstuvwxyz234567"
static

Definition at line 510 of file muttlib.c.