summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--guile/mu-guile.cc2
-rw-r--r--lib/message/mu-message.cc3
-rw-r--r--lib/mu-maildir.cc9
-rw-r--r--lib/mu-store.cc1
-rw-r--r--lib/tests/test-mu-maildir.cc3
-rw-r--r--lib/tests/test-mu-store.cc1
-rw-r--r--lib/utils/meson.build44
-rw-r--r--lib/utils/mu-error.hh12
-rw-r--r--lib/utils/mu-util.c468
-rw-r--r--lib/utils/mu-util.h349
-rw-r--r--lib/utils/mu-utils-file.cc285
-rw-r--r--lib/utils/mu-utils-file.hh141
-rw-r--r--lib/utils/mu-utils.cc147
-rw-r--r--lib/utils/mu-utils.hh76
-rw-r--r--lib/utils/tests/meson.build17
-rw-r--r--lib/utils/tests/test-mu-util.c286
-rw-r--r--lib/utils/tests/test-utils.cc40
-rw-r--r--mu/mu-cmd-cfind.cc51
-rw-r--r--mu/mu-cmd-extract.cc31
-rw-r--r--mu/mu-cmd-find.cc11
-rw-r--r--mu/mu-cmd-index.cc4
-rw-r--r--mu/mu-cmd.cc14
-rw-r--r--mu/mu-options.hh4
23 files changed, 696 insertions, 1303 deletions
diff --git a/guile/mu-guile.cc b/guile/mu-guile.cc
index 853b123..4a295d1 100644
--- a/guile/mu-guile.cc
+++ b/guile/mu-guile.cc
@@ -31,6 +31,8 @@
#include <mu-store.hh>
#include <mu-query.hh>
+#include <utils/mu-utils-file.hh>
+
using namespace Mu;
SCM
diff --git a/lib/message/mu-message.cc b/lib/message/mu-message.cc
index e5bd40c..f81b01f 100644
--- a/lib/message/mu-message.cc
+++ b/lib/message/mu-message.cc
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
+** Copyright (C) 2022-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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
@@ -26,7 +26,6 @@
#include <array>
#include <string>
#include <regex>
-#include <utils/mu-util.h>
#include <utils/mu-utils.hh>
#include <utils/mu-error.hh>
#include <utils/mu-option.hh>
diff --git a/lib/mu-maildir.cc b/lib/mu-maildir.cc
index 8b27aa7..470512f 100644
--- a/lib/mu-maildir.cc
+++ b/lib/mu-maildir.cc
@@ -34,7 +34,7 @@
#include "glibconfig.h"
#include "mu-maildir.hh"
#include "utils/mu-utils.hh"
-#include "utils/mu-util.h"
+#include "utils/mu-utils-file.hh"
using namespace Mu;
@@ -61,7 +61,8 @@ get_dtype(struct dirent* dentry, const std::string& path, bool use_lstat)
slowpath:
#endif /*HAVE_STRUCT_DIRENT_D_TYPE*/
- return mu_util_get_dtype(path.c_str(), use_lstat);
+
+ return determine_dtype(path, use_lstat);
}
static Mu::Result<void>
@@ -77,7 +78,7 @@ create_maildir(const std::string& path, mode_t mode)
/* if subdir already exists, don't try to re-create
* it */
- if (mu_util_check_dir(fullpath.c_str(), TRUE, TRUE))
+ if (check_dir(fullpath, true/*readable*/, true/*writable*/))
continue;
int rv{g_mkdir_with_parents(fullpath.c_str(), static_cast<int>(mode))};
@@ -85,7 +86,7 @@ create_maildir(const std::string& path, mode_t mode)
/* note, g_mkdir_with_parents won't detect an error if
* there's already such a dir, but with the wrong
* permissions; so we need to check */
- if (rv != 0 || !mu_util_check_dir(fullpath.c_str(), TRUE, TRUE))
+ if (rv != 0 || !check_dir(fullpath, true/*readable*/, true/*writable*/))
return Err(Error{Error::Code::File,
"creating dir failed for %s: %s",
fullpath.c_str(), g_strerror(errno)});
diff --git a/lib/mu-store.cc b/lib/mu-store.cc
index f34b6d4..880a766 100644
--- a/lib/mu-store.cc
+++ b/lib/mu-store.cc
@@ -41,6 +41,7 @@
#include "utils/mu-error.hh"
#include "utils/mu-utils.hh"
+#include <utils/mu-utils-file.hh>
#include "utils/mu-xapian-utils.hh"
using namespace Mu;
diff --git a/lib/tests/test-mu-maildir.cc b/lib/tests/test-mu-maildir.cc
index d3713f6..5b9d545 100644
--- a/lib/tests/test-mu-maildir.cc
+++ b/lib/tests/test-mu-maildir.cc
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 2008-2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
+** Copyright (C) 2008-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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
@@ -29,7 +29,6 @@
#include "utils/mu-test-utils.hh"
#include "mu-maildir.hh"
#include "utils/mu-result.hh"
-#include "utils/mu-util.h"
using namespace Mu;
diff --git a/lib/tests/test-mu-store.cc b/lib/tests/test-mu-store.cc
index 7801ad0..872c56e 100644
--- a/lib/tests/test-mu-store.cc
+++ b/lib/tests/test-mu-store.cc
@@ -33,6 +33,7 @@
#include "mu-store.hh"
#include "utils/mu-result.hh"
#include <utils/mu-utils.hh>
+#include <utils/mu-utils-file.hh>
#include "mu-maildir.hh"
using namespace Mu;
diff --git a/lib/utils/meson.build b/lib/utils/meson.build
index 93902e2..b8e446a 100644
--- a/lib/utils/meson.build
+++ b/lib/utils/meson.build
@@ -16,22 +16,22 @@
lib_mu_utils=static_library('mu-utils', [
- 'mu-command-handler.cc',
- 'mu-logger.cc',
+ 'mu-command-handler.cc',
+ 'mu-logger.cc',
'mu-option.cc',
- 'mu-readline.cc',
- 'mu-sexp.cc',
+ 'mu-readline.cc',
+ 'mu-sexp.cc',
'mu-test-utils.cc',
- 'mu-util.c',
- 'mu-utils.cc'],
- dependencies: [
- glib_dep,
+ 'mu-utils.cc',
+ 'mu-utils-file.cc'],
+ dependencies: [
+ glib_dep,
gio_dep,
- config_h_dep,
- readline_dep
- ],
- include_directories: include_directories(['.','..']),
- install: false)
+ config_h_dep,
+ readline_dep
+ ],
+ include_directories: include_directories(['.','..']),
+ install: false)
lib_mu_utils_dep = declare_dependency(
link_with: lib_mu_utils,
@@ -43,14 +43,20 @@ lib_mu_utils_dep = declare_dependency(
#
test('test-sexp',
executable('test-sexp', 'mu-sexp.cc',
- install: false,
- cpp_args: ['-DBUILD_TESTS'],
- dependencies: [glib_dep, lib_mu_utils_dep]))
+ install: false,
+ cpp_args: ['-DBUILD_TESTS'],
+ dependencies: [glib_dep, lib_mu_utils_dep]))
test('test-command-handler',
executable('test-command-handler', 'mu-command-handler.cc',
- install: false,
- cpp_args: ['-DBUILD_TESTS'],
- dependencies: [glib_dep, lib_mu_utils_dep]))
+ install: false,
+ cpp_args: ['-DBUILD_TESTS'],
+ dependencies: [glib_dep, lib_mu_utils_dep]))
+
+test('test-utils-file',
+ executable('test-utils-file', 'mu-utils-file.cc',
+ install: false,
+ cpp_args: ['-DBUILD_TESTS'],
+ dependencies: [glib_dep, config_h_dep, lib_mu_utils_dep]))
subdir('tests')
diff --git a/lib/utils/mu-error.hh b/lib/utils/mu-error.hh
index 9aa1c8e..55a8002 100644
--- a/lib/utils/mu-error.hh
+++ b/lib/utils/mu-error.hh
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 2019-2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
+** Copyright (C) 2019-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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
@@ -24,7 +24,6 @@
#include <string>
#include "mu-utils-format.hh"
-#include "mu-util.h"
#include <glib.h>
namespace Mu {
@@ -164,11 +163,18 @@ struct Error final : public std::exception {
* @param err GError** (or NULL)
*/
void fill_g_error(GError **err) const noexcept{
- g_set_error(err, MU_ERROR_DOMAIN, static_cast<int>(code_),
+ g_set_error(err, error_quark(), static_cast<int>(code_),
"%s", what_.c_str());
}
private:
+ static inline GQuark error_quark (void) {
+ static GQuark error_domain = 0;
+ if (G_UNLIKELY(error_domain == 0))
+ error_domain = g_quark_from_static_string("mu-error-quark");
+ return error_domain;
+ }
+
const Code code_;
std::string what_;
};
diff --git a/lib/utils/mu-util.c b/lib/utils/mu-util.c
deleted file mode 100644
index a2e3bc6..0000000
--- a/lib/utils/mu-util.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
-** Copyright (C) 2008-2021 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
-**
-** 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 3 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.
-**
-*/
-
-#include <config.h>
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif /*_GNU_SOURCE*/
-
-#include "mu-util.h"
-#ifdef HAVE_WORDEXP_H
-#include <wordexp.h> /* for shell-style globbing */
-#endif /*HAVE_WORDEXP_H*/
-
-#include <stdlib.h>
-
-#include <string.h>
-#include <locale.h> /* for setlocale() */
-
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <glib-object.h>
-#include <glib/gstdio.h>
-#include <gio/gio.h>
-#include <errno.h>
-
-#include <langinfo.h>
-
-
-static char*
-do_wordexp (const char *path)
-{
-#ifdef HAVE_WORDEXP_H
- wordexp_t wexp;
- char *dir;
-
- if (!path) {
- /* g_debug ("%s: path is empty", __func__); */
- return NULL;
- }
-
- if (wordexp (path, &wexp, 0) != 0) {
- /* g_debug ("%s: expansion failed for %s", __func__, path); */
- return NULL;
- }
-
- /* we just pick the first one */
- dir = g_strdup (wexp.we_wordv[0]);
-
- /* strangely, below seems to lead to a crash on MacOS (BSD);
- so we have to allow for a tiny leak here on that
- platform... maybe instead of __APPLE__ it should be
- __BSD__?
-
- Hmmm., cannot reproduce that crash anymore, so commenting
- it out for now...
- */
-/* #ifndef __APPLE__ */
- wordfree (&wexp);
-/* #endif /\*__APPLE__*\/ */
- return dir;
-
-# else /*!HAVE_WORDEXP_H*/
-/* E.g. OpenBSD does not have wordexp.h, so we ignore it */
- return path ? g_strdup (path) : NULL;
-#endif /*HAVE_WORDEXP_H*/
-}
-
-
-/* note, the g_debugs are commented out because this function may be
- * called before the log handler is installed. */
-char*
-mu_util_dir_expand (const char *path)
-{
- char *dir;
- char resolved[PATH_MAX + 1];
-
- g_return_val_if_fail (path, NULL);
-
- dir = do_wordexp (path);
- if (!dir)
- return NULL; /* error */
-
- /* don't try realpath if the dir does not exist */
- if (access (dir, F_OK) != 0)
- return dir;
-
- /* now resolve any symlinks, .. etc. */
- if (realpath (dir, resolved) == NULL) {
- /* g_debug ("%s: could not get realpath for '%s': %s", */
- /* __func__, dir, g_strerror(errno)); */
- g_free (dir);
- return NULL;
- } else
- g_free (dir);
-
- return g_strdup (resolved);
-}
-
-GQuark
-mu_util_error_quark (void)
-{
- static GQuark error_domain = 0;
-
- if (G_UNLIKELY(error_domain == 0))
- error_domain = g_quark_from_static_string
- ("mu-error-quark");
-
- return error_domain;
-}
-
-gboolean
-mu_util_check_dir (const gchar* path, gboolean readable, gboolean writeable)
-{
- int mode;
- struct stat statbuf;
-
- if (!path)
- return FALSE;
-
- mode = F_OK | (readable ? R_OK : 0) | (writeable ? W_OK : 0);
-
- if (access (path, mode) != 0) {
- /* g_debug ("Cannot access %s: %s", path, g_strerror (errno)); */
- return FALSE;
- }
-
- if (stat (path, &statbuf) != 0) {
- /* g_debug ("Cannot stat %s: %s", path, g_strerror (errno)); */
- return FALSE;
- }
-
- return S_ISDIR(statbuf.st_mode) ? TRUE: FALSE;
-}
-
-
-gchar*
-mu_util_guess_maildir (void)
-{
- const gchar *mdir1, *home;
-
- /* first, try MAILDIR */
- mdir1 = g_getenv ("MAILDIR");
-
- if (mdir1 && mu_util_check_dir (mdir1, TRUE, FALSE))
- return g_strdup (mdir1);
-
- /* then, try <home>/Maildir */
- home = g_get_home_dir();
- if (home) {
- char *mdir2;
- mdir2 = g_strdup_printf ("%s%cMaildir",
- home, G_DIR_SEPARATOR);
- if (mu_util_check_dir (mdir2, TRUE, FALSE))
- return mdir2;
- g_free (mdir2);
- }
-
- /* nope; nothing found */
- return NULL;
-}
-
-gboolean
-mu_util_create_dir_maybe (const gchar *path, mode_t mode, gboolean nowarn)
-{
- struct stat statbuf;
-
- g_return_val_if_fail (path, FALSE);
-
- /* if it exists, it must be a readable dir */
- if (stat (path, &statbuf) == 0) {
- if ((!S_ISDIR(statbuf.st_mode)) ||
- (access (path, W_OK|R_OK) != 0)) {
- if (!nowarn)
- g_warning ("not a read-writable"
- "directory: %s", path);
- return FALSE;
- }
- }
-
- if (g_mkdir_with_parents (path, mode) != 0) {
- if (!nowarn)
- g_warning ("failed to create %s: %s",
- path, g_strerror(errno));
- return FALSE;
- }
-
- return TRUE;
-}
-
-gboolean
-mu_util_supports (MuFeature feature)
-{
- /* check for Guile support */
-#ifndef BUILD_GUILE
- if (feature & MU_FEATURE_GUILE)
- return FALSE;
-#endif /*BUILD_GUILE*/
-
- /* check for Gnuplot */
- if (feature & MU_FEATURE_GNUPLOT)
- if (!mu_util_program_in_path ("gnuplot"))
- return FALSE;
-
- return TRUE;
-}
-
-
-gboolean
-mu_util_program_in_path (const char *prog)
-{
- gchar *path;
-
- g_return_val_if_fail (prog, FALSE);
-
- path = g_find_program_in_path (prog);
- g_free (path);
-
- return (path != NULL) ? TRUE : FALSE;
-}
-
-
-/*
- * Set the child to a group leader to avoid being killed when the
- * parent group is killed.
- */
-static void
-maybe_setsid (G_GNUC_UNUSED gpointer user_data)
-{
-#if HAVE_SETSID
- setsid();
-#endif /*HAVE_SETSID*/
-}
-
-gboolean
-mu_util_play (const char *path, GError **err)
-{
- GFile *gf;
- gboolean rv, is_native;
- const gchar *argv[3];
- const char *prog;
-
- g_return_val_if_fail (path, FALSE);
-
- gf = g_file_new_for_path(path);
- is_native = g_file_is_native(gf);
- g_object_unref(gf);
-
- if (!is_native) {
- mu_util_g_set_error (err, MU_ERROR_FILE_CANNOT_EXECUTE,
- "'%s' is not a native file", path);
- return FALSE;
- }
-
- prog = g_getenv ("MU_PLAY_PROGRAM");
- if (!prog) {
-#ifdef __APPLE__
- prog = "open";
-#else
- prog = "xdg-open";
-#endif /*!__APPLE__*/
- }
-
- if (!mu_util_program_in_path (prog)) {
- mu_util_g_set_error (err, MU_ERROR_FILE_CANNOT_EXECUTE,
- "cannot find '%s' in path", prog);
- return FALSE;
- }
-
- argv[0] = prog;
- argv[1] = path;
- argv[2] = NULL;
-
- err = NULL;
- rv = g_spawn_async (NULL, (gchar**)&argv, NULL,
- G_SPAWN_SEARCH_PATH, maybe_setsid,
- NULL, NULL, err);
- return rv;
-}
-
-
-unsigned char
-mu_util_get_dtype (const char *path, gboolean use_lstat)
-{
- int res;
- struct stat statbuf;
-
- g_return_val_if_fail (path, DT_UNKNOWN);
-
- if (use_lstat)
- res = lstat (path, &statbuf);
- else
- res = stat (path, &statbuf);
-
- if (res != 0) {
- g_warning ("%sstat failed on %s: %s",
- use_lstat ? "l" : "", path, g_strerror(errno));
- return DT_UNKNOWN;
- }
-
- /* we only care about dirs, regular files and links */
- if (S_ISREG (statbuf.st_mode))
- return DT_REG;
- else if (S_ISDIR (statbuf.st_mode))
- return DT_DIR;
- else if (S_ISLNK (statbuf.st_mode))
- return DT_LNK;
-
- return DT_UNKNOWN;
-}
-
-
-
-gboolean
-mu_util_locale_is_utf8 (void)
-{
- const gchar *dummy;
- static int is_utf8 = -1;
-
- if (G_UNLIKELY(is_utf8 == -1))
- is_utf8 = g_get_charset(&dummy) ? 1 : 0;
-
- return is_utf8 ? TRUE : FALSE;
-}
-
-gboolean
-mu_util_fputs_encoded (const char *str, FILE *stream)
-{
- int rv;
- char *conv;
-
- g_return_val_if_fail (stream, FALSE);
-
- /* g_get_charset return TRUE when the locale is UTF8 */
- if (mu_util_locale_is_utf8())
- return fputs (str, stream) == EOF ? FALSE : TRUE;
-
- /* charset is _not_ utf8, so we need to convert it */
- conv = NULL;
- if (g_utf8_validate (str, -1, NULL))
- conv = g_locale_from_utf8 (str, -1, NULL, NULL, NULL);
-
- /* conversion failed; this happens because is some cases GMime may gives
- * us non-UTF-8 strings from e.g. wrongly encoded message-subjects; if
- * so, we escape the string */
- conv = conv ? conv : g_strescape (str, "\n\t");
- rv = conv ? fputs (conv, stream) : EOF;
- g_free (conv);
-
- return (rv == EOF) ? FALSE : TRUE;
-}
-
-
-
-gboolean
-mu_util_g_set_error (GError **err, MuError errcode, const char *frm, ...)
-{
- va_list ap;
- char *msg;
-
- /* don't bother with NULL errors, or errors already set */
- if (!err || *err)
- return FALSE;
-
- msg = NULL;
- va_start (ap, frm);
- g_vasprintf (&msg, frm, ap);
- va_end (ap);
-
- g_set_error (err, MU_ERROR_DOMAIN, errcode, "%s", msg);
-
- g_free (msg);
-
- return FALSE;
-}
-
-
-
-__attribute__((format(printf, 2, 0))) static gboolean
-print_args (FILE *stream, const char *frm, va_list args)
-{
- gchar *str;
- gboolean rv;
-
- str = g_strdup_vprintf (frm, args);
-
- rv = mu_util_fputs_encoded (str, stream);
-
- g_free (str);
-
- return rv;
-}
-
-
-gboolean
-mu_util_print_encoded (const char *frm, ...)
-{
- va_list args;
- gboolean rv;
-
- g_return_val_if_fail (frm, FALSE);
-
- va_start (args, frm);
- rv = print_args (stdout, frm, args);
- va_end (args);
-
- return rv;
-}
-
-char*
-mu_str_summarize (const char* str, size_t max_lines)
-{
- char *summary;
- size_t nl_seen;
- unsigned i,j;
- gboolean last_was_blank;
-
- g_return_val_if_fail (str, NULL);
- g_return_val_if_fail (max_lines > 0, NULL);
-
- /* len for summary <= original len */
- summary = g_new (gchar, strlen(str) + 1);
-
- /* copy the string up to max_lines lines, replace CR/LF/tab with
- * single space */
- for (i = j = 0, nl_seen = 0, last_was_blank = TRUE;
- nl_seen < max_lines && str[i] != '\0'; ++i) {
-
- if (str[i] == '\n' || str[i] == '\r' ||
- str[i] == '\t' || str[i] == ' ' ) {
-
- if (str[i] == '\n')
- ++nl_seen;
-
- /* no double-blanks or blank at end of str */
- if (!last_was_blank && str[i+1] != '\0')
- summary[j++] = ' ';
-
- last_was_blank = TRUE;
- } else {
-
- summary[j++] = str[i];
- last_was_blank = FALSE;
- }
- }
-
- summary[j] = '\0';
- return summary;
-}
diff --git a/lib/utils/mu-util.h b/lib/utils/mu-util.h
deleted file mode 100644
index 3dedc0a..0000000
--- a/lib/utils/mu-util.h
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
-** Copyright (C) 2008-2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
-**
-** 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 3 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.
-**
-*/
-
-#ifndef __MU_UTIL_H__
-#define __MU_UTIL_H__
-
-#include <glib.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <sys/stat.h> /* for mode_t */
-
-/* hopefully, this should get us a sane PATH_MAX */
-#include <limits.h>
-/* not all systems provide PATH_MAX in limits.h */
-#ifndef PATH_MAX
-#include <sys/param.h>
-#ifndef PATH_MAX
-#define PATH_MAX MAXPATHLEN
-#endif /*!PATH_MAX*/
-#endif /*PATH_MAX*/
-
-G_BEGIN_DECLS
-
-/**
- * get the expanded path; ie. perform shell expansion on the path. the
- * path does not have to exist
- *
- * @param path path to expand
- *
- * @return the expanded path as a newly allocated string, or NULL in
- * case of error
- */
-char* mu_util_dir_expand(const char* path) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
-
-/**
- * guess the maildir; first try $MAILDIR; if it is unset or
- * non-existent, try ~/Maildir if both fail, return NULL
- *
- * @return full path of the guessed Maildir, or NULL; must be freed (gfree)
- */
-char* mu_util_guess_maildir (void)
- G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
-
-/**
- * if path exists, check that's a read/writeable dir; otherwise try to
- * create it (with perms 0700)
- *
- * @param path path to the dir
- * @param mode to set for the dir (as per chmod(1))
- * @param nowarn, if TRUE, don't write warnings (if any) to stderr
- *
- * @return TRUE if a read/writeable directory `path' exists after
- * leaving this function, FALSE otherwise
- */
-gboolean mu_util_create_dir_maybe (const gchar *path, mode_t mode,
- gboolean nowarn) G_GNUC_WARN_UNUSED_RESULT;
-
-/**
- * check whether path is a directory, and optionally, if it's readable
- * and/or writeable
- *
- * @param path dir path
- * @param readable check for readability
- * @param writeable check for writability
- *
- * @return TRUE if dir exist and has the specified properties
- */
-gboolean mu_util_check_dir (const gchar* path, gboolean readable,
- gboolean writeable)
- G_GNUC_WARN_UNUSED_RESULT;
-
-/**
- * is the current locale utf-8 compatible?
- *
- * @return TRUE if it's utf8 compatible, FALSE otherwise
- */
-gboolean mu_util_locale_is_utf8 (void) G_GNUC_CONST;
-
-/**
- * get a 'summary' of the string, ie. the first /n/ lines of the
- * strings, with all newlines removed, replaced by single spaces
- *
- * @param str the source string
- * @param max_lines the maximum number of lines to include in the summary
- *
- * @return a newly allocated string with the summary. use g_free to free it.
- */
-char* mu_str_summarize (const char* str, size_t max_lines)
- G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
-
-
-/**
- * write a string (assumed to be in utf8-format) to a stream,
- * converted to the current locale
- *
- * @param str a string
- * @param stream a stream
- *
- * @return TRUE if printing worked, FALSE otherwise
- */
-gboolean mu_util_fputs_encoded (const char *str, FILE *stream);
-
-/**
- * print a formatted string (assumed to be in utf8-format) to stdout,
- * converted to the current locale
- *
- * @param a standard printf() format string, followed by a parameter list
- *
- * @return TRUE if printing worked, FALSE otherwise
- */
-gboolean mu_util_print_encoded (const char *frm, ...) G_GNUC_PRINTF(1,2);
-
-
-/**
- * Try to 'play' (ie., open with it's associated program) a file. On MacOS, the
- * the program 'open' is used for this; on other platforms 'xdg-open' to do the
- * actual opening. In addition you can set it to another program by setting the
- * MU_PLAY_PROGRAM environment variable
- *
- * This requires a 'native' file, see g_file_is_native()
- *
- * @param path full path of the file to open
- * @param err receives error information, if any
- *
- * @return TRUE if it succeeded, FALSE otherwise
- */
-gboolean mu_util_play (const char *path, GError **err);
-
-/**
- * Check whether program prog exists in PATH
- *
- * @param prog a program (executable)
- *
- * @return TRUE if it exists and is executable, FALSE otherwise
- */
-gboolean mu_util_program_in_path (const char *prog);
-
-
-enum _MuFeature {
- MU_FEATURE_GUILE = 1 << 0, /* do we support Guile 2.0? */
- MU_FEATURE_GNUPLOT = 1 << 1, /* do we have gnuplot installed? */
-};
-typedef enum _MuFeature MuFeature;
-
-/**
- * Check whether mu supports some particular feature
- *
- * @param feature a feature (multiple features can be logical-or'd together)
- *
- * @return TRUE if the feature is supported, FALSE otherwise
- */
-gboolean mu_util_supports (MuFeature feature);
-
-
-
-/**
- * Get an error-query for mu, to be used in `g_set_error'. Recent
- * version of Glib warn when using 0 for the error-domain in
- * g_set_error.
- *
- *
- * @return an error quark for mu
- */
-GQuark mu_util_error_quark (void) G_GNUC_CONST;
-#define MU_ERROR_DOMAIN (mu_util_error_quark())
-
-
-/*
- * for OSs with out support for direntry->d_type, like Solaris
- */
-#ifndef DT_UNKNOWN
-enum {
- DT_UNKNOWN = 0,
-#define DT_UNKNOWN DT_UNKNOWN
- DT_FIFO = 1,
-#define DT_FIFO DT_FIFO
- DT_CHR = 2,
-#define DT_CHR DT_CHR
- DT_DIR = 4,
-#define DT_DIR DT_DIR
- DT_BLK = 6,
-#define DT_BLK DT_BLK
- DT_REG = 8,
-#define DT_REG DT_REG
- DT_LNK = 10,
-#define DT_LNK DT_LNK
- DT_SOCK = 12,
-#define DT_SOCK DT_SOCK
- DT_WHT = 14
-#define DT_WHT DT_WHT
-};
-#endif /*DT_UNKNOWN*/
-
-
-/**
- * get the d_type (as in direntry->d_type) for the file at path, using either
- * stat(3) or lstat(3)
- *
- * @param path full path
- * @param use_lstat whether to use lstat (otherwise use stat)
- *
- * @return DT_REG, DT_DIR, DT_LNK, or DT_UNKNOWN (other values are not supported
- * currently )
- */
-unsigned char mu_util_get_dtype (const char *path, gboolean use_lstat);
-
-
-/**
- * we need this when using Xapian::Document* from C
- *
- */
-typedef gpointer XapianDocument;
-
-/**
- * we need this when using Xapian::Enquire* from C
- *
- */
-typedef gpointer XapianEnquire;
-
-
-/* print a warning for a GError, and free it */
-#define MU_HANDLE_G_ERROR(GE) \
- do { \
- if (!(GE)) \
- g_warning ("%s:%u: an error occurred in %s", \
- __FILE__, __LINE__, __func__); \
- else { \
- g_warning ("error %u: %s", (GE)->code, (GE)->message); \
- g_error_free ((GE)); \
- } \
- } while (0)
-
-
-#define MU_G_ERROR_CODE(GE) ((GE)&&(*(GE))?(MuError)(*(GE))->code:MU_ERROR)
-
-
-enum _MuError {
- /* no error at all! */
- MU_OK = 0,
-
- /* generic error */
- MU_ERROR = 1,
- MU_ERROR_IN_PARAMETERS = 2,
- MU_ERROR_INTERNAL = 3,
- MU_ERROR_NO_MATCHES = 4,
-
- /* not really an error; for callbacks */
- MU_IGNORE = 5,
-
- MU_ERROR_SCRIPT_NOT_FOUND = 8,
-
- /* general xapian related error */
- MU_ERROR_XAPIAN = 11,
-
- /* (parsing) error in the query */
- MU_ERROR_XAPIAN_QUERY = 13,
-
- /* missing data for a document */
- MU_ERROR_XAPIAN_MISSING_DATA = 17,
- /* can't get write lock */
- MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK = 19,
- /* could not write */
- MU_ERROR_XAPIAN_STORE_FAILED = 21,
- /* could not remove */
- MU_ERROR_XAPIAN_REMOVE_FAILED = 22,
- /* database was modified; reload */
- MU_ERROR_XAPIAN_MODIFIED = 23,
- /* database was modified; reload */
- MU_ERROR_XAPIAN_NEEDS_REINDEX = 24,
- /* database schema version doesn't match */
- MU_ERROR_XAPIAN_SCHEMA_MISMATCH = 25,
- /* failed to open the database */
- MU_ERROR_XAPIAN_CANNOT_OPEN = 26,
-
- /* GMime related errors */
-
- /* gmime parsing related error */
- MU_ERROR_GMIME = 30,
-
- /* contacts related errors */
- MU_ERROR_CONTACTS = 50,
- MU_ERROR_CONTACTS_CANNOT_RETRIEVE = 51,
-
- /* crypto related errors */
- MU_ERROR_CRYPTO = 60,
-
-
- /* File errors */
- /* generic file-related error */
- MU_ERROR_FILE = 70,
- MU_ERROR_FILE_INVALID_NAME = 71,
- MU_ERROR_FILE_CANNOT_LINK = 72,
- MU_ERROR_FILE_CANNOT_OPEN = 73,
- MU_ERROR_FILE_CANNOT_READ = 74,
- MU_ERROR_FILE_CANNOT_EXECUTE = 75,
- MU_ERROR_FILE_CANNOT_CREATE = 76,
- MU_ERROR_FILE_CANNOT_MKDIR = 77,
- MU_ERROR_FILE_STAT_FAILED = 78,
- MU_ERROR_FILE_READDIR_FAILED = 79,
- MU_ERROR_FILE_INVALID_SOURCE = 80,
- MU_ERROR_FILE_TARGET_EQUALS_SOURCE = 81,
- MU_ERROR_FILE_CANNOT_WRITE = 82,
- MU_ERROR_FILE_CANNOT_UNLINK = 83,
-
- /* not really an error, used in callbacks */
- MU_STOP = 99
-};
-typedef enum _MuError MuError;
-
-
-/**
- * set an error if it's not already set, and return FALSE
- *
- * @param err errptr, or NULL
- * @param errcode error code
- * @param frm printf-style format, followed by parameters
- *
- * @return FALSE
- */
-gboolean mu_util_g_set_error (GError **err, MuError errcode, const char *frm, ...)
- G_GNUC_PRINTF(3,4);
-
-#define MU_COLOR_RED "\x1b[31m"
-#define MU_COLOR_GREEN "\x1b[32m"
-#define MU_COLOR_YELLOW "\x1b[33m"
-#define MU_COLOR_BLUE "\x1b[34m"
-#define MU_COLOR_MAGENTA "\x1b[35m"
-#define MU_COLOR_CYAN "\x1b[36m"
-#define MU_COLOR_DEFAULT "\x1b[0m"
-
-G_END_DECLS
-
-#endif /*__MU_UTIL_H__*/
diff --git a/lib/utils/mu-utils-file.cc b/lib/utils/mu-utils-file.cc
new file mode 100644
index 0000000..9bc8c1d
--- /dev/null
+++ b/lib/utils/mu-utils-file.cc
@@ -0,0 +1,285 @@
+/*
+** Copyright (C) 2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
+**
+** 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 3, 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.
+**
+*/
+
+#include "config.h"
+
+#include "mu-utils.hh"
+#include "mu-utils-file.hh"
+
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+using namespace Mu;
+
+
+Mu::Option<std::string>
+Mu::program_in_path(const std::string& name)
+{
+ if (char *path = g_find_program_in_path(name.c_str()); path)
+ return to_string_gchar(std::move(path)/*consumes*/);
+ else
+ return Nothing;
+}
+
+/*
+ * Set the child to a group leader to avoid being killed when the
+ * parent group is killed.
+ */
+static void
+maybe_setsid (G_GNUC_UNUSED gpointer user_data)
+{
+#if HAVE_SETSID
+ setsid();
+#endif /*HAVE_SETSID*/
+}
+
+Mu::Result<void>
+Mu::play (const std::string& path)
+{
+ /* check nativity */
+ GFile *gf = g_file_new_for_path(path.c_str());
+ auto is_native = g_file_is_native(gf);
+ g_object_unref(gf);
+ if (!is_native)
+ return Err(Error::Code::File, "'%s' is not a native file", path.c_str());
+
+ const char *prog{g_getenv ("MU_PLAY_PROGRAM")};
+ if (!prog) {
+#ifdef __APPLE__
+ prog = "open";
+#else
+ prog = "xdg-open";
+#endif /*!__APPLE__*/
+ }
+
+ const auto program_path{program_in_path(prog)};
+ if (!program_path)
+ return Err(Error::Code::File, "cannot find '%s' in path", prog);
+
+ const gchar *argv[3]{};
+ argv[0] = program_path->c_str();
+ argv[1] = path.c_str();
+ argv[2] = nullptr;
+
+ GError *err{};
+ if (!g_spawn_async ({}, (gchar**)&argv, {}, G_SPAWN_SEARCH_PATH, maybe_setsid,
+ {}, {}, &err))
+ return Err(Error::Code::File, &err/*consumes*/, "failed to open '%s' with '%s'",
+ path. c_str(), program_path->c_str());
+
+ return Ok();
+}
+
+
+bool
+Mu::check_dir (const std::string& path, bool readable, bool writeable)
+{
+ const auto mode = F_OK | (readable ? R_OK : 0) | (writeable ? W_OK : 0);
+
+ if (::access (path.c_str(), mode) != 0)
+ return false;
+
+ struct stat statbuf{};
+ if (::stat (path.c_str(), &statbuf) != 0)
+ return false;
+
+ return S_ISDIR(statbuf.st_mode) ? true : false;
+}
+
+uint8_t
+Mu::determine_dtype (const std::string& path, bool use_lstat)
+{
+ int res;
+ struct stat statbuf{};
+
+ if (use_lstat)
+ res = ::lstat(path.c_str(), &statbuf);
+ else
+ res = ::stat(path.c_str(), &statbuf);
+
+ if (res != 0) {
+ g_warning ("%sstat failed on %s: %s",
+ use_lstat ? "l" : "", path.c_str(), g_strerror(errno));
+ return DT_UNKNOWN;
+ }
+
+ /* we only care about dirs, regular files and links */
+ if (S_ISREG (statbuf.st_mode))
+ return DT_REG;
+ else if (S_ISDIR (statbuf.st_mode))
+ return DT_DIR;
+ else if (S_ISLNK (statbuf.st_mode))
+ return DT_LNK;
+
+ return DT_UNKNOWN;
+}
+
+std::string
+Mu::canonicalize_filename(const std::string& path, const std::string& relative_to)
+{
+ auto str{to_string_opt_gchar(
+ g_canonicalize_filename(
+ path.c_str(),
+ relative_to.empty() ? nullptr : relative_to.c_str())).value()};
+
+ // remove trailing '/'... is this needed?
+ if (str[str.length()-1] == G_DIR_SEPARATOR)
+ str.erase(str.length() - 1);
+
+ return str;
+}
+
+
+std::string
+Mu::runtime_path(Mu::RuntimePath path, const std::string& muhome)
+{
+ auto [mu_cache, mu_config] =
+ std::invoke([&]()->std::pair<std::string, std::string> {
+
+ static std::string mu{"/mu"};
+ if (muhome.empty())
+ return { g_get_user_cache_dir() + mu,
+ g_get_user_config_dir() + mu };
+ else
+ return { muhome, muhome };
+ });
+
+ switch (path) {
+ case Mu::RuntimePath::Cache:
+ return mu_cache;
+ case Mu::RuntimePath::XapianDb:
+ return mu_cache + "/xapian";
+ case Mu::RuntimePath::LogFile:
+ return mu_cache + "/mu.log";
+ case Mu::RuntimePath::Bookmarks:
+ return mu_config + "/bookmarks";
+ case Mu::RuntimePath::Config:
+ return mu_config;
+ case Mu::RuntimePath::Scripts:
+ return mu_config + "/scripts";
+ default:
+ throw std::logic_error("unknown path");
+ }
+}
+
+
+#ifdef BUILD_TESTS
+
+/*
+ * Tests.
+ *
+ */
+
+#include <glib/gstdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "utils/mu-test-utils.hh"
+
+static void
+test_check_dir_01(void)
+{
+ if (g_access("/usr/bin", F_OK) == 0) {
+ g_assert_cmpuint(
+ check_dir("/usr/bin", true, false) == true,
+ ==,
+ g_access("/usr/bin", R_OK) == 0);
+ }
+}
+
+static void
+test_check_dir_02(void)
+{
+ if (g_access("/tmp", F_OK) == 0) {
+ g_assert_cmpuint(
+ check_dir("/tmp", false, true) == true,
+ ==,
+ g_access("/tmp", W_OK) == 0);
+ }
+}
+
+static void
+test_check_dir_03(void)
+{
+ if (g_access(".", F_OK) == 0) {
+ g_assert_cmpuint(
+ check_dir(".", true, true) == true,
+ ==,
+ g_access(".", W_OK | R_OK) == 0);
+ }
+}
+
+static void
+test_check_dir_04(void)
+{
+ /* not a dir, so it must be false */
+ g_assert_cmpuint(
+ check_dir("test-util.c", true, true),
+ ==,
+ false);
+}
+
+static void
+test_determine_dtype_with_lstat(void)
+{
+ g_assert_cmpuint(
+ determine_dtype(MU_TESTMAILDIR, true), ==, DT_DIR);
+ g_assert_cmpuint(
+ determine_dtype(MU_TESTMAILDIR2, true), ==, DT_DIR);
+ g_assert_cmpuint(
+ determine_dtype(MU_TESTMAILDIR2 "/Foo/cur/mail5", true),
+ ==, DT_REG);
+}
+
+
+static void
+test_program_in_path(void)
+{
+ g_assert_true(!!program_in_path("ls"));
+}
+
+
+int
+main(int argc, char* argv[])
+{
+ mu_test_init(&argc, &argv);
+
+ /* check_dir */
+ g_test_add_func("/utils/check-dir-01",
+ test_check_dir_01);
+ g_test_add_func("/utils/check-dir-02",
+ test_check_dir_02);
+ g_test_add_func("/utils/check-dir-03",
+ test_check_dir_03);
+ g_test_add_func("/utils/check-dir-04",
+ test_check_dir_04);
+
+ g_test_add_func("/utils/determine-dtype-with-lstat",
+ test_determine_dtype_with_lstat);
+
+ g_test_add_func("/utils/program-in-path",
+ test_program_in_path);
+
+ return g_test_run();
+}
+
+#endif /*BUILD_TESTS*/
diff --git a/lib/utils/mu-utils-file.hh b/lib/utils/mu-utils-file.hh
new file mode 100644
index 0000000..f47ada5
--- /dev/null
+++ b/lib/utils/mu-utils-file.hh
@@ -0,0 +1,141 @@
+/*
+** Copyright (C) 2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
+**
+** 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 3, 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.
+**
+*/
+
+#ifndef MU_UTILS_FILE_HH__
+#define MU_UTILS_FILE_HH__
+
+#include <string>
+#include <cinttypes>
+#include <sys/stat.h>
+
+#include <utils/mu-sexp.hh>
+#include <utils/mu-option.hh>
+
+namespace Mu {
+
+/**
+ * Try to 'play' (ie., open with it's associated program) a file. On MacOS, the
+ * the program 'open' is used for this; on other platforms 'xdg-open' to do the
+ * actual opening. In addition you can set it to another program by setting thep
+ * MU_PLAY_PROGRAM environment variable
+ *
+ * This requires a 'native' file, see g_file_is_native()
+ *
+ * @param path full path of the file to open
+ *
+ * @return Ok() if succeeded, some error otherwise.
+ */
+Result<void> play(const std::string& path);
+
+/**
+ * Find program in PATH
+ *
+ * @param name the name of the program
+ *
+ * @return either the full path to program, or Nothing if not found.
+ */
+Option<std::string> program_in_path(const std::string& name);
+
+/**
+ * Check if the directory has the given attributes
+ *
+ * @param path path to dir
+ * @param readable is it readable?
+ * @param writeable is it writable?
+ *
+ * @return true if is is a directory with given attributes; false otherwise.
+ */
+bool check_dir(const std::string& path, bool readable, bool writeable);
+
+/**
+ * See g_canonicalize_filename
+ *
+ * @param filename
+ * @param relative_to
+ *
+ * @return
+ */
+std::string canonicalize_filename(const std::string& path, const std::string& relative_to);
+
+/*
+ * for OSs with out support for direntry->d_type, like Solaris
+ */
+#ifndef DT_UNKNOWN
+enum {
+ DT_UNKNOWN = 0,
+#define DT_UNKNOWN DT_UNKNOWN
+ DT_FIFO = 1,
+#define DT_FIFO DT_FIFO
+ DT_CHR = 2,
+#define DT_CHR DT_CHR
+ DT_DIR = 4,
+#define DT_DIR DT_DIR
+ DT_BLK = 6,
+#define DT_BLK DT_BLK
+ DT_REG = 8,
+#define DT_REG DT_REG
+ DT_LNK = 10,
+#define DT_LNK DT_LNK
+ DT_SOCK = 12,
+#define DT_SOCK DT_SOCK
+ DT_WHT = 14
+#define DT_WHT DT_WHT
+};
+#endif /*DT_UNKNOWN*/
+
+ /**
+ * get the d_type (as in direntry->d_type) for the file at path, using either
+ * stat(3) or lstat(3)
+ *
+ * @param path full path
+ * @param use_lstat whether to use lstat (otherwise use stat)
+ *
+ * @return DT_REG, DT_DIR, DT_LNK, or DT_UNKNOWN (other values are not supported
+ * currently)
+ */
+uint8_t determine_dtype(const std::string& path, bool use_lstat);
+
+
+/**
+ * Well-known runtime paths
+ *
+ */
+enum struct RuntimePath {
+ XapianDb,
+ Cache,
+ LogFile,
+ Config,
+ Scripts,
+ Bookmarks
+};
+
+/**
+ * Get some well-known Path for internal use when don't have
+ * access to the command-line
+ *
+ * @param path the RuntimePath to find
+ * @param muhome path to muhome directory, or empty for the default.
+ *
+ * @return the path name
+ */
+std::string runtime_path(RuntimePath path, const std::string& muhome="");
+
+}
+#endif /* MU_UTILS_FILE_HH__ */
+
diff --git a/lib/utils/mu-utils.cc b/lib/utils/mu-utils.cc
index 356e5d8..151b221 100644
--- a/lib/utils/mu-utils.cc
+++ b/lib/utils/mu-utils.cc
@@ -45,7 +45,6 @@
#include "mu-utils.hh"
#include "mu-utils-format.hh"
-#include "mu-util.h"
#include "mu-error.hh"
#include "mu-option.hh"
@@ -572,23 +571,6 @@ Mu::from_lexnum(const std::string& str)
return val;
}
-
-std::string
-Mu::canonicalize_filename(const std::string& path, const std::string& relative_to)
-{
- auto str{to_string_opt_gchar(
- g_canonicalize_filename(
- path.c_str(),
- relative_to.empty() ? nullptr : relative_to.c_str())).value()};
-
- // remove trailing '/'... is this needed?
- if (str[str.length()-1] == G_DIR_SEPARATOR)
- str.erase(str.length() - 1);
-
- return str;
-}
-
-
bool
Mu::locale_workaround() try
{
@@ -627,35 +609,110 @@ Mu::timezone_available(const std::string& tz)
return have_tz;
}
-
std::string
-Mu::runtime_path(Mu::RuntimePath path, const std::string& muhome)
+Mu::summarize(const std::string& str, size_t max_lines)
{
- auto [mu_cache, mu_config] =
- std::invoke([&]()->std::pair<std::string, std::string> {
-
- static std::string mu{"/mu"};
- if (muhome.empty())
- return { g_get_user_cache_dir() + mu,
- g_get_user_config_dir() + mu };
- else
- return { muhome, muhome };
- });
+ size_t nl_seen;
+ unsigned i,j;
+ gboolean last_was_blank;
- switch (path) {
- case Mu::RuntimePath::Cache:
- return mu_cache;
- case Mu::RuntimePath::XapianDb:
- return mu_cache + "/xapian";
- case Mu::RuntimePath::LogFile:
- return mu_cache + "/mu.log";
- case Mu::RuntimePath::Bookmarks:
- return mu_config + "/bookmarks";
- case Mu::RuntimePath::Config:
- return mu_config;
- case Mu::RuntimePath::Scripts:
- return mu_config + "/scripts";
- default:
- throw std::logic_error("unknown path");
+ if (str.empty())
+ return {};
+
+ /* len for summary <= original len */
+ char *summary = g_new (gchar, str.length() + 1);
+
+ /* copy the string up to max_lines lines, replace CR/LF/tab with
+ * single space */
+ for (i = j = 0, nl_seen = 0, last_was_blank = TRUE;
+ nl_seen < max_lines && i < str.length(); ++i) {
+
+ if (str[i] == '\n' || str[i] == '\r' ||
+ str[i] == '\t' || str[i] == ' ' ) {
+
+ if (str[i] == '\n')
+ ++nl_seen;
+
+ /* no double-blanks or blank at end of str */
+ if (!last_was_blank && str[i+1] != '\0')
+ summary[j++] = ' ';
+
+ last_was_blank = TRUE;
+ } else {
+
+ summary[j++] = str[i];
+ last_was_blank = FALSE;
+ }
}
+
+ summary[j] = '\0';
+
+ return to_string_gchar(std::move(summary)/*consumes*/);
+}
+
+
+
+
+static bool
+locale_is_utf8 (void)
+{
+ const gchar *dummy;
+ static int is_utf8 = -1;
+ if (G_UNLIKELY(is_utf8 == -1))
+ is_utf8 = g_get_charset(&dummy) ? 1 : 0;
+
+ return !!is_utf8;
+}
+
+bool
+Mu::fputs_encoded (const std::string& str, FILE *stream)
+{
+ g_return_val_if_fail (stream, false);
+
+ /* g_get_charset return TRUE when the locale is UTF8 */
+ if (locale_is_utf8())
+ return ::fputs (str.c_str(), stream) == EOF ? false: true;
+
+ /* charset is _not_ utf8, so we need to convert it */
+ char *conv{};
+ if (g_utf8_validate (str.c_str(), -1, NULL))
+ conv = g_locale_from_utf8 (str.c_str(), -1, {}, {}, {});
+
+ /* conversion failed; this happens because is some cases GMime may gives
+ * us non-UTF-8 strings from e.g. wrongly encoded message-subjects; if
+ * so, we escape the string */
+ conv = conv ? conv : g_strescape (str.c_str(), "\n\t");
+ int rv = conv ? ::fputs (conv, stream) : EOF;
+ g_free (conv);
+
+ return (rv == EOF) ? false: true;
+}
+
+__attribute__((format(printf, 2, 0)))
+static bool
+print_args (FILE *stream, const char *frm, va_list args)
+{
+ gchar *str;
+ gboolean rv;
+
+ str = g_strdup_vprintf (frm, args);
+ rv = fputs_encoded (str, stream);
+ g_free (str);
+
+ return rv;
+}
+
+bool
+Mu::print_encoded (const char *frm, ...)
+{
+ va_list args;
+ gboolean rv;
+
+ g_return_val_if_fail (frm, false);
+
+ va_start (args, frm);
+ rv = print_args (stdout, frm, args);
+ va_end (args);
+
+ return rv;
}
diff --git a/lib/utils/mu-utils.hh b/lib/utils/mu-utils.hh
index 41c02fa..4f77b08 100644
--- a/lib/utils/mu-utils.hh
+++ b/lib/utils/mu-utils.hh
@@ -110,6 +110,27 @@ static inline std::string join(const std::vector<std::string>& svec, char sepa)
}
/**
+ * write a string (assumed to be in utf8-format) to a stream,
+ * converted to the current locale
+ *
+ * @param str a string
+ * @param stream a stream
+ *
+ * @return true if printing worked, false otherwise
+ */
+bool fputs_encoded (const std::string& str, FILE *stream);
+
+/**
+ * print a formatted string (assumed to be in utf8-format) to stdout,
+ * converted to the current locale
+ *
+ * @param a standard printf() format string, followed by a parameter list
+ *
+ * @return true if printing worked, false otherwise
+ */
+bool print_encoded (const char *frm, ...) G_GNUC_PRINTF(1,2);
+
+/**
* Parse a date string to the corresponding time_t
* *
* @param date the date expressed a YYYYMMDDHHMMSS or any n... of the first
@@ -162,30 +183,6 @@ bool locale_workaround();
*/
bool timezone_available(const std::string& tz);
-/**
- * Well-known runtime paths
- *
- */
-enum struct RuntimePath {
- XapianDb,
- Cache,
- LogFile,
- Config,
- Scripts,
- Bookmarks
-};
-
-/**
- * Get some well-known Path for internal use when don't have
- * access to the command-line
- *
- * @param path the RuntimePath to find
- * @param muhome path to muhome directory, or empty for the default.
- *
- * @return the path name
- */
-std::string runtime_path(RuntimePath path, const std::string& muhome="");
-
// https://stackoverflow.com/questions/19053351/how-do-i-use-a-custom-deleter-with-a-stdunique-ptr-member
template <auto fn>
@@ -247,16 +244,6 @@ private:
};
/**
- * See g_canonicalize_filename
- *
- * @param filename
- * @param relative_to
- *
- * @return
- */
-std::string canonicalize_filename(const std::string& path, const std::string& relative_to);
-
-/**
* Convert a size string to a size in bytes
*
* @param sizestr the size string
@@ -277,6 +264,17 @@ Option<int64_t> parse_size(const std::string& sizestr, bool first);
std::string size_to_string(int64_t size);
/**
+ * get a crude 'summary' of the string, ie. the first /n/ lines of the strings,
+ * with all newlines removed, replaced by single spaces
+ *
+ * @param str the source string
+ * @param max_lines the maximum number of lines to include in the summary
+ *
+ * @return a newly allocated string with the summary. use g_free to free it.
+ */
+std::string summarize(const std::string& str, size_t max_lines);
+
+/**
* Convert any ostreamable<< value to a string
*
* @param t the value
@@ -446,7 +444,6 @@ to_second(const P& p, typename P::value_type::first_type f)
return Nothing;
}
-
/**
* Convert string view in something printable with %.*s
*/
@@ -489,6 +486,15 @@ private:
const bool color_;
};
+#define MU_COLOR_RED "\x1b[31m"
+#define MU_COLOR_GREEN "\x1b[32m"
+#define MU_COLOR_YELLOW "\x1b[33m"
+#define MU_COLOR_BLUE "\x1b[34m"
+#define MU_COLOR_MAGENTA "\x1b[35m"
+#define MU_COLOR_CYAN "\x1b[36m"
+#define MU_COLOR_DEFAULT "\x1b[0m"
+
+
/// Allow using enum structs as bitflags
#define MU_TO_NUM(ET, ELM) std::underlying_type_t<ET>(ELM)
#define MU_TO_ENUM(ET, NUM) static_cast<ET>(NUM)
diff --git a/lib/utils/tests/meson.build b/lib/utils/tests/meson.build
index 335fcfa..83d4e49 100644
--- a/lib/utils/tests/meson.build
+++ b/lib/utils/tests/meson.build
@@ -18,18 +18,13 @@
################################################################################
# tests
#
-test('test-mu-util',
- executable('test-mu-util',
- 'test-mu-util.c',
- install: false,
- dependencies: [glib_dep,config_h_dep, lib_mu_utils_dep]))
test('test-option',
executable('test-option',
- 'test-option.cc',
- install: false,
- dependencies: [glib_dep, lib_mu_utils_dep]))
+ 'test-option.cc',
+ install: false,
+ dependencies: [glib_dep, lib_mu_utils_dep]))
test('test-mu-utils',
executable('test-mu-utils',
- 'test-utils.cc',
- install: false,
- dependencies: [glib_dep, lib_mu_utils_dep]))
+ 'test-utils.cc',
+ install: false,
+ dependencies: [glib_dep, lib_mu_utils_dep]))
diff --git a/lib/utils/tests/test-mu-util.c b/lib/utils/tests/test-mu-util.c
deleted file mode 100644
index e453ea5..0000000
--- a/lib/utils/tests/test-mu-util.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
-** Copyright (C) 2008-2013 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
-**
-** 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 3, 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.
-**
-*/
-
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif /*HAVE_CONFIG_H*/
-
-#include <glib.h>
-#include <glib/gstdio.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include "mu-util.h"
-
-static void
-test_mu_util_dir_expand_00(void)
-{
-#ifdef HAVE_WORDEXP_H
- gchar *got, *expected;
-
- got = mu_util_dir_expand("~/IProbablyDoNotExist");
- expected = g_strdup_printf("%s%cIProbablyDoNotExist",
- getenv("HOME"), G_DIR_SEPARATOR);
-
- g_assert_cmpstr(got, ==, expected);
-
- g_free(got);
- g_free(expected);
-#endif /*HAVE_WORDEXP_H*/
-}
-
-static void
-test_mu_util_dir_expand_01(void)
-{
- /* XXXX: the testcase does not work when using some dir
- * setups; (see issue #585), although the code should still
- * work. Turn of the test for now */
- return;
-
-#ifdef HAVE_WORDEXP_H
- {
- gchar *got, *expected;
-
- got = mu_util_dir_expand("~/Desktop");
- expected = g_strdup_printf("%s%cDesktop",
- getenv("HOME"), G_DIR_SEPARATOR);
-
- g_assert_cmpstr(got, ==, expected);
-
- g_free(got);
- g_free(expected);
- }
-#endif /*HAVE_WORDEXP_H*/
-}
-
-static void
-test_mu_util_guess_maildir_01(void)
-{
- char* got;
- const char* expected;
-
- /* skip the test if there's no /tmp */
- if (access("/tmp", F_OK))
- return;
-
- g_setenv("MAILDIR", "/tmp", TRUE);
-
- got = mu_util_guess_maildir();
- expected = "/tmp";
-
- g_assert_cmpstr(got, ==, expected);
- g_free(got);
-}
-
-static void
-test_mu_util_guess_maildir_02(void)
-{
- char *got, *mdir;
-
- g_unsetenv("MAILDIR");
-
- mdir = g_strdup_printf("%s%cMaildir",
- getenv("HOME"), G_DIR_SEPARATOR);
- got = mu_util_guess_maildir();
-
- if (access(mdir, F_OK) == 0)
- g_assert_cmpstr(got, ==, mdir);
- else
- g_assert_cmpstr(got, ==, NULL);
-
- g_free(got);
- g_free(mdir);
-}
-
-static void
-test_mu_util_check_dir_01(void)
-{
- if (g_access("/usr/bin", F_OK) == 0) {
- g_assert_cmpuint(
- mu_util_check_dir("/usr/bin", TRUE, FALSE) == TRUE,
- ==,
- g_access("/usr/bin", R_OK) == 0);
- }
-}
-
-static void
-test_mu_util_check_dir_02(void)
-{
- if (g_access("/tmp", F_OK) == 0) {
- g_assert_cmpuint(
- mu_util_check_dir("/tmp", FALSE, TRUE) == TRUE,
- ==,
- g_access("/tmp", W_OK) == 0);
- }
-}
-
-static void
-test_mu_util_check_dir_03(void)
-{
- if (g_access(".", F_OK) == 0) {
- g_assert_cmpuint(
- mu_util_check_dir(".", TRUE, TRUE) == TRUE,
- ==,
- g_access(".", W_OK | R_OK) == 0);
- }
-}
-
-static void
-test_mu_util_check_dir_04(void)
-{
- /* not a dir, so it must be false */
- g_assert_cmpuint(
- mu_util_check_dir("test-util.c", TRUE, TRUE),
- ==,
- FALSE);
-}
-
-static void
-test_mu_util_get_dtype_with_lstat(void)
-{
- g_assert_cmpuint(
- mu_util_get_dtype(MU_TESTMAILDIR, TRUE), ==, DT_DIR);
- g_assert_cmpuint(
- mu_util_get_dtype(MU_TESTMAILDIR2, TRUE), ==, DT_DIR);
- g_assert_cmpuint(
- mu_util_get_dtype(MU_TESTMAILDIR2 "/Foo/cur/mail5", TRUE),
- ==, DT_REG);
-}
-
-static void
-test_mu_util_supports(void)
-{
- gboolean has_guile;
- gchar* path;
-
-#ifdef BUILD_GUILE
- has_guile = TRUE;
-#else
- has_guile = FALSE;
-#endif /*BUILD_GUILE*/
-
- g_assert_cmpuint(mu_util_supports(MU_FEATURE_GUILE), ==, has_guile);
-
- path = g_find_program_in_path("gnuplot");
- g_free(path);
-
- g_assert_cmpuint(mu_util_supports(MU_FEATURE_GNUPLOT), ==,
- path ? TRUE : FALSE);
-
- g_assert_cmpuint(
- mu_util_supports(MU_FEATURE_GNUPLOT | MU_FEATURE_GUILE),
- ==,
- has_guile && path ? TRUE : FALSE);
-}
-
-static void
-test_mu_util_program_in_path(void)
-{
- g_assert_cmpuint(mu_util_program_in_path("ls"), ==, TRUE);
-}
-
-
-static void
-test_mu_util_summarize(void)
-{
- const char *txt =
- "Khiron was fortified and made the seat of a pargana during "
- "the reign of Asaf-ud-Daula.\n\the headquarters had previously "
- "been at Satanpur since its foundation and fortification by "
- "the Bais raja Sathna.\n\nKhiron was also historically the seat "
- "of a taluqdari estate belonging to a Janwar dynasty.\n"
- "There were also several Kayasth qanungo families, "
- "including many descended from Rai Sahib Rai, who had been "
- "a chakladar under the Nawabs of Awadh.";
-
- char *summ = mu_str_summarize(txt, 3);
- g_assert_cmpstr(summ, ==,
- "Khiron was fortified and made the seat of a pargana "
- "during the reign of Asaf-ud-Daula. he headquarters had "
- "previously been at Satanpur since its foundation and "
- "fortification by the Bais raja Sathna. ");
- g_free (summ);
-}
-
-
-static void
-test_mu_error(void)
-{
- GQuark q;
- GError *err;
- gboolean res;
-
- q = mu_util_error_quark();
- g_assert_true(q != 0);
-
-
- err = NULL;
- res = mu_util_g_set_error(&err, MU_ERROR_IN_PARAMETERS,
- "Hello, %s!", "World");
-
- g_assert_false(res);
- g_assert_cmpuint(err->domain, ==, q);
- g_assert_cmpuint(err->code, ==, MU_ERROR_IN_PARAMETERS);
- g_assert_cmpstr(err->message,==,"Hello, World!");
-
- g_clear_error(&err);
-}
-
-
-int
-main(int argc, char* argv[])
-{
- g_test_init(&argc, &argv, NULL);
-
- /* mu_util_dir_expand */
- g_test_add_func("/mu-util/mu-util-dir-expand-00",
- test_mu_util_dir_expand_00);
- g_test_add_func("/mu-util/mu-util-dir-expand-01",
- test_mu_util_dir_expand_01);
-
- /* mu_util_guess_maildir */
- g_test_add_func("/mu-util/mu-util-guess-maildir-01",
- test_mu_util_guess_maildir_01);
- g_test_add_func("/mu-util/mu-util-guess-maildir-02",
- test_mu_util_guess_maildir_02);
-
- /* mu_util_check_dir */
- g_test_add_func("/mu-util/mu-util-check-dir-01",
- test_mu_util_check_dir_01);
- g_test_add_func("/mu-util/mu-util-check-dir-02",
- test_mu_util_check_dir_02);
- g_test_add_func("/mu-util/mu-util-check-dir-03",
- test_mu_util_check_dir_03);
- g_test_add_func("/mu-util/mu-util-check-dir-04",
- test_mu_util_check_dir_04);
-
- g_test_add_func("/mu-util/mu-util-get-dtype-with-lstat",
- test_mu_util_get_dtype_with_lstat);
-
- g_test_add_func("/mu-util/mu-util-supports", test_mu_util_supports);
- g_test_add_func("/mu-util/mu-util-program-in-path",
- test_mu_util_program_in_path);
-
- g_test_add_func("/mu-util/summarize", test_mu_util_summarize);
- g_test_add_func("/mu-util/error", test_mu_error);
-
- return g_test_run();
-}
diff --git a/lib/utils/tests/test-utils.cc b/lib/utils/tests/test-utils.cc
index a135a9a..56b3d4d 100644
--- a/lib/utils/tests/test-utils.cc
+++ b/lib/utils/tests/test-utils.cc
@@ -282,19 +282,6 @@ test_locale_workaround()
g_assert_true(locale_workaround());
}
-static void
-test_error()
-{
- GError *err;
- err = g_error_new(MU_ERROR_DOMAIN, 77, "Hello, %s", "world");
- Error ex{Error::Code::Crypto, &err, "boo"};
- g_assert_cmpstr(ex.what(), ==, "boo: Hello, world");
-
- ex.fill_g_error(&err);
- g_assert_cmpuint(err->code, ==, static_cast<unsigned>(Error::Code::Crypto));
- g_clear_error(&err);
-}
-
enum struct TestEnum { A, B, C };
constexpr AssocPairs<TestEnum, std::string_view, 3>
test_epairs = {{
@@ -323,6 +310,31 @@ test_enum_pairs(void)
g_assert_true(to_type("c").value() == TestEnum::C);
}
+
+
+static void
+test_summarize(void)
+{
+ const char *txt =
+ "Khiron was fortified and made the seat of a pargana during "
+ "the reign of Asaf-ud-Daula.\n\the headquarters had previously "
+ "been at Satanpur since its foundation and fortification by "
+ "the Bais raja Sathna.\n\nKhiron was also historically the seat "
+ "of a taluqdari estate belonging to a Janwar dynasty.\n"
+ "There were also several Kayasth qanungo families, "
+ "including many descended from Rai Sahib Rai, who had been "
+ "a chakladar under the Nawabs of Awadh.";
+
+ const auto summ = summarize(txt, 3);
+ g_assert_cmpstr(summ.c_str(), ==,
+ "Khiron was fortified and made the seat of a pargana "
+ "during the reign of Asaf-ud-Daula. he headquarters had "
+ "previously been at Satanpur since its foundation and "
+ "fortification by the Bais raja Sathna. ");
+}
+
+
+
int
main(int argc, char* argv[])
{
@@ -335,12 +347,12 @@ main(int argc, char* argv[])
g_test_add_func("/utils/remove-ctrl", test_remove_ctrl);
g_test_add_func("/utils/clean", test_clean);
g_test_add_func("/utils/format", test_format);
+ g_test_add_func("/utils/summarize", test_summarize);
g_test_add_func("/utils/split", test_split);
g_test_add_func("/utils/join", test_join);
g_test_add_func("/utils/define-bitmap", test_define_bitmap);
g_test_add_func("/utils/to-from-lexnum", test_to_from_lexnum);
g_test_add_func("/utils/locale-workaround", test_locale_workaround);
- g_test_add_func("/utils/error", test_error);
g_test_add_func("/utils/enum-pairs", test_enum_pairs);
return g_test_run();
diff --git a/mu/mu-cmd-cfind.cc b/mu/mu-cmd-cfind.cc
index aa8dead..d75fc5a 100644
--- a/mu/mu-cmd-cfind.cc
+++ b/mu/mu-cmd-cfind.cc
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
+** Copyright (C) 2022-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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
@@ -27,7 +27,6 @@
#include <utils/mu-utils.hh>
#include <utils/mu-regex.hh>
-#include <utils/mu-util.h>
#include <utils/mu-option.hh>
using namespace Mu;
@@ -113,14 +112,14 @@ output_plain(ItemType itype, OptContact contact, const Options& opts)
const auto col2{opts.nocolor ? "" : MU_COLOR_GREEN};
const auto coldef{opts.nocolor ? "" : MU_COLOR_DEFAULT};
- mu_util_print_encoded("%s%s%s%s%s%s%s\n",
- col1,
- contact->name.c_str(),
- coldef,
- contact->name.empty() ? "" : " ",
- col2,
- contact->email.c_str(),
- coldef);
+ print_encoded("%s%s%s%s%s%s%s\n",
+ col1,
+ contact->name.c_str(),
+ coldef,
+ contact->name.empty() ? "" : " ",
+ col2,
+ contact->email.c_str(),
+ coldef);
}
static void
@@ -130,8 +129,8 @@ output_mutt_alias(ItemType itype, OptContact contact, const Options& opts)
return;
const auto nick{guess_nick(*contact)};
- mu_util_print_encoded("alias %s %s <%s>\n", nick.c_str(),
- contact->name.c_str(), contact->email.c_str());
+ print_encoded("alias %s %s <%s>\n", nick.c_str(),
+ contact->name.c_str(), contact->email.c_str());
}
static void
@@ -143,9 +142,9 @@ output_mutt_address_book(ItemType itype, OptContact contact, const Options& opts
if (!contact)
return;
- mu_util_print_encoded("%s\t%s\t\n",
- contact->email.c_str(),
- contact->name.c_str());
+ print_encoded("%s\t%s\t\n",
+ contact->email.c_str(),
+ contact->name.c_str());
}
static void
@@ -156,10 +155,10 @@ output_wanderlust(ItemType itype, OptContact contact, const Options& opts)
auto nick=guess_nick(*contact);
- mu_util_print_encoded("%s \"%s\" \"%s\"\n",
- contact->email.c_str(),
- nick.c_str(),
- contact->name.c_str());
+ print_encoded("%s \"%s\" \"%s\"\n",
+ contact->email.c_str(),
+ nick.c_str(),
+ contact->name.c_str());
}
static void
@@ -168,9 +167,9 @@ output_org_contact(ItemType itype, OptContact contact, const Options& opts)
if (!contact || contact->name.empty())
return;
- mu_util_print_encoded("* %s\n:PROPERTIES:\n:EMAIL: %s\n:END:\n\n",
- contact->name.c_str(),
- contact->email.c_str());
+ print_encoded("* %s\n:PROPERTIES:\n:EMAIL: %s\n:END:\n\n",
+ contact->name.c_str(),
+ contact->email.c_str());
}
static void
@@ -201,9 +200,9 @@ output_csv(ItemType itype, OptContact contact, const Options& opts)
if (!contact)
return;
- mu_util_print_encoded("%s,%s\n",
- contact->name.empty() ? "" : Mu::quote(contact->name).c_str(),
- Mu::quote(contact->email).c_str());
+ print_encoded("%s,%s\n",
+ contact->name.empty() ? "" : Mu::quote(contact->name).c_str(),
+ Mu::quote(contact->email).c_str());
}
static void
@@ -216,7 +215,7 @@ output_json(ItemType itype, OptContact contact, const Options& opts)
g_print (" {\n");
const std::string name = contact->name.empty() ? "null" : Mu::quote(contact->name);
- mu_util_print_encoded(
+ print_encoded(
" \"email\" : \"%s\",\n"
" \"name\" : %s,\n"
" \"display\" : %s,\n"
diff --git a/mu/mu-cmd-extract.cc b/mu/mu-cmd-extract.cc
index 1318f60..80d4719 100644
--- a/mu/mu-cmd-extract.cc
+++ b/mu/mu-cmd-extract.cc
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 2010-2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
+** Copyright (C) 2010-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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
@@ -19,8 +19,8 @@
#include "config.h"
#include "mu-cmd.hh"
-#include "utils/mu-util.h"
#include "utils/mu-utils.hh"
+#include "utils/mu-utils-file.hh"
#include "utils/mu-regex.hh"
#include <message/mu-message.hh>
@@ -38,16 +38,10 @@ save_part(const Message::Part& part, size_t idx, const Options& opts)
if (auto&& res{part.to_file(path, opts.extract.overwrite)}; !res)
return Err(res.error());
-
- if (opts.extract.play) {
- GError *err{};
- if (auto res{mu_util_play(path.c_str(), &err)};
- res != MU_OK)
- return Err(Error::Code::Play, &err, "playing '%s' failed",
- path.c_str());
- }
-
- return Ok();
+ else if (opts.extract.play)
+ return play(path);
+ else
+ return Ok();
}
static Result<void>
@@ -113,19 +107,18 @@ show_part(const MessagePart& part, size_t index, bool color)
/* filename */
color_maybe(MU_COLOR_GREEN);
const auto fname{part.raw_filename()};
- mu_util_fputs_encoded(fname ? fname->c_str() : "<none>", stdout);
-
- mu_util_fputs_encoded(" ", stdout);
+ fputs_encoded(fname.value_or("<none>"), stdout);
+ fputs_encoded(" ", stdout);
/* content-type */
color_maybe(MU_COLOR_BLUE);
const auto ctype{part.mime_type()};
- mu_util_fputs_encoded(ctype ? ctype->c_str() : "<none>", stdout);
+ fputs_encoded(ctype.value_or("<none>"), stdout);
/* /\* disposition *\/ */
color_maybe(MU_COLOR_MAGENTA);
- mu_util_print_encoded(" [%s]", part.is_attachment() ?
- "attachment" : "inline");
+ print_encoded(" [%s]", part.is_attachment() ?
+ "attachment" : "inline");
/* size */
if (part.size() > 0) {
color_maybe(MU_COLOR_CYAN);
@@ -159,7 +152,7 @@ Mu::mu_cmd_extract(const Options& opts)
opts.extract.filename_rx.empty())
return show_parts(opts.extract.message, opts); /* show, don't save */
- if (!mu_util_check_dir(opts.extract.targetdir.c_str(), FALSE, TRUE))
+ if (!check_dir(opts.extract.targetdir, false/*!readable*/, true/*writeable*/))
return Err(Error::Code::File,
"target '%s' is not a writable directory",
opts.extract.targetdir.c_str());
diff --git a/mu/mu-cmd-find.cc b/mu/mu-cmd-find.cc
index 1534ec1..cbab137 100644
--- a/mu/mu-cmd-find.cc
+++ b/mu/mu-cmd-find.cc
@@ -36,7 +36,6 @@
#include "message/mu-message.hh"
#include "utils/mu-option.hh"
-#include "utils/mu-util.h"
#include "mu-cmd.hh"
#include "utils/mu-utils.hh"
@@ -258,12 +257,10 @@ print_summary(const Message& msg, const Options& opts)
if (!body)
return;
- const auto summ{to_string_opt_gchar(
- mu_str_summarize(body->c_str(),
- opts.find.summary_len.value_or(0)))};
+ const auto summ{summarize(body->c_str(), opts.find.summary_len.value_or(0))};
g_print("Summary: ");
- mu_util_fputs_encoded(summ ? summ->c_str() : "<none>", stdout);
+ fputs_encoded(summ, stdout);
g_print("\n");
}
@@ -311,8 +308,8 @@ output_plain_fields(const Message& msg, const std::string& fields,
else {
ansi_color_maybe(field_opt->id, color);
- nonempty += mu_util_fputs_encoded(
- display_field(msg, field_opt->id).c_str(), stdout);
+ nonempty += fputs_encoded(
+ display_field(msg, field_opt->id), stdout);
ansi_reset_maybe(field_opt->id, color);
}
}
diff --git a/mu/mu-cmd-index.cc b/mu/mu-cmd-index.cc
index 269dc72..93954ee 100644
--- a/mu/mu-cmd-index.cc
+++ b/mu/mu-cmd-index.cc
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 2008-2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
+** Copyright (C) 2008-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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
@@ -33,8 +33,6 @@
#include "index/mu-indexer.hh"
#include "mu-store.hh"
-#include "utils/mu-util.h"
-
using namespace Mu;
static std::atomic<bool> caught_signal;
diff --git a/mu/mu-cmd.cc b/mu/mu-cmd.cc
index 304bfca..5042239 100644
--- a/mu/mu-cmd.cc
+++ b/mu/mu-cmd.cc
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 2010-2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
+** Copyright (C) 2010-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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
@@ -35,8 +35,6 @@
#include "message/mu-message.hh"
#include "message/mu-mime-object.hh"
-#include "utils/mu-util.h"
-
#include "utils/mu-error.hh"
#include "utils/mu-utils.hh"
#include "message/mu-message.hh"
@@ -86,12 +84,12 @@ print_field(const std::string& field, const std::string& val, bool color)
return;
color_maybe(MU_COLOR_MAGENTA);
- mu_util_fputs_encoded(field.c_str(), stdout);
+ fputs_encoded(field, stdout);
color_maybe(MU_COLOR_DEFAULT);
fputs(": ", stdout);
color_maybe(MU_COLOR_GREEN);
- mu_util_fputs_encoded(val.c_str(), stdout);
+ fputs_encoded(val, stdout);
color_maybe(MU_COLOR_DEFAULT);
fputs("\n", stdout);
@@ -120,12 +118,10 @@ body_or_summary(const Message& message, const Options& opts)
}
if (opts.view.summary_len) {
- gchar* summ;
- summ = mu_str_summarize(body->c_str(), *opts.view.summary_len);
+ const auto summ{summarize(body->c_str(), *opts.view.summary_len)};
print_field("Summary", summ, color);
- g_free(summ);
} else {
- mu_util_print_encoded("%s", body->c_str());
+ print_encoded("%s", body->c_str());
if (!g_str_has_suffix(body->c_str(), "\n"))
g_print("\n");
}
diff --git a/mu/mu-options.hh b/mu/mu-options.hh
index fc0eb69..04eff1f 100644
--- a/mu/mu-options.hh
+++ b/mu/mu-options.hh
@@ -1,5 +1,5 @@
/*
-** Copyright (C) 2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
+** Copyright (C) 2022-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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
@@ -26,6 +26,8 @@
#include <utils/mu-option.hh>
#include <utils/mu-result.hh>
#include <utils/mu-utils.hh>
+#include <utils/mu-utils-file.hh>
+
#include <message/mu-fields.hh>
#include <mu-script.hh>
#include <ctime>