From 366c1ea44f1d473deab6420ebcf0a53bba7fc797 Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Thu, 31 Dec 2009 19:27:41 +0200 Subject: [PATCH] * add symlink support, code refactoring --- src/mu-maildir.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++ src/mu-maildir.h | 56 +++++++++++++++ src/mu.c | 39 +++++++++- 3 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 src/mu-maildir.c create mode 100644 src/mu-maildir.h diff --git a/src/mu-maildir.c b/src/mu-maildir.c new file mode 100644 index 00000000..4b5205f7 --- /dev/null +++ b/src/mu-maildir.c @@ -0,0 +1,182 @@ +/* +** Copyright (C) 2009 Dirk-Jan C. Binnema +** +** 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 +#include +#include +#include + +#include +#include + +#include "mu-maildir.h" + +static gboolean +_create_maildir (const char *path, int mode, GError **err) +{ + int i; + const gchar* subdirs[] = {"new", "cur", "tmp"}; + + /* make sure it does not exist yet */ + if (access (path, F_OK) == 0) + errno = EEXIST; + if (errno != ENOENT) { + g_set_error (err, 0, 0, "%s", strerror (errno)); + return FALSE; + } + + for (i = 0; i != G_N_ELEMENTS(subdirs); ++i) { + + gchar *fullpath; + int rv; + + fullpath = g_strdup_printf ("%s%c%s", path, + G_DIR_SEPARATOR, + subdirs[i]); + rv = g_mkdir_with_parents (fullpath, mode); + g_free (fullpath); + + if (rv != 0) { + g_set_error (err, 0, 0, "%s", + strerror (errno)); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +_create_noindex (const char *path, GError **err) +{ + /* create a noindex file if requested */ + int fd; + gchar *noindexpath; + noindexpath = g_strdup_printf ("%s%c%s", path, + G_DIR_SEPARATOR, + ".noindex"); + fd = creat (noindexpath, 0644); + g_free (noindexpath); + if (fd < 0 || close (fd) != 0) { + g_set_error (err, 0, 0, "%s", strerror (errno)); + return FALSE; + } + + return TRUE; +} + + +gboolean +mu_maildir_mkmdir (const char* path, int mode, + gboolean noindex, GError **err) +{ + + g_return_val_if_fail (path, FALSE); + + if (!_create_maildir (path, mode, err)) + return FALSE; + + if (noindex && !_create_noindex (path, err)) + return FALSE; + + return TRUE; +} + +/* determine whether the source message is in 'new' or in 'cur'; + * we ignore messages in 'tmp' for obvious reasons */ +static gboolean +_check_subdir (const char *src, gboolean *in_cur, GError **err) +{ + gchar *srcpath; + + srcpath = g_path_get_dirname (src); + + if (g_str_has_suffix (srcpath, "new")) + *in_cur = FALSE; + else if (g_str_has_suffix (srcpath, "cur")) + *in_cur = TRUE; + else { + g_set_error (err, 0, 0, "%s", + "Invalid source message"); + return FALSE; + } + g_free (srcpath); + + return TRUE; +} + +static gchar* +_get_target_fullpath (const char* src, const gchar *targetpath, + GError **err) +{ + gchar *targetfullpath; + gchar *srcfile; + gboolean in_cur; + + if (!_check_subdir (src, &in_cur, err)) + return NULL; + + srcfile = g_path_get_basename (src); + + /* create & test targetpath */ + targetfullpath = g_strdup_printf ("%s%c%s%c%s", + targetpath, + G_DIR_SEPARATOR, + in_cur ? "cur" : "new", + G_DIR_SEPARATOR, + srcfile); + g_free (srcfile); + + return targetfullpath; +} + + + +gboolean +mu_maildir_link (const char* src, const char *targetpath, + GError **err) +{ + gchar *targetfullpath; + int rv; + + g_return_val_if_fail (src, FALSE); + g_return_val_if_fail (targetpath, FALSE); + + /* just a basic check */ + if (access (src, R_OK) != 0) { + g_set_error (err, 0, 0, "Cannot read source message: %s", + strerror (errno)); + return FALSE; + } + + targetfullpath = _get_target_fullpath (src, targetpath, err); + if (!targetfullpath) + return FALSE; + + rv = symlink (src, targetfullpath); + g_free (targetfullpath); + if (rv != 0) { + g_set_error (err, 0, 0, "Error creating link: %s", + strerror (errno)); + return FALSE; + } + + return TRUE; +} + diff --git a/src/mu-maildir.h b/src/mu-maildir.h new file mode 100644 index 00000000..ee38fa01 --- /dev/null +++ b/src/mu-maildir.h @@ -0,0 +1,56 @@ +/* +** Copyright (C) 2009 Dirk-Jan C. Binnema +** +** 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_MAILDIR_H__ +#define __MU_MAILDIR_H__ + +#include + +/** + * create a new maildir. Note, if the function fails 'halfway', it + * will *not* try to remove the parts the were created. + * + * @param path the path (missing components will be created, as in 'mkdir -p') + * @param mode the file mode (e.g., 0755) + * @param noindex add a .noindex file to the maildir, so it will be excluded + * from indexing by 'mu index' + * @param err a GError* to receive error info, or NULL + * + * @return TRUE if creation succeeded, FALSE otherwise + */ +gboolean mu_maildir_mkmdir (const char* path, int mode, + gboolean noindex, GError **err); + + +/** + * create a symbolic link to a mail message; the function will + * automatically + * + * @param src the full path to the source message + * @param targetpath the path to the target maildir; ie., *not* + * MyMaildir/cur, but just MyMaildir/. The function will figure out + * the correct subdir then. * + * @param err a GError* to receive error info, or NULL + * + * @return + */ +gboolean mu_maildir_link (const char* src, const char *targetpath, + GError **err); + +#endif /*__MU_MAILDIR_H__*/ diff --git a/src/mu.c b/src/mu.c index 172fe6d6..cbb3296b 100644 --- a/src/mu.c +++ b/src/mu.c @@ -38,6 +38,7 @@ enum _MuCmd { MU_CMD_INDEX, MU_CMD_QUERY, MU_CMD_MKDIR, + MU_CMD_LINK, MU_CMD_HELP, MU_CMD_UNKNOWN }; @@ -62,6 +63,9 @@ parse_cmd (const char* cmd) if ((strcmp (cmd, "mkmdir") == 0) || (strcmp (cmd, "mkdir") == 0)) return MU_CMD_MKDIR; + + if (strcmp (cmd, "link") == 0) + return MU_CMD_LINK; if ((strcmp (cmd, "help") == 0) || (strcmp (cmd, "info") == 0)) @@ -112,7 +116,8 @@ make_maildir (MuConfigOptions *opts) i = 1; while (opts->params[i]) { GError *err = NULL; - if (!mu_maildir_mkmdir (opts->params[i], 0755, &err)) { + if (!mu_maildir_mkmdir (opts->params[i], 0755, FALSE, + &err)) { g_printerr ("error creating %s: %s\n", opts->params[i], err->message); g_error_free (err); @@ -123,7 +128,34 @@ make_maildir (MuConfigOptions *opts) return 0; } + + + +static int +make_symlink (MuConfigOptions *opts) +{ + GError *err; + if (!opts->params[0]) + return 1; /* shouldn't happen */ + + if (!opts->params[1] || !opts->params[2]) { + g_printerr ("usage: mu link \n"); + return 1; + } + + err = NULL; + if (!mu_maildir_link (opts->params[1], opts->params[2], &err)) { + if (err) { + g_printerr ("error: %s\n", err->message); + g_error_free (err); + } + return 1; + } + + return 0; +} + @@ -165,7 +197,7 @@ show_help (MuConfigOptions *opts) { /* FIXME: get context-sensitive help */ show_version (); - show_usage (FALSE); + return show_usage (FALSE); } @@ -240,6 +272,9 @@ main (int argc, char *argv[]) if (cmd == MU_CMD_MKDIR) return make_maildir (&config); + if (cmd == MU_CMD_LINK) + return make_symlink (&config); + if (!init_log (&config)) return 1;