ADDRESS *mutt_default_from (void) { ADDRESS *adr; const char *fqdn = mutt_fqdn(1); /* * Note: We let $from override $realname here. Is this the right * thing to do? */ if (From) adr = rfc822_cpy_adr_real (From); else if (option (OPTUSEDOMAIN)) { adr = rfc822_new_address (); adr->mailbox = safe_malloc (mutt_strlen (Username) + mutt_strlen (fqdn) + 2); sprintf (adr->mailbox, "%s@%s", NONULL(Username), NONULL(fqdn)); /* __SPRINTF_CHECKED__ */ } else { adr = rfc822_new_address (); adr->mailbox = safe_strdup (NONULL(Username)); } return (adr); }
static void redraw_mix_line (LIST *chain) { int c; char *t; mvaddstr (HDR_MIX, 0, " Mix: "); if (!chain) { addstr ("<no chain defined>"); clrtoeol (); return; } for (c = 12; chain; chain = chain->next) { t = chain->data; if (t && t[0] == '0' && t[1] == '\0') t = "<random>"; if (c + mutt_strlen (t) + 2 >= COLS) break; addstr (NONULL(t)); if (chain->next) addstr (", "); c += mutt_strlen (t) + 2; } }
int mutt_addrlist_to_local (ADDRESS *a) { char *user, *domain; char *tmp = NULL; for (; a; a = a->next) { if (!a->mailbox) continue; if (!check_idn (a)) continue; if (mbox_to_udomain (a->mailbox, &user, &domain) == -1) continue; if (mutt_idna_to_local (domain, &tmp, 0) == 0) { safe_realloc (&a->mailbox, mutt_strlen (user) + mutt_strlen (tmp) + 2); sprintf (a->mailbox, "%s@%s", NONULL (user), NONULL (tmp)); /* __SPRINTF_CHECKED__ */ a->idn_checked = 0; } FREE (&tmp); } return 0; }
/* collapse the pathname using ~ or = when possible */ void mutt_pretty_mailbox (char *s) { char *p = s, *q = s; size_t len; /* first attempt to collapse the pathname */ while (*p) { if (*p == '/' && p[1] == '/') { *q++ = '/'; p += 2; } else if (p[0] == '/' && p[1] == '.' && p[2] == '/') { *q++ = '/'; p += 3; } else *q++ = *p++; } *q = 0; if (mutt_strncmp (s, Maildir, (len = mutt_strlen (Maildir))) == 0 && s[len] == '/') { *s++ = '='; strcpy (s, s + len); } else if (mutt_strncmp (s, Homedir, (len = mutt_strlen (Homedir))) == 0 && s[len] == '/') { *s++ = '~'; strcpy (s, s + len - 1); } }
/* convert just for displaying purposes */ const char *mutt_addr_for_display (ADDRESS *a) { static char *buff = NULL; char *tmp = NULL; /* user and domain will be either allocated or reseted to the NULL in * the mbox_to_udomain(), but for safety... */ char *domain = NULL; char *user = NULL; FREE (&buff); if (!check_idn (a)) return a->mailbox; if (mbox_to_udomain (a->mailbox, &user, &domain) != 0) return a->mailbox; if (mutt_idna_to_local (domain, &tmp, MI_MAY_BE_IRREVERSIBLE) != 0) { FREE (&tmp); return a->mailbox; } safe_realloc (&buff, mutt_strlen (tmp) + mutt_strlen (user) + 2); sprintf (buff, "%s@%s", NONULL(user), NONULL(tmp)); /* __SPRINTF_CHECKED__ */ FREE (&tmp); return buff; }
static void format_address_header (char **h, ADDRESS *a) { char buf[HUGE_STRING]; char cbuf[STRING]; char c2buf[STRING]; char *p = NULL; int l, linelen, buflen, count, cbuflen, c2buflen, plen; linelen = mutt_strlen (*h); plen = linelen; buflen = linelen + 3; safe_realloc (h, buflen); for (count = 0; a; a = a->next, count++) { ADDRESS *tmp = a->next; a->next = NULL; *buf = *cbuf = *c2buf = '\0'; l = rfc822_write_address (buf, sizeof (buf), a, 0); a->next = tmp; if (count && linelen + l > 74) { strcpy (cbuf, "\n\t"); /* __STRCPY_CHECKED__ */ linelen = l + 8; } else { if (a->mailbox) { strcpy (cbuf, " "); /* __STRCPY_CHECKED__ */ linelen++; } linelen += l; } if (!a->group && a->next && a->next->mailbox) { linelen++; buflen++; strcpy (c2buf, ","); /* __STRCPY_CHECKED__ */ } cbuflen = mutt_strlen (cbuf); c2buflen = mutt_strlen (c2buf); buflen += l + cbuflen + c2buflen; safe_realloc (h, buflen); p = *h; strcat (p + plen, cbuf); /* __STRCAT_CHECKED__ */ plen += cbuflen; strcat (p + plen, buf); /* __STRCAT_CHECKED__ */ plen += l; strcat (p + plen, c2buf); /* __STRCAT_CHECKED__ */ plen += c2buflen; } /* Space for this was allocated in the beginning of this function. */ strcat (p + plen, "\n"); /* __STRCAT_CHECKED__ */ }
/* note: it is assumed that `buf' is nul terminated! */ int rfc822_write_address (char *buf, size_t buflen, ADDRESS *addr, int display) { char *pbuf = buf; size_t len = mutt_strlen (buf); buflen--; /* save room for the terminal nul */ if (len > 0) { if (len > buflen) return pbuf - buf; /* safety check for bogus arguments */ pbuf += len; buflen -= len; if (!buflen) goto done; *pbuf++ = ','; buflen--; if (!buflen) goto done; *pbuf++ = ' '; buflen--; } for (; addr && buflen > 0; addr = addr->next) { /* use buflen+1 here because we already saved space for the trailing nul char, and the subroutine can make use of it */ rfc822_write_address_single (pbuf, buflen + 1, addr, display); /* this should be safe since we always have at least 1 char passed into the above call, which means `pbuf' should always be nul terminated */ len = mutt_strlen (pbuf); pbuf += len; buflen -= len; /* if there is another address, and its not a group mailbox name or group terminator, add a comma to separate the addresses */ if (addr->next && addr->next->mailbox && !addr->group) { if (!buflen) goto done; *pbuf++ = ','; buflen--; if (!buflen) goto done; *pbuf++ = ' '; buflen--; } } done: *pbuf = 0; return pbuf - buf; }
void rfc822_qualify (ADDRESS *addr, const char *host) { char *p; for (; addr; addr = addr->next) if (!addr->group && addr->mailbox && strchr (addr->mailbox, '@') == NULL) { p = safe_malloc (mutt_strlen (addr->mailbox) + mutt_strlen (host) + 2); sprintf (p, "%s@%s", addr->mailbox, host); /* __SPRINTF_CHECKED__ */ FREE (&addr->mailbox); addr->mailbox = p; } }
/* imap_pretty_mailbox: called by mutt_pretty_mailbox to make IMAP paths * look nice. */ void imap_pretty_mailbox (char* path) { IMAP_MBOX home, target; ciss_url_t url; char* delim; int tlen; int hlen = 0; char home_match = 0; if (imap_parse_path (path, &target) < 0) return; tlen = mutt_strlen (target.mbox); /* check whether we can do '=' substitution */ if (mx_is_imap(Maildir) && !imap_parse_path (Maildir, &home)) { hlen = mutt_strlen (home.mbox); if (tlen && mutt_account_match (&home.account, &target.account) && !mutt_strncmp (home.mbox, target.mbox, hlen)) { if (! hlen) home_match = 1; else if (ImapDelimChars) for (delim = ImapDelimChars; *delim != '\0'; delim++) if (target.mbox[hlen] == *delim) home_match = 1; } FREE (&home.mbox); } /* do the '=' substitution */ if (home_match) { *path++ = '='; /* copy remaining path, skipping delimiter */ if (! hlen) hlen = -1; memcpy (path, target.mbox + hlen + 1, tlen - hlen - 1); path[tlen - hlen - 1] = '\0'; } else { mutt_account_tourl (&target.account, &url); url.path = target.mbox; /* FIXME: That hard-coded constant is bogus. But we need the actual * size of the buffer from mutt_pretty_mailbox. And these pretty * operations usually shrink the result. Still... */ url_ciss_tostring (&url, path, 1024, 0); } FREE (&target.mbox); }
int mutt_socket_write_d (CONNECTION *conn, const char *buf, int len, int dbg) { int rc; int sent = 0; dprint (dbg, (debugfile,"%d> %s", conn->fd, buf)); if (conn->fd < 0) { dprint (1, (debugfile, "mutt_socket_write: attempt to write to closed connection\n")); return -1; } if (len < 0) len = mutt_strlen (buf); while (sent < len) { if ((rc = conn->conn_write (conn, buf + sent, len - sent)) < 0) { dprint (1, (debugfile, "mutt_socket_write: error writing (%s), closing socket\n", strerror(errno))); mutt_socket_close (conn); return -1; } if (rc < len - sent) dprint (3, (debugfile, "mutt_socket_write: short write (%d of %d bytes)\n", rc, len - sent)); sent += rc; } return sent; }
void mutt_remove_trailing_ws (char *s) { char *p; for (p = s + mutt_strlen (s) - 1 ; p >= s && ISSPACE (*p) ; p--) *p = 0; }
int mutt_socket_write_d (CONNECTION *conn, const char *buf, int dbg) { int rc; int len; dprint (dbg, (debugfile,"> %s", buf)); if (conn->fd < 0) { dprint (1, (debugfile, "mutt_socket_write: attempt to write to closed connection\n")); return -1; } len = mutt_strlen (buf); if ((rc = conn->write (conn, buf, len)) < 0) { dprint (1, (debugfile, "mutt_socket_write: error writing, closing socket\n")); mutt_socket_close (conn); return -1; } if (rc < len) { dprint (1, (debugfile, "mutt_socket_write: ERROR: wrote %d of %d bytes!\n", rc, len)); } return rc; }
static int get_wrapped_width (const char *t, size_t wid) { wchar_t wc; size_t k; size_t m, n; size_t len = mutt_strlen (t); const char *s = t; mbstate_t mbstate; memset (&mbstate, 0, sizeof (mbstate)); for (m = wid, n = 0; len && (k = mbrtowc (&wc, s, len, &mbstate)) && (n <= wid); s += k, len -= k) { if (*s == ' ') m = n; if (k == (size_t)(-1) || k == (size_t)(-2)) { k = (k == (size_t)(-1)) ? 1 : len; wc = replacement_char (); } if (!IsWPrint (wc)) wc = '?'; n += wcwidth (wc); } if (n > wid) n = m; else n = wid; return n; }
/* Modified by blong to 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. * Renamed to mutt_adv_mktemp so I only have to change where it's * called, and not all possible cases. */ void mutt_adv_mktemp (char *s, size_t l) { char buf[_POSIX_PATH_MAX]; char tmp[_POSIX_PATH_MAX]; char *period; size_t sl; struct stat sb; strfcpy (buf, NONULL (Tempdir), sizeof (buf)); mutt_expand_path (buf, sizeof (buf)); if (s[0] == '\0') { snprintf (s, l, "%s/muttXXXXXX", buf); mktemp (s); } else { strfcpy (tmp, s, sizeof (tmp)); mutt_sanitize_filename (tmp, 1); snprintf (s, l, "%s/%s", buf, tmp); if (lstat (s, &sb) == -1 && errno == ENOENT) return; if ((period = strrchr (tmp, '.')) != NULL) *period = 0; snprintf (s, l, "%s/%s.XXXXXX", buf, tmp); mktemp (s); if (period != NULL) { *period = '.'; sl = mutt_strlen(s); strfcpy(s + sl, period, l - sl); } } }
void mutt_check_lookup_list (BODY *b, char *type, int len) { LIST *t = MimeLookupList; int i; for (; t; t = t->next) { i = mutt_strlen (t->data) - 1; if ((i > 0 && t->data[i-1] == '/' && t->data[i] == '*' && ascii_strncasecmp (type, t->data, i) == 0) || ascii_strcasecmp (type, t->data) == 0) { BODY tmp = {0}; int n; if ((n = mutt_lookup_mime_type (&tmp, b->filename)) != TYPEOTHER) { snprintf (type, len, "%s/%s", n == TYPEAUDIO ? "audio" : n == TYPEAPPLICATION ? "application" : n == TYPEIMAGE ? "image" : n == TYPEMESSAGE ? "message" : n == TYPEMODEL ? "model" : n == TYPEMULTIPART ? "multipart" : n == TYPETEXT ? "text" : n == TYPEVIDEO ? "video" : "other", tmp.subtype); dprint(1, (debugfile, "mutt_check_lookup_list: \"%s\" -> %s\n", b->filename, type)); } if (tmp.subtype) FREE (&tmp.subtype); if (tmp.xtype) FREE (&tmp.xtype); } } }
int mutt_is_autoview (BODY *b, const char *type) { LIST *t = AutoViewList; char _type[SHORT_STRING]; int i; if (!type) snprintf (_type, sizeof (_type), "%s/%s", TYPE (b), b->subtype); else strncpy (_type, type, sizeof(_type)); mutt_check_lookup_list (b, _type, sizeof(_type)); type = _type; if (mutt_needs_mailcap (b)) { if (option (OPTIMPLICITAUTOVIEW)) return 1; if (is_mmnoask (type)) return 1; } for (; t; t = t->next) { i = mutt_strlen (t->data) - 1; if ((i > 0 && t->data[i-1] == '/' && t->data[i] == '*' && ascii_strncasecmp (type, t->data, i) == 0) || ascii_strcasecmp (type, t->data) == 0) return 1; } return 0; }
static unsigned char * dump_char_size(char *c, unsigned char *d, int *off, ssize_t size, int convert) { char *p = c; if (c == NULL) { size = 0; d = dump_int(size, d, off); return d; } if (convert && !is_ascii (c, size)) { p = mutt_substrdup (c, c + size); if (mutt_convert_string (&p, Charset, "utf-8", 0) == 0) { c = p; size = mutt_strlen (c) + 1; } } d = dump_int(size, d, off); lazy_realloc(&d, *off + size); memcpy(d + *off, p, size); *off += size; if (p != c) FREE(&p); return d; }
int imap_mailbox_rename (const char* url, const char* parent, const char* subfolder, int subscribe) { IMAP_DATA* idata; IMAP_MBOX mx; char buf[LONG_STRING]; short n; BUFFER new_url; memset (&new_url, 0, sizeof (new_url)); if (imap_parse_path (url, &mx) < 0) { dprint (1, (debugfile, "imap_mailbox_rename: Bad path %s\n", url)); return -1; } if (!(idata = imap_conn_find (&mx.account, M_IMAP_CONN_NONEW))) { dprint (1, (debugfile, "imap_mailbox_rename: Couldn't find open connection to %s", mx.account.host)); goto fail; } strfcpy (buf, parent, sizeof (buf)); /* append a delimiter if necessary */ n = mutt_strlen (buf); if (n && (n < sizeof (buf) - 1) && (buf[n-1] != idata->delim)) { buf[n++] = idata->delim; buf[n] = '\0'; } strfcpy (buf + n, subfolder, sizeof (buf) - n); imap_subscribe(url, 0); if (imap_rename_mailbox (idata, mx.mbox, buf) < 0) goto fail; if (subscribe) { char* slash = strchr(url+8, '/'); if(slash) { mutt_buffer_add(&new_url, url, slash-url+1); mutt_buffer_addstr(&new_url, parent); mutt_buffer_addch (&new_url, idata->delim); mutt_buffer_addstr(&new_url, subfolder); if (imap_subscribe(new_url.data, 1) < 0) goto fail; } } FREE (&new_url.data); FREE (&mx.mbox); return 0; fail: FREE (&new_url.data); FREE (&mx.mbox); return -1; }
static int print_macro (FILE *f, int maxwidth, const char **macro) { int n = maxwidth; wchar_t wc; int w; size_t k; size_t len = mutt_strlen (*macro); mbstate_t mbstate1, mbstate2; memset (&mbstate1, 0, sizeof (mbstate1)); memset (&mbstate2, 0, sizeof (mbstate2)); for (; len && (k = mbrtowc (&wc, *macro, len, &mbstate1)); *macro += k, len -= k) { if (k == (size_t)(-1) || k == (size_t)(-2)) { k = (k == (size_t)(-1)) ? 1 : len; wc = replacement_char (); } /* glibc-2.1.3's wcwidth() returns 1 for unprintable chars! */ if (IsWPrint (wc) && (w = wcwidth (wc)) >= 0) { if (w > n) break; n -= w; { char buf[MB_LEN_MAX*2]; size_t n1, n2; if ((n1 = wcrtomb (buf, wc, &mbstate2)) != (size_t)(-1) && (n2 = wcrtomb (buf + n1, 0, &mbstate2)) != (size_t)(-1)) fputs (buf, f); } } else if (wc < 0x20 || wc == 0x7f) { if (2 > n) break; n -= 2; if (wc == '\033') fprintf (f, "\\e"); else if (wc == '\n') fprintf (f, "\\n"); else if (wc == '\r') fprintf (f, "\\r"); else if (wc == '\t') fprintf (f, "\\t"); else fprintf (f, "^%c", (char)((wc + '@') & 0x7f)); } else { if (1 > n) break; n -= 1; fprintf (f, "?"); } } return (maxwidth - n); }
void mutt_expand_fmt (char *dest, size_t destlen, const char *fmt, const char *src) { const char *p = fmt; const char *last = p; size_t len; size_t slen; int found = 0; slen = mutt_strlen (src); while ((p = strchr (p, '%')) != NULL) { if (p[1] == 's') { found++; len = (size_t) (p - last); if (len) { if (len > destlen - 1) len = destlen - 1; memcpy (dest, last, len); dest += len; destlen -= len; if (destlen <= 0) { *dest = 0; break; /* no more space */ } } strfcpy (dest, src, destlen); if (slen > destlen) { /* no more room */ break; } dest += slen; destlen -= slen; p += 2; last = p; } else if (p[1] == '%') p++; p++; } if (found) strfcpy (dest, last, destlen); else snprintf (dest, destlen, "%s %s", fmt, src); }
/* returns true if the header contained in "s" is in list "t" */ int mutt_matches_ignore (const char *s, LIST *t) { for (; t; t = t->next) { if (!mutt_strncasecmp (s, t->data, mutt_strlen (t->data)) || *t->data == '*') return 1; } return 0; }
int mutt_get_password (char *msg, char *buf, size_t buflen) { int rc; CLEARLINE (LINES-1); addstr (msg); rc = mutt_enter_string ((unsigned char *) buf, buflen, LINES - 1, mutt_strlen (msg), M_PASS); CLEARLINE (LINES-1); return (rc); }
/* * This routine does RfC3676 space stuffing since it's a MUST. * Space stuffing means that we have to add leading spaces to * certain lines: * - lines starting with a space * - lines starting with 'From ' * This routine is only called once right after editing the * initial message so it's up to the user to take care of stuffing * when editing the message several times before actually sending it * * This is more or less a hack as it replaces the message's content with * a freshly created copy in a tempfile and modifies the file's mtime * so we don't trigger code paths watching for mtime changes */ void rfc3676_space_stuff (HEADER* hdr) { #if DEBUG int lc = 0; size_t len = 0; unsigned char c = '\0'; #endif FILE *in = NULL, *out = NULL; char buf[LONG_STRING]; char tmpfile[_POSIX_PATH_MAX]; if (!hdr || !hdr->content || !hdr->content->filename) return; dprint (2, (debugfile, "f=f: postprocess %s\n", hdr->content->filename)); if ((in = safe_fopen (hdr->content->filename, "r")) == NULL) return; mutt_mktemp (tmpfile, sizeof (tmpfile)); if ((out = safe_fopen (tmpfile, "w+")) == NULL) { safe_fclose (&in); return; } while (fgets (buf, sizeof (buf), in)) { if (ascii_strncmp ("From ", buf, 5) == 0 || buf[0] == ' ') { fputc (' ', out); #if DEBUG lc++; len = mutt_strlen (buf); if (len > 0) { c = buf[len-1]; buf[len-1] = '\0'; } dprint (4, (debugfile, "f=f: line %d needs space-stuffing: '%s'\n", lc, buf)); if (len > 0) buf[len-1] = c; #endif } fputs (buf, out); } safe_fclose (&in); safe_fclose (&out); mutt_set_mtime (hdr->content->filename, tmpfile); unlink (hdr->content->filename); mutt_str_replace (&hdr->content->filename, tmpfile); }
int mutt_addrlist_to_idna (ADDRESS *a, char **err) { char *user = NULL, *domain = NULL; char *tmp = NULL; int e = 0; if (err) *err = NULL; for (; a; a = a->next) { if (!a->mailbox) continue; if (mbox_to_udomain (a->mailbox, &user, &domain) == -1) continue; if (mutt_local_to_idna (domain, &tmp) < 0) { e = 1; if (err) *err = safe_strdup (domain); } else { safe_realloc (&a->mailbox, mutt_strlen (user) + mutt_strlen (tmp) + 2); sprintf (a->mailbox, "%s@%s", NONULL(user), NONULL(tmp)); /* __SPRINTF_CHECKED__ */ a->idn_checked = 0; } FREE (&tmp); if (e) return -1; } return 0; }
void mutt_make_misc_reply_headers (ENVELOPE *env, CONTEXT *ctx, HEADER *cur, ENVELOPE *curenv) { /* This takes precedence over a subject that might have * been taken from a List-Post header. Is that correct? */ if (curenv->real_subj) { FREE (&env->subject); env->subject = safe_malloc (mutt_strlen (curenv->real_subj) + 5); sprintf (env->subject, "Re: %s", curenv->real_subj); /* __SPRINTF_CHECKED__ */ } else if (!env->subject) env->subject = safe_strdup ("Re: your mail"); }
int mutt_bcache_del(body_cache_t *bcache, const char *id) { char path[_POSIX_PATH_MAX]; if (!id || !*id || !bcache) return -1; path[0] = '\0'; safe_strncat (path, sizeof (path), bcache->path, bcache->pathlen); safe_strncat (path, sizeof (path), id, mutt_strlen (id)); dprint (3, (debugfile, "bcache: del: '%s'\n", path)); return unlink (path); }
int _mutt_get_field (/* const */ char *field, char *buf, size_t buflen, int complete, int multiple, char ***files, int *numfiles) { int ret; int len = mutt_strlen (field); /* in case field==buffer */ do { CLEARLINE (LINES-1); addstr (field); mutt_refresh (); ret = _mutt_enter_string ((unsigned char *) buf, buflen, LINES-1, len, complete, multiple, files, numfiles); } while (ret == 1); CLEARLINE (LINES-1); return (ret); }
FILE* mutt_bcache_get(body_cache_t *bcache, const char *id) { char path[_POSIX_PATH_MAX]; FILE* fp = NULL; if (!id || !*id || !bcache) return NULL; path[0] = '\0'; safe_strncat (path, sizeof (path), bcache->path, bcache->pathlen); safe_strncat (path, sizeof (path), id, mutt_strlen (id)); fp = safe_fopen (path, "r"); dprint (3, (debugfile, "bcache: get: '%s': %s\n", path, fp == NULL ? "no" : "yes")); return fp; }
/* incomplete. Only used to thwart the APOP MD5 attack (#2846). */ int rfc822_valid_msgid (const char *msgid) { /* msg-id = "<" addr-spec ">" * addr-spec = local-part "@" domain * local-part = word *("." word) * word = atom / quoted-string * atom = 1*<any CHAR except specials, SPACE and CTLs> * CHAR = ( 0.-127. ) * specials = "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / <"> / "." / "[" / "]" * SPACE = ( 32. ) * CTLS = ( 0.-31., 127.) * quoted-string = <"> *(qtext/quoted-pair) <"> * qtext = <any CHAR except <">, "\" and CR> * CR = ( 13. ) * quoted-pair = "\" CHAR * domain = sub-domain *("." sub-domain) * sub-domain = domain-ref / domain-literal * domain-ref = atom * domain-literal = "[" *(dtext / quoted-pair) "]" */ unsigned int l, i; if (!msgid || !*msgid) return -1; l = mutt_strlen (msgid); if (l < 5) /* <atom@atom> */ return -1; if (msgid[0] != '<' || msgid[l-1] != '>') return -1; if (!(strrchr (msgid, '@'))) return -1; /* TODO: complete parser */ for (i = 0; i < l; i++) if ((unsigned char)msgid[i] > 127) return -1; return 0; }
body_cache_t *mutt_bcache_open (ACCOUNT *account, const char *mailbox) { struct body_cache *bcache = NULL; if (!account) goto bail; bcache = safe_calloc (1, sizeof (struct body_cache)); if (bcache_path (account, mailbox, bcache->path, sizeof (bcache->path)) < 0) goto bail; bcache->pathlen = mutt_strlen (bcache->path); return bcache; bail: if (bcache) FREE(&bcache); return NULL; }