#include <lib-lib/mem.h>
#include <lib-lib/ascii.h>
#include <lib-lib/str.h>
+#include <lib-lib/file.h>
#include <lib-lib/macros.h>
#include "lib/rx.h"
#include <lib-lib/mem.h>
#include <lib-lib/ascii.h>
#include <lib-lib/str.h>
+#include <lib-lib/file.h>
#include <lib-lib/macros.h>
#include "mutt.h"
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
struct stat st;
char fullpath[_POSIX_PATH_MAX];
- mutt_concat_path (fullpath, folder, path, sizeof (fullpath));
+ mutt_concat_path(fullpath, sizeof(fullpath), folder, path);
if (stat (fullpath, &st) == 0)
return (S_ISDIR (st.st_mode));
if (!((regexec (Mask.rx, de->d_name, 0, NULL, 0) == 0) ^ Mask.not))
continue;
- mutt_concat_path (buffer, d, de->d_name, sizeof (buffer));
+ mutt_concat_path(buffer, sizeof(buffer), d, de->d_name);
if (lstat (buffer, &s) == -1)
continue;
}
#endif
else
- mutt_concat_path (buf, LastDir, state.entry[menu->current].name,
- sizeof (buf));
+ mutt_concat_path(buf, sizeof(buf), LastDir,
+ state.entry[menu->current].name);
if ((mx_get_magic (buf) <= 0)
#ifdef USE_IMAP
else {
char tmp[_POSIX_PATH_MAX];
- mutt_concat_path (tmp, LastDir, state.entry[menu->current].name,
- sizeof (tmp));
+ mutt_concat_path(tmp, sizeof(tmp), LastDir,
+ state.entry[menu->current].name);
strfcpy (LastDir, tmp, sizeof (LastDir));
}
strfcpy (f, state.entry[menu->current].name, flen);
#endif
else
- mutt_concat_path (f, LastDir, state.entry[menu->current].name, flen);
+ mutt_concat_path(f, flen, LastDir, state.entry[menu->current].name);
/* Fall through to OP_EXIT */
char full[_POSIX_PATH_MAX];
if (ff.tagged) {
- mutt_concat_path (full, LastDir, ff.name, sizeof (full));
+ mutt_concat_path(full, sizeof(full), LastDir, ff.name);
mutt_expand_path (full, sizeof (full));
tfiles[j++] = m_strdup(full);
}
BODY *b;
char buf[_POSIX_PATH_MAX];
- mutt_concat_path (buf, LastDir, state.entry[menu->current].name,
- sizeof (buf));
+ mutt_concat_path(buf, sizeof(buf), LastDir,
+ state.entry[menu->current].name);
b = mutt_make_file_attach (buf);
if (b != NULL) {
mutt_view_attachment (NULL, b, M_REGULAR, NULL, NULL, 0);
#endif
#include <lib-lib/mem.h>
-
+#include <lib-lib/file.h>
#include <lib-lib/macros.h>
#include <lib-lib/ascii.h>
#endif
#include <lib-lib/str.h>
+#include <lib-lib/file.h>
#include "lib/debug.h"
#include <dirent.h>
/* we can use '/' as a delimiter, imap_complete rewrites it */
if (*s == '=' || *s == '+' || *s == '!') {
const char *q = NONULL(*s == '!' ? Spoolfile : Maildir);
- mutt_concat_path (imap_path, q, s + 1, sizeof (imap_path));
+ mutt_concat_path(imap_path, sizeof(imap_path), q, s + 1);
}
else
strfcpy (imap_path, s, sizeof (imap_path));
char buf[_POSIX_PATH_MAX];
*p++ = 0;
- mutt_concat_path (buf, exp_dirpart, s + 1, sizeof (buf));
+ mutt_concat_path(buf, sizeof(buf), exp_dirpart, s + 1);
strfcpy (exp_dirpart, buf, sizeof (exp_dirpart));
snprintf (buf, sizeof (buf), "%s%s/", dirpart, s + 1);
strfcpy (dirpart, buf, sizeof (dirpart));
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
if (m_strcmp("builtin", Editor) != 0 &&
(op == OP_COMPOSE_EDIT_HEADERS ||
(op == OP_COMPOSE_EDIT_MESSAGE && option (OPTEDITHDRS)))) {
- const char *tag = NULL, *err = NULL;
+ const char *tag = NULL;
+ char *err = NULL;
mutt_env_to_local (msg->env);
mutt_edit_headers (NONULL (Editor), msg->content->filename, msg,
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
# include "config.h"
#endif
+#include <lib-lib/macros.h>
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
+#include <lib-lib/file.h>
#include <lib-lib/ascii.h>
#include "mutt.h"
#include <lib-lib/str.h>
#include <lib-lib/ascii.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "mutt_crypt.h"
#endif
#include <lib-lib/str.h>
+#include <lib-lib/file.h>
#include <lib-lib/ascii.h>
#include <lib-lib/mem.h>
#include <lib-lib/macros.h>
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
#include <lib-lib/ascii.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
#endif
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include <lib-lib/str.h>
#include "mutt.h"
}
}
-size_t my_mbstowcs (wchar_t ** pwbuf, size_t * pwbuflen, size_t i, char *buf)
+size_t my_mbstowcs (wchar_t ** pwbuf, size_t * pwbuflen, size_t i, const char *buf)
{
wchar_t wc;
mbstate_t st;
memcpy (savebuf, state->wbuf + state->curpos, savelen * sizeof (wchar_t));
/* Convert to wide characters */
- state->curpos = my_mbstowcs (&state->wbuf, &state->wbuflen, from, buf);
+ state->curpos = my_mbstowcs(&state->wbuf, &state->wbuflen, from, buf);
/* Make space for suffix */
if (state->curpos + savelen > state->wbuflen) {
#include <ctype.h>
#include <string.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#ifndef STDC_HEADERS
#include <lib-lib/ascii.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "recvattach.h"
#include <lib-lib/macros.h>
#include <lib-lib/ascii.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "mutt_crypt.h"
#endif
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include <lib-lib/str.h>
#include "mutt.h"
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
#include <lib-lib/buffer.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "mx.h"
(env->to || env->cc || env->bcc)) {
adr = env->to ? env->to : (env->cc ? env->cc : env->bcc);
mutt_safe_path (buf, sizeof (buf), adr);
- mutt_concat_path (path, NONULL (Maildir), buf, pathlen);
+ mutt_concat_path(path, pathlen, NONULL(Maildir), buf);
if (!option (OPTFORCENAME) && mx_access (path, W_OK) != 0)
strfcpy (path, NONULL (Outbox), pathlen);
}
#endif
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "lib/debug.h"
#if HAVE_STDINT_H
#include <sys/stat.h>
#include <lib-lib/mem.h>
+#include <lib-lib/file.h>
#include <lib-lib/str.h>
#include "mutt.h"
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
+#include <lib-lib/file.h>
#include <lib-lib/ascii.h>
#include <lib-lib/macros.h>
#include <lib-lib/buffer.h>
/* free()'s option_t* */
static void del_option (void* p) {
- struct option_t* ptr = (struct option_t*) p;
+ struct option_t *ptr = (struct option_t*) p;
char* s = (char*) ptr->data;
debug_print (1, ("removing option '%s' from table\n", NONULL (ptr->option)));
p_delete(&ptr->option);
Spoolfile = m_strdup(p);
else {
#ifdef HOMESPOOL
- mutt_concat_path (buffer, NONULL (Homedir), MAILPATH, sizeof(buffer));
+ mutt_concat_path(buffer, sizeof(buffer), NONULL(Homedir), MAILPATH);
#else
- mutt_concat_path (buffer, MAILPATH, NONULL (Username), sizeof(buffer));
+ mutt_concat_path(buffer, sizeof(buffer), MAILPATH, NONULL(Username));
#endif
Spoolfile = m_strdup(buffer);
}
return NULL;
}
-static void push_string (char *s)
+static void push_string(const char *s)
{
- char *pp, *p = s + m_strlen(s) - 1;
+ const char *pp, *p = s + m_strlen(s) - 1;
size_t l;
int i, op = OP_NULL;
/* careful not to feed the <..> as one token. otherwise
* push_string() will push the bogus op right back! */
mutt_ungetch ('>', 0);
- push_string (func);
+ push_string(func);
mutt_ungetch ('<', 0);
break;
}
noinst_LIBRARIES = liblib.a
-liblib_a_SOURCES = mem.h str.h ascii.h buffer.h hash.h list.h \
- str.c ascii.c buffer.c hash.c list.c
+liblib_a_SOURCES = mem.h str.h ascii.h buffer.h hash.h list.h file.h \
+ str.c ascii.c buffer.c hash.c list.c file.c
-noinst_HEADERS = mem.h str.h ascii.h buffer.h hash.h list.h
+noinst_HEADERS = mem.h str.h ascii.h buffer.h hash.h list.h file.h
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Copyright © 2006 Pierre Habouzit
+ */
+/*
+ * Copyright notice from original mutt:
+ * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
+ * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
+ *
+ * This file is part of mutt-ng, see http://www.muttng.org/.
+ * It's licensed under the GNU General Public License,
+ * please see the file GPL in the top level source directory.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "macros.h"
+#include "mem.h"
+#include "str.h"
+#include "file.h"
+
+#include "../lib/debug.h"
+#include "../lib/str.h"
+
+#ifndef O_NOFOLLOW
+# define O_NOFOLLOW 0
+#endif
+
+/* FIXME: ugly to the max */
+extern short Umask;
+
+static int compare_stat(struct stat *osb, struct stat *nsb)
+{
+ if (osb->st_dev != nsb->st_dev || osb->st_ino != nsb->st_ino
+ || osb->st_rdev != nsb->st_rdev)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+/* fd ops */
+/****************************************************************************/
+
+int safe_open(const char *path, int flags)
+{
+ struct stat osb, nsb;
+ int fd;
+
+ umask(Umask);
+
+ if ((fd = open(path, flags, 0666)) < 0)
+ return fd;
+
+ /* make sure the file is not symlink */
+ if (lstat (path, &osb) < 0 || fstat(fd, &nsb) < 0
+ || compare_stat(&osb, &nsb) == -1)
+ {
+ debug_print(1, ("%s is a symlink!\n", path));
+ close(fd);
+ return -1;
+ }
+
+ return (fd);
+}
+
+
+int safe_symlink(const char *oldpath, const char *newpath)
+{
+ struct stat osb, nsb;
+
+ if (!oldpath || !newpath)
+ return -1;
+
+ if (unlink(newpath) < 0 && errno != ENOENT)
+ return -1;
+
+ if (oldpath[0] == '/') {
+ if (symlink(oldpath, newpath) < 0)
+ return -1;
+ } else {
+ char abs_oldpath[_POSIX_PATH_MAX];
+ ssize_t len;
+
+ if (!getcwd(abs_oldpath, sizeof(abs_oldpath)))
+ return -1;
+
+ len = m_strcat(abs_oldpath, sizeof(abs_oldpath), "/");
+ if (len >= sizeof(abs_oldpath))
+ return -1;
+
+ len += m_strcpy(abs_oldpath + len, sizeof(abs_oldpath) - len, oldpath);
+ if (len >= sizeof(abs_oldpath))
+ return -1;
+
+ if (symlink (abs_oldpath, newpath) < 0)
+ return -1;
+ }
+
+ if (stat(oldpath, &osb) < 0
+ || stat(newpath, &nsb) < 0
+ || compare_stat(&osb, &nsb) < 0)
+ {
+ unlink (newpath);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function is supposed to do nfs-safe renaming of files.
+ *
+ * Warning: We don't check whether src and target are equal.
+ */
+int safe_rename(const char *src, const char *target)
+{
+ struct stat ssb, tsb;
+
+ if (!src || !target)
+ return -1;
+
+ if (link(src, target) != 0) {
+ /*
+ * Coda does not allow cross-directory links, but tells
+ * us it's a cross-filesystem linking attempt.
+ *
+ * However, the Coda rename call is allegedly safe to use.
+ *
+ * With other file systems, rename should just fail when
+ * the files reside on different file systems, so it's safe
+ * to try it here.
+ *
+ */
+
+ if (errno == EXDEV)
+ return rename(src, target);
+
+ return -1;
+ }
+
+ /* Stat both links and check if they are equal. */
+
+ if (stat(src, &ssb) < 0 || stat(target, &tsb) < 0) {
+ return -1;
+ }
+
+ /*
+ * pretend that the link failed because the target file
+ * did already exist.
+ */
+
+ if (compare_stat(&ssb, &tsb) == -1) {
+ errno = EEXIST;
+ return -1;
+ }
+
+ /*
+ * Unlink the original link. Should we really ignore the return
+ * value here? XXX
+ */
+
+ unlink(src);
+ return 0;
+}
+
+void mutt_unlink(const char *s)
+{
+ struct stat sb, sb2;
+
+ if (lstat(s, &sb) == 0 && S_ISREG(sb.st_mode)) {
+ int fd;
+ FILE *f;
+
+ /* Defend against symlink attacks */
+
+ if ((fd = open(s, O_RDWR | O_NOFOLLOW)) < 0)
+ return;
+
+ if ((fstat(fd, &sb2) != 0) || !S_ISREG(sb2.st_mode)
+ || (sb.st_dev != sb2.st_dev) || (sb.st_ino != sb2.st_ino))
+ {
+ close (fd);
+ return;
+ }
+
+ if ((f = fdopen(fd, "r+"))) {
+ char buf[BUFSIZ];
+ unlink(s);
+
+ p_clear(buf, sizeof(buf));
+ while (sb.st_size > 0) {
+ fwrite(buf, 1, MIN(sizeof(buf), sb.st_size), f);
+ sb.st_size -= MIN(sizeof(buf), sb.st_size);
+ }
+ fclose (f);
+ }
+ }
+}
+
+
+/****************************************************************************/
+/* FILE* ops */
+/****************************************************************************/
+
+/* when opening files for writing, make sure the file doesn't already exist
+ to avoid race conditions. */
+FILE *safe_fopen(const char *path, const char *mode)
+{
+ /* first set the current umask */
+ umask(Umask);
+
+ if (mode[0] == 'w') {
+ int fd;
+ int flags = O_CREAT | O_EXCL | O_NOFOLLOW;
+
+ flags |= (mode[1] == '+' ? O_RDWR : O_WRONLY);
+
+ if ((fd = safe_open(path, flags)) < 0)
+ return (NULL);
+
+ return fdopen (fd, mode);
+ }
+
+ return fopen(path, mode);
+}
+
+int safe_fclose(FILE **f)
+{
+ int r = 0;
+
+ if (*f)
+ r = fclose (*f);
+ *f = NULL;
+ return r;
+}
+
+/* Read a line from ``fp'' into the dynamically allocated ``s'',
+ * increasing ``s'' if necessary. The ending "\n" or "\r\n" is removed.
+ * If a line ends with "\", this char and the linefeed is removed,
+ * and the next line is read too.
+ */
+char *mutt_read_line(char *s, size_t *size, FILE * fp, int *line)
+{
+ size_t offset = 0;
+ char *ch;
+
+ if (!s) {
+ s = p_new(char, STRING);
+ *size = STRING;
+ }
+
+ for (;;) {
+ if (fgets(s + offset, *size - offset, fp) == NULL) {
+ p_delete(&s);
+ return NULL;
+ }
+ if ((ch = strchr(s + offset, '\n')) != NULL) {
+ (*line)++;
+ *ch = 0;
+ if (ch > s && *(ch - 1) == '\r')
+ *--ch = 0;
+ if (ch == s || *(ch - 1) != '\\')
+ return s;
+ offset = ch - s - 1;
+ } else {
+ int c;
+
+ c = getc (fp); /* This is kind of a hack. We want to know if the
+ char at the current point in the input stream is EOF.
+ feof() will only tell us if we've already hit EOF, not
+ if the next character is EOF. So, we need to read in
+ the next character and manually check if it is EOF. */
+ if (c == EOF) {
+ /* The last line of fp isn't \n terminated */
+ (*line)++;
+ return s;
+ } else {
+ ungetc (c, fp); /* undo our dammage */
+ /* There wasn't room for the line -- increase ``s'' */
+ offset = *size - 1; /* overwrite the terminating 0 */
+ *size += STRING;
+ p_realloc(&s, *size);
+ }
+ }
+ }
+}
+
+int mutt_copy_stream(FILE *fin, FILE *fout)
+{
+ char buf[BUFSIZ];
+ ssize_t l;
+
+ while ((l = fread(buf, 1, sizeof (buf), fin)) > 0) {
+ if (fwrite(buf, 1, l, fout) != l)
+ return -1;
+ }
+
+ return 0;
+}
+
+int mutt_copy_bytes(FILE *in, FILE *out, size_t size)
+{
+ char buf[BUFSIZ];
+
+ while (size > 0) {
+ ssize_t chunk = MIN(size, sizeof(buf));
+
+ if ((chunk = fread(buf, 1, chunk, in)) < 1)
+ break;
+ if (fwrite(buf, 1, chunk, out) != chunk) {
+ debug_print(1, ("fwrite() returned short byte count\n"));
+ return -1;
+ }
+ size -= chunk;
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************/
+/* ligben-like funcs */
+/****************************************************************************/
+
+const char *mutt_basename(const char *f)
+{
+ const char *p = strrchr(f, '/');
+ return p ? p + 1 : f;
+}
+
+
+char *
+mutt_concat_path(char *d, ssize_t n, const char *dir, const char *fname)
+{
+ const char *fmt = "%s/%s";
+
+ if (!*fname || (*dir && dir[m_strlen(dir) - 1] == '/'))
+ fmt = "%s%s";
+
+ snprintf(d, n, fmt, dir, fname);
+ return d;
+}
+
+
+void mutt_sanitize_filename(char *s, short slash)
+{
+ static char safe_chars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/";
+
+ if (!s)
+ return;
+
+ for (; *s; s++) {
+ if ((slash && *s == '/') || !strchr (safe_chars, *s))
+ *s = '_';
+ }
+}
+
+/* prepare a file name to survive the shell's quoting rules.
+ * From the Unix programming FAQ by way of Liviu.
+ */
+
+/* FIXME: API is very wrong */
+ssize_t mutt_quote_filename(char *d, ssize_t l, const char *s)
+{
+ size_t i, j = 0;
+
+ if (!s) {
+ *d = '\0';
+ return 0;
+ }
+
+ /* leave some space for the trailing characters. */
+ l -= 6;
+
+ d[j++] = '\'';
+
+ for (i = 0; j < l && s[i]; i++) {
+ if (s[i] == '\'' || s[i] == '`') {
+ d[j++] = '\'';
+ d[j++] = '\\';
+ d[j++] = s[i];
+ d[j++] = '\'';
+ } else {
+ d[j++] = s[i];
+ }
+ }
+
+ d[j++] = '\'';
+ d[j] = '\0';
+
+ return j;
+}
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Copyright © 2006 Pierre Habouzit
+ */
+/*
+ * Copyright notice from original mutt:
+ * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
+ * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
+ *
+ * This file is part of mutt-ng, see http://www.muttng.org/.
+ * It's licensed under the GNU General Public License,
+ * please see the file GPL in the top level source directory.
+ */
+
+/*
+ * File manipulations + saner libgen functions
+ */
+
+#ifndef MUTT_LIB_LIB_FILE_H
+#define MUTT_LIB_LIB_FILE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/****************************************************************************/
+/* fd ops */
+/****************************************************************************/
+
+int safe_open(const char *, int);
+int safe_symlink(const char *, const char *);
+int safe_rename(const char *, const char *);
+void mutt_unlink(const char *);
+
+/****************************************************************************/
+/* FILE* ops */
+/****************************************************************************/
+
+FILE *safe_fopen(const char *, const char *);
+int safe_fclose(FILE **);
+
+char *mutt_read_line(char *, size_t *, FILE *, int *);
+
+int mutt_copy_stream(FILE *, FILE *);
+int mutt_copy_bytes(FILE *, FILE *, size_t);
+
+/****************************************************************************/
+/* ligben-like funcs */
+/****************************************************************************/
+
+const char *mutt_basename(const char *);
+char *mutt_concat_path(char *, ssize_t, const char *, const char *);
+
+void mutt_sanitize_filename(char *, short);
+ssize_t mutt_quote_filename(char *, ssize_t, const char *);
+
+#endif /* MUTT_LIB_LIB_FILE_H */
# define N_(a) (a)
#endif
+
+#define TRUE 1
+#define FALSE 0
+
+#undef MAX
+#undef MIN
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
#endif /* MUTT_LIB_LIB_MACROS_H */
* Copyright © 2006 Pierre Habouzit
*/
+#include "macros.h"
#include "str.h"
+
+ssize_t m_strcpy(char *dst, ssize_t n, const char *src)
+{
+ ssize_t len = m_strlen(src);
+
+ if (dst && n > 0) {
+ ssize_t dlen = MIN(n - 1, len);
+ memcpy(dst, src, dlen);
+ dst[dlen] = '\0';
+ }
+
+ return len;
+}
+
return s ? strlen(s) : 0;
}
+static inline ssize_t m_strnlen(const char *s, ssize_t n) {
+ const char *p = memchr(s, '\0', n);
+ return p ? p - s : n;
+}
+
static inline char *m_strdup(const char *s) {
return p_dupstr(s, m_strlen(s));
}
return strcmp(NONULL(a), NONULL(b));
}
+
+ssize_t m_strcpy(char *dst, ssize_t n, const char *src);
+
+static inline ssize_t m_strcat(char *dst, ssize_t n, const char *src) {
+ ssize_t dlen = m_strnlen(dst, n);
+ return dlen + m_strcpy(dst + dlen, n - dlen, src);
+}
+
#endif /* MUTT_LIB_LIB_STR_H */
#define EX_OK 0
#endif
+#include <lib-lib/macros.h>
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include "lib/debug.h"
-extern short Umask;
-
static struct sysexits
{
int v;
fputc ('\n', stderr);
}
-int safe_fclose (FILE ** f)
-{
- int r = 0;
-
- if (*f)
- r = fclose (*f);
-
- *f = NULL;
- return r;
-}
-
-void mutt_unlink (const char *s)
-{
- int fd;
- int flags;
- FILE *f;
- struct stat sb, sb2;
- char buf[2048];
-
- /* Defend against symlink attacks */
-
-#ifdef O_NOFOLLOW
- flags = O_RDWR | O_NOFOLLOW;
-#else
- flags = O_RDWR;
-#endif
-
- if (lstat (s, &sb) == 0 && S_ISREG (sb.st_mode)) {
- if ((fd = open (s, flags)) < 0)
- return;
-
- if ((fstat (fd, &sb2) != 0) || !S_ISREG (sb2.st_mode)
- || (sb.st_dev != sb2.st_dev) || (sb.st_ino != sb2.st_ino)) {
- close (fd);
- return;
- }
-
- if ((f = fdopen (fd, "r+"))) {
- unlink (s);
- p_clear(buf, sizeof(buf));
- while (sb.st_size > 0) {
- fwrite (buf, 1, MIN (sizeof (buf), sb.st_size), f);
- sb.st_size -= MIN (sizeof (buf), sb.st_size);
- }
- fclose (f);
- }
- }
-}
-
-int mutt_copy_bytes (FILE * in, FILE * out, size_t size)
-{
- char buf[2048];
- size_t chunk;
-
- while (size > 0) {
- chunk = (size > sizeof (buf)) ? sizeof (buf) : size;
- if ((chunk = fread (buf, 1, chunk, in)) < 1)
- break;
- if (fwrite (buf, 1, chunk, out) != chunk) {
- debug_print (1, ("fwrite() returned short byte count\n"));
- return (-1);
- }
- size -= chunk;
- }
-
- return 0;
-}
-
-int mutt_copy_stream (FILE * fin, FILE * fout)
-{
- size_t l;
- char buf[LONG_STRING];
-
- while ((l = fread (buf, 1, sizeof (buf), fin)) > 0) {
- if (fwrite (buf, 1, l, fout) != l)
- return (-1);
- }
-
- return 0;
-}
-
-static int compare_stat (struct stat *osb, struct stat *nsb)
-{
- if (osb->st_dev != nsb->st_dev || osb->st_ino != nsb->st_ino ||
- osb->st_rdev != nsb->st_rdev) {
- return -1;
- }
-
- return 0;
-}
-
-int safe_symlink (const char *oldpath, const char *newpath)
-{
- struct stat osb, nsb;
-
- if (!oldpath || !newpath)
- return -1;
-
- if (unlink (newpath) == -1 && errno != ENOENT)
- return -1;
-
- if (oldpath[0] == '/') {
- if (symlink (oldpath, newpath) == -1)
- return -1;
- }
- else {
- char abs_oldpath[_POSIX_PATH_MAX];
-
- if ((getcwd (abs_oldpath, sizeof abs_oldpath) == NULL) ||
- (m_strlen(abs_oldpath) + 1 + m_strlen(oldpath) + 1 >
- sizeof abs_oldpath))
- return -1;
-
- strcat (abs_oldpath, "/"); /* __STRCAT_CHECKED__ */
- strcat (abs_oldpath, oldpath); /* __STRCAT_CHECKED__ */
- if (symlink (abs_oldpath, newpath) == -1)
- return -1;
- }
-
- if (stat (oldpath, &osb) == -1 || stat (newpath, &nsb) == -1
- || compare_stat (&osb, &nsb) == -1) {
- unlink (newpath);
- return -1;
- }
-
- return 0;
-}
-
-/*
- * This function is supposed to do nfs-safe renaming of files.
- *
- * Warning: We don't check whether src and target are equal.
- */
-
-int safe_rename (const char *src, const char *target)
-{
- struct stat ssb, tsb;
-
- if (!src || !target)
- return -1;
-
- if (link (src, target) != 0) {
-
- /*
- * Coda does not allow cross-directory links, but tells
- * us it's a cross-filesystem linking attempt.
- *
- * However, the Coda rename call is allegedly safe to use.
- *
- * With other file systems, rename should just fail when
- * the files reside on different file systems, so it's safe
- * to try it here.
- *
- */
-
- if (errno == EXDEV)
- return rename (src, target);
-
- return -1;
- }
-
- /*
- * Stat both links and check if they are equal.
- */
-
- if (stat (src, &ssb) == -1) {
- return -1;
- }
-
- if (stat (target, &tsb) == -1) {
- return -1;
- }
-
- /*
- * pretend that the link failed because the target file
- * did already exist.
- */
-
- if (compare_stat (&ssb, &tsb) == -1) {
- errno = EEXIST;
- return -1;
- }
-
- /*
- * Unlink the original link. Should we really ignore the return
- * value here? XXX
- */
-
- unlink (src);
-
- return 0;
-}
-
-int safe_open (const char *path, int flags)
-{
- struct stat osb, nsb;
- int fd;
-
- umask (Umask);
- if ((fd = open (path, flags, 0666)) < 0)
- return fd;
-
- /* make sure the file is not symlink */
- if (lstat (path, &osb) < 0 || fstat (fd, &nsb) < 0 ||
- compare_stat (&osb, &nsb) == -1) {
- debug_print (1, ("%s is a symlink!\n", path));
- close (fd);
- return (-1);
- }
-
- return (fd);
-}
-
-/* when opening files for writing, make sure the file doesn't already exist
- * to avoid race conditions.
- */
-FILE *safe_fopen (const char *path, const char *mode)
-{
- /* first set the current umask */
- umask (Umask);
- if (mode[0] == 'w') {
- int fd;
- int flags = O_CREAT | O_EXCL;
-
-#ifdef O_NOFOLLOW
- flags |= O_NOFOLLOW;
-#endif
-
- if (mode[1] == '+')
- flags |= O_RDWR;
- else
- flags |= O_WRONLY;
-
- if ((fd = safe_open (path, flags)) < 0)
- return (NULL);
-
- return (fdopen (fd, mode));
- }
- else
- return (fopen (path, mode));
-}
-
-static char safe_chars[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/";
-
-void mutt_sanitize_filename (char *f, short slash)
-{
- if (!f)
- return;
-
- for (; *f; f++) {
- if ((slash && *f == '/') || !strchr (safe_chars, *f))
- *f = '_';
- }
-}
/* these characters must be escaped in regular expressions */
return 0;
}
-/* Read a line from ``fp'' into the dynamically allocated ``s'',
- * increasing ``s'' if necessary. The ending "\n" or "\r\n" is removed.
- * If a line ends with "\", this char and the linefeed is removed,
- * and the next line is read too.
- */
-char *mutt_read_line(char *s, size_t * size, FILE * fp, int *line)
-{
- size_t offset = 0;
- char *ch;
-
- if (!s) {
- s = p_new(char, STRING);
- *size = STRING;
- }
-
- for (;;) {
- if (fgets (s + offset, *size - offset, fp) == NULL) {
- p_delete(&s);
- return NULL;
- }
- if ((ch = strchr (s + offset, '\n')) != NULL) {
- (*line)++;
- *ch = 0;
- if (ch > s && *(ch - 1) == '\r')
- *--ch = 0;
- if (ch == s || *(ch - 1) != '\\')
- return s;
- offset = ch - s - 1;
- }
- else {
- int c;
-
- c = getc (fp); /* This is kind of a hack. We want to know if the
- char at the current point in the input stream is EOF.
- feof() will only tell us if we've already hit EOF, not
- if the next character is EOF. So, we need to read in
- the next character and manually check if it is EOF. */
- if (c == EOF) {
- /* The last line of fp isn't \n terminated */
- (*line)++;
- return s;
- }
- else {
- ungetc (c, fp); /* undo our dammage */
- /* There wasn't room for the line -- increase ``s'' */
- offset = *size - 1; /* overwrite the terminating 0 */
- *size += STRING;
- p_realloc(&s, *size);
- }
- }
- }
-}
-
-/* prepare a file name to survive the shell's quoting rules.
- * From the Unix programming FAQ by way of Liviu.
- */
-
-size_t mutt_quote_filename (char *d, size_t l, const char *f)
-{
- size_t i, j = 0;
-
- if (!f) {
- *d = '\0';
- return 0;
- }
-
- /* leave some space for the trailing characters. */
- l -= 6;
-
- d[j++] = '\'';
-
- for (i = 0; j < l && f[i]; i++) {
- if (f[i] == '\'' || f[i] == '`') {
- d[j++] = '\'';
- d[j++] = '\\';
- d[j++] = f[i];
- d[j++] = '\'';
- }
- else
- d[j++] = f[i];
- }
-
- d[j++] = '\'';
- d[j] = '\0';
-
- return j;
-}
-
-char *mutt_concat_path (char *d, const char *dir, const char *fname, size_t l)
-{
- const char *fmt = "%s/%s";
-
- if (!*fname || (*dir && dir[m_strlen(dir) - 1] == '/'))
- fmt = "%s%s";
-
- snprintf (d, l, fmt, dir, fname);
- return d;
-}
-
-const char *mutt_basename (const char *f)
-{
- const char *p = strrchr (f, '/');
-
- if (p)
- return p + 1;
- else
- return f;
-}
-
const char *
mutt_strsysexit(int e)
{
# include <posix1_lim.h>
# endif
-# define TRUE 1
-# define FALSE 0
-
-# undef MAX
-# undef MIN
-# define MAX(a,b) ((a) < (b) ? (b) : (a))
-# define MIN(a,b) ((a) < (b) ? (a) : (b))
-
void mutt_exit (int);
/* Exit values used in send_msg() */
/* The actual library functions. */
-FILE *safe_fopen (const char *, const char *);
-
-char *mutt_concat_path (char *, const char *, const char *, size_t);
-char *mutt_read_line (char *, size_t *, FILE *, int *);
-
-const char *mutt_basename (const char *);
-
-int mutt_copy_stream (FILE *, FILE *);
-int mutt_copy_bytes (FILE *, FILE *, size_t);
int mutt_rx_sanitize_string (char *, size_t, const char *);
-int safe_open (const char *, int);
-int safe_symlink (const char *, const char *);
-int safe_rename (const char *, const char *);
-int safe_fclose (FILE **);
-
-size_t mutt_quote_filename (char *, size_t, const char *);
-
void mutt_nocurses_error (const char *, ...);
-void mutt_sanitize_filename (char *, short);
-void mutt_unlink (const char *);
const char *mutt_strsysexit(int e);
#include <time.h>
#include <lib-lib/str.h>
+#include <lib-lib/file.h>
#include "debug.h"
#include "mutt.h"
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "mutt_curses.h"
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "mx.h"
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "mx.h"
const unsigned int *pbufsize;
/* read buffer */
- const char *buf;
+ char *buf;
unsigned int blen;
unsigned int bpos;
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "mutt_socket.h"
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
#include <lib-lib/buffer.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
if (mutt_get_field (_("File under directory: "), tmp, sizeof (tmp),
M_FILE | M_CLEAR) != 0 || !tmp[0])
return (-1);
- mutt_concat_path (fname, path, tmp, flen);
+ mutt_concat_path(fname, flen, path, tmp);
}
else
- mutt_concat_path (fname, path, mutt_basename (attname), flen);
+ mutt_concat_path(fname, flen, path, mutt_basename(attname));
}
if (*append == 0 && access (fname, F_OK) == 0) {
#include <lib-lib/ascii.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "buffy.h"
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
+#include <lib-lib/file.h>
#include <lib-lib/macros.h>
#include "mutt.h"
}
static int mutt_update_list_file (char *filename, char *section,
- char *key, char *line) {
+ const char *key, char *line) {
FILE *ifp;
FILE *ofp;
char buf[HUGE_STRING];
}
/* newrc being fully rewritten */
if (news->newsrc &&
- (r = mutt_update_list_file (news->newsrc, NULL, "", buf)) == 0) {
+ (r = mutt_update_list_file(news->newsrc, NULL, "", buf)) == 0) {
struct stat st;
stat (news->newsrc, &st);
/* Updates info into .index file: ALL or about selected newsgroup */
static int nntp_update_cacheindex (NNTP_SERVER * serv, NNTP_DATA * data)
{
- char buf[LONG_STRING], *key = "ALL";
+ char buf[LONG_STRING];
char file[_POSIX_PATH_MAX];
+ const char *key = "ALL";
if (!serv || !serv->conn || !serv->conn->account.host)
return -1;
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
+#include <lib-lib/file.h>
#include <lib-lib/macros.h>
#include "mutt.h"
#include <lib-lib/ascii.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include <lib-lib/buffer.h>
#include "mutt.h"
#include <lib-lib/ascii.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "mutt_curses.h"
#include <lib-lib/str.h>
#include <lib-lib/ascii.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
#include <string.h>
#include <ctype.h>
+#include <lib-lib/file.h>
#include "lib/debug.h"
static struct {
#endif
#include <lib-lib/mem.h>
+#include <lib-lib/file.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
#include <lib-lib/str.h>
#include <lib-lib/ascii.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "mutt_menu.h"
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
#include <lib-lib/ascii.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
if (body->filename) {
if (directory && *directory)
- mutt_concat_path (buf, *directory, mutt_basename (body->filename),
- sizeof (buf));
+ mutt_concat_path(buf, sizeof(buf), *directory,
+ mutt_basename(body->filename));
else
strfcpy (buf, body->filename, sizeof (buf));
}
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "recvattach.h"
#include <lib-lib/str.h>
#include <lib-lib/ascii.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "rfc1524.h"
#include <lib-lib/str.h>
#include <lib-lib/ascii.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "mutt_curses.h"
#include <lib-lib/str.h>
#include <lib-lib/ascii.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"
#include <lib-lib/ascii.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "handler.h"
#include <lib-lib/mem.h>
#include <lib-lib/str.h>
#include <lib-lib/macros.h>
+#include <lib-lib/file.h>
#include "mutt.h"
#include "enter.h"