unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* [RFC/PATCH] notmuch link
@ 2011-10-01  8:45 Ali Polatel
  2011-10-01  8:45 ` [RFC/PATCH] link: Add new command Ali Polatel
  2011-10-03 21:15 ` [RFC/PATCH] notmuch link Ali Polatel
  0 siblings, 2 replies; 4+ messages in thread
From: Ali Polatel @ 2011-10-01  8:45 UTC (permalink / raw)
  To: Notmuch Mailing List; +Cc: Ali Polatel

From: Ali Polatel <alip@exherbo.org>

Hello,

I have been working on a new notmuch command namely 'link'. This command
aims to help integrating notmuch with different mail agents. Basically
it (sym)links messages matching the given search terms to the specified
target maildir. You may use this maildir as a so-called "virtual"
folder. After applying the patch call "notmuch help link" for basic
help.

The patch is also available on links branch under my notmuch repository:
https://github.com/alip/notmuch

Beware this is pretty experimental, I have been using it for a couple of
days fixing the issues along the way. I will be sharing my workflow
using this command with mutt after I'm done polishing my scripts.

This mail is merely a request for comments and testing.

Ali Polatel (1):
  link: Add new command

 Makefile.local   |    2 +
 maildir.c        |  262 +++++++++++++++++++++++++++++++++++++++++
 maildir.h        |   53 +++++++++
 notmuch-client.h |    4 +
 notmuch-link.c   |  339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 notmuch.c        |   44 +++++++
 6 files changed, 704 insertions(+), 0 deletions(-)
 create mode 100644 maildir.c
 create mode 100644 maildir.h
 create mode 100644 notmuch-link.c

-- 
1.7.6.1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [RFC/PATCH] link: Add new command
  2011-10-01  8:45 [RFC/PATCH] notmuch link Ali Polatel
@ 2011-10-01  8:45 ` Ali Polatel
  2011-10-03 21:15 ` [RFC/PATCH] notmuch link Ali Polatel
  1 sibling, 0 replies; 4+ messages in thread
From: Ali Polatel @ 2011-10-01  8:45 UTC (permalink / raw)
  To: Notmuch Mailing List; +Cc: Ali Polatel

From: Ali Polatel <alip@exherbo.org>

'link' is a new command to create links to specified target maildirs.
This is especially useful for integration with other mail agents.
---
 Makefile.local   |    2 +
 maildir.c        |  262 +++++++++++++++++++++++++++++++++++++++++
 maildir.h        |   53 +++++++++
 notmuch-client.h |    4 +
 notmuch-link.c   |  339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 notmuch.c        |   44 +++++++
 6 files changed, 704 insertions(+), 0 deletions(-)
 create mode 100644 maildir.c
 create mode 100644 maildir.h
 create mode 100644 notmuch-link.c

diff --git a/Makefile.local b/Makefile.local
index 38f6c17..a613a4b 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -278,6 +278,7 @@ notmuch_client_srcs =		\
 	notmuch-config.c	\
 	notmuch-count.c		\
 	notmuch-dump.c		\
+	notmuch-link.c		\
 	notmuch-new.c		\
 	notmuch-reply.c		\
 	notmuch-restore.c	\
@@ -289,6 +290,7 @@ notmuch_client_srcs =		\
 	query-string.c		\
 	show-message.c		\
 	json.c			\
+	maildir.c		\
 	xutil.c
 
 notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
diff --git a/maildir.c b/maildir.c
new file mode 100644
index 0000000..b8c48b3
--- /dev/null
+++ b/maildir.c
@@ -0,0 +1,262 @@
+/* Maildir utilities for the notmuch mail library
+ *
+ * Copyright © 2011 Ali Polatel
+ * Based in part upon mu which is:
+ *   Copyright © 2008-2011 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, see http://www.gnu.org/licenses/ .
+ *
+ * Author: Ali Polatel <polatel@gmail.com>
+ */
+
+#include "maildir.h"
+
+static const char *const maildir_subdirs_array[] = {"new", "cur", "tmp"};
+
+/* FIXME: The two functions below, dirent_sort_inode and get_dtype duplicate
+ * code from notmuch-new.c
+ */
+static int
+dirent_sort_inode (const struct dirent **a, const struct dirent **b)
+{
+    return ((*a)->d_ino < (*b)->d_ino) ? -1 : 1;
+}
+
+static unsigned char
+get_dtype(const char *fullpath, struct dirent *entry)
+{
+    struct stat buf;
+
+    if (entry->d_type != DT_UNKNOWN)
+	return entry->d_type;
+
+    if (lstat(fullpath, &buf) == -1) {
+	fprintf (stderr, "Warning: stat failed on `%s': %s\n",
+		 fullpath, strerror(errno));
+	return DT_UNKNOWN;
+    }
+
+    if (S_ISREG (buf.st_mode)) {
+	return DT_REG;
+    } else if (S_ISDIR (buf.st_mode)) {
+	return DT_DIR;
+    } else if (S_ISLNK (buf.st_mode)) {
+	return DT_LNK;
+    }
+
+    return DT_UNKNOWN;
+}
+
+static notmuch_bool_t
+maildir_access (const char *path)
+{
+    struct stat buf;
+
+    if (access (path, R_OK | W_OK | X_OK) == -1) {
+	fprintf (stderr, "Failed to access path `%s': %s\n",
+		 path, strerror(errno));
+	return FALSE;
+    }
+
+    if (lstat(path, &buf) == -1) {
+	fprintf (stderr, "Failed to access path `%s': %s\n",
+		 path, strerror(errno));
+	return FALSE;
+    }
+
+    if (!S_ISDIR(buf.st_mode)) {
+	fprintf (stderr, "Path `%s' is not a directory\n", path);
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
+/* Determine whether the source message is in 'new' or in 'cur';
+ * we ignore messages in 'tmp' for obvious reasons
+ */
+static notmuch_bool_t
+maildir_subdir (const char *src, notmuch_bool_t *in_cur)
+{
+    char *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_free (srcpath);
+	errno = EINVAL;
+	return FALSE;
+    }
+
+    g_free(srcpath);
+    return TRUE;
+}
+
+static char *
+maildir_transform_path (const char *src, const char *targetpath)
+{
+    char *targetfullpath, *srcfile;
+    notmuch_bool_t in_cur;
+
+    if (!maildir_subdir (src, &in_cur)) {
+	fprintf (stderr, "Invalid maildir subdirectory `%s': %s\n",
+		 src, strerror(errno));
+	return NULL;
+    }
+
+    srcfile = g_path_get_basename (src);
+    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;
+}
+
+notmuch_bool_t
+maildir_check (const char *path, notmuch_bool_t makedir, mode_t mode)
+{
+    int i;
+    char *fullpath = NULL;
+
+    for (i = 0; i != G_N_ELEMENTS (maildir_subdirs_array); i++) {
+	    fullpath = g_build_filename (path, maildir_subdirs_array[i], NULL);
+	    if (!makedir && !maildir_access(fullpath))
+		goto FAIL;
+	    if (makedir && g_mkdir_with_parents (fullpath, (int)mode) != 0) {
+		fprintf (stderr, "Error creating %s: %s\n",
+			 fullpath, strerror(errno));
+		goto FAIL;
+	    }
+	    g_free (fullpath);
+    }
+
+    return TRUE;
+
+  FAIL:
+    g_free (fullpath);
+    return FALSE;
+}
+
+notmuch_bool_t
+maildir_rename (const char *src, const char *targetpath, rename_method_t methr)
+{
+    int ret;
+    char *targetfullpath;
+
+    targetfullpath = maildir_transform_path (src, targetpath);
+    if (!targetfullpath)
+	return FALSE;
+
+    switch (methr) {
+    case RENAME_SYMLINK:
+	ret = symlink (src, targetfullpath);
+	break;
+    case RENAME_HARDLINK:
+	ret = link (src, targetfullpath);
+	break;
+    default:
+	return FALSE;
+    }
+
+    if (ret == -1) {
+	if (errno != EEXIST) {
+	    fprintf (stderr, "Failed to link %s to %s: %s\n",
+		     src, targetfullpath, strerror(errno));
+	}
+	g_free (targetfullpath);
+	return FALSE;
+    }
+
+    g_free (targetfullpath);
+    return TRUE;
+}
+
+int
+maildir_clean_recursive (const char *path, clean_method_t methc)
+{
+    int i, count, ret, num_fs_entries;
+    notmuch_bool_t delete;
+    char *fullpath = NULL;
+    struct dirent *entry = NULL;
+    struct dirent **fs_entries = NULL;
+    struct stat buf;
+
+    if (methc == CLEAN_NONE)
+	return 0;
+
+    num_fs_entries = scandir(path, &fs_entries, NULL, dirent_sort_inode);
+    if (num_fs_entries == -1) {
+	fprintf (stderr, "Error opening directory %s: %s\n",
+		 path, strerror(errno));
+	return -1;
+    }
+
+    count = 0;
+    for (i = 0; i < num_fs_entries; i++) {
+	entry = fs_entries[i];
+
+	if (!entry->d_name ||
+	    strcmp (entry->d_name, ".") == 0 ||
+	    strcmp (entry->d_name, "..") == 0 ||
+	    strcmp (entry->d_name, "tmp") == 0)
+	{
+	    continue;
+	}
+
+	delete = FALSE;
+	fullpath = g_build_filename (path, entry->d_name, NULL);
+	switch (get_dtype(fullpath, entry)) {
+	case DT_REG:
+	    if (methc == CLEAN_ALL)
+		delete = TRUE;
+	    break;
+	case DT_LNK:
+	    if (methc == CLEAN_ALL ||
+		methc == CLEAN_SYMLINK ||
+		(methc == CLEAN_DANGLING &&
+		 (stat(fullpath, &buf) == -1 &&
+		  (errno == ENOENT || errno == ELOOP))))
+		delete = TRUE;
+	    break;
+	case DT_DIR:
+	    ret = maildir_clean_recursive (fullpath, methc);
+	    if (ret != -1)
+		count += ret;
+	    break;
+	default:
+	    break; /* skip the rest */
+	}
+
+	if (delete) {
+	    if (unlink (fullpath) == -1) {
+		fprintf (stderr, "Warning: error unlinking `%s': %s",
+			 fullpath, strerror(errno));
+	    } else {
+		count++;
+	    }
+	}
+
+	g_free (fullpath);
+    }
+
+    return count;
+}
diff --git a/maildir.h b/maildir.h
new file mode 100644
index 0000000..8b50ddf
--- /dev/null
+++ b/maildir.h
@@ -0,0 +1,53 @@
+/* Maildir utilities for the notmuch mail library
+ *
+ * Copyright © 2011 Ali Polatel
+ * Based in part upon mu which is:
+ *   Copyright © 2008-2011 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, see http://www.gnu.org/licenses/ .
+ *
+ * Author: Ali Polatel <polatel@gmail.com>
+ */
+
+#ifndef NOTMUCH_MAILDIR_H
+#define NOTMUCH_MAILDIR_H
+
+#include "notmuch-client.h"
+
+typedef enum {
+    RENAME_SYMLINK,
+    RENAME_HARDLINK,
+    /* TODO:
+     * RENAME_COPY,
+     * RENAME_MOVE,
+     */
+} rename_method_t;
+
+typedef enum {
+    CLEAN_DANGLING,
+    CLEAN_SYMLINK,
+    CLEAN_ALL,
+    CLEAN_NONE
+} clean_method_t;
+
+notmuch_bool_t
+maildir_check (const char *path, notmuch_bool_t makedir, mode_t mode);
+
+notmuch_bool_t
+maildir_rename (const char *src, const char *targetpath, rename_method_t methr);
+
+int
+maildir_clean_recursive(const char *path, clean_method_t methc);
+
+#endif
diff --git a/notmuch-client.h b/notmuch-client.h
index b50cb38..979eafd 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -36,6 +36,7 @@
  * keep notmuch.c from looking into any internals, (which helps us
  * develop notmuch.h into a plausible library interface).
  */
+#include "maildir.h"
 #include "xutil.h"
 
 #include <stddef.h>
@@ -120,6 +121,9 @@ int
 notmuch_dump_command (void *ctx, int argc, char *argv[]);
 
 int
+notmuch_link_command (void *ctx, int argc, char *argv[]);
+
+int
 notmuch_new_command (void *ctx, int argc, char *argv[]);
 
 int
diff --git a/notmuch-link.c b/notmuch-link.c
new file mode 100644
index 0000000..a147206
--- /dev/null
+++ b/notmuch-link.c
@@ -0,0 +1,339 @@
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright © 2011 Ali Polatel
+ *
+ * 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, see http://www.gnu.org/licenses/ .
+ *
+ * Author: Ali Polatel <alip@exherbo.org>
+ */
+
+#include "notmuch-client.h"
+
+typedef struct {
+    const char *maildir;
+
+    notmuch_bool_t cleandir;
+    notmuch_bool_t makedir;
+    notmuch_bool_t entire_thread;
+    mode_t mode;
+
+    clean_method_t clean_method;
+    rename_method_t rename_method;
+} link_options_t;
+
+static inline void
+init_link_options(link_options_t *options)
+{
+    options->maildir = NULL;
+
+    options->makedir = FALSE;
+    options->entire_thread = FALSE;
+    options->mode = 0700;
+
+    options->clean_method = CLEAN_NONE;
+    options->rename_method = RENAME_SYMLINK;
+}
+
+static inline const char *
+rename_method_abbr(rename_method_t method)
+{
+    switch (method) {
+    case RENAME_SYMLINK:
+	return "sym";
+    case RENAME_HARDLINK:
+	return "hard";
+    default:
+	return "love";
+    }
+}
+
+static inline const char *
+rename_method_verb(rename_method_t method)
+{
+    switch (method) {
+    case RENAME_SYMLINK:
+	return "symlinked";
+    case RENAME_HARDLINK:
+	return "hardlinked";
+    default:
+	return "made love all day long!";
+    }
+}
+
+static notmuch_bool_t
+prepare_maildir (const char *maildir,
+		 notmuch_bool_t makedir,
+		 mode_t mode,
+		 clean_method_t methc)
+{
+    int ret;
+
+    if (!maildir_check(maildir, makedir, mode))
+	return FALSE;
+
+    ret = maildir_clean_recursive(maildir, methc);
+    if (ret == -1)
+	return FALSE;
+    else if (ret > 0)
+	printf("Unlinked %d entries under %s\n",
+	       ret, maildir);
+
+    return TRUE;
+}
+
+static int
+link_messages (notmuch_messages_t *messages,
+	       rename_method_t rename_method,
+	       const char *maildir)
+{
+    int ret = 0;
+    const char *path;
+    notmuch_message_t *message;
+    notmuch_filenames_t *filenames;
+
+    for (;
+	 notmuch_messages_valid (messages);
+	 notmuch_messages_move_to_next (messages))
+    {
+	message = notmuch_messages_get (messages);
+
+	filenames = notmuch_message_get_filenames (message);
+	for (;
+	     notmuch_filenames_valid (filenames);
+	     notmuch_filenames_move_to_next (filenames))
+	{
+	    path = notmuch_filenames_get (filenames);
+	    if (maildir_rename (path, maildir, rename_method)) {
+		ret++;
+	    }
+	}
+	notmuch_filenames_destroy( filenames );
+
+	notmuch_message_destroy (message);
+    }
+
+    return ret;
+}
+
+static int
+do_link_threads (notmuch_query_t *query,
+		 const link_options_t *lopts)
+{
+    int message_count, thread_count;
+    notmuch_threads_t *threads;
+    notmuch_thread_t *thread;
+    notmuch_messages_t *messages;
+
+    threads = notmuch_query_search_threads (query);
+    if (threads == NULL)
+	return 1;
+
+    if (!prepare_maildir(lopts->maildir,
+			 lopts->makedir, lopts->mode,
+			 lopts->clean_method))
+	return 1;
+
+    message_count = thread_count = 0;
+    for (;
+	 notmuch_threads_valid (threads);
+	 notmuch_threads_move_to_next (threads))
+    {
+	thread = notmuch_threads_get (threads);
+
+	messages = notmuch_thread_get_toplevel_messages (thread);
+
+	if (messages == NULL)
+	    INTERNAL_ERROR ("Thread %s has no toplevel messages.\n",
+			    notmuch_thread_get_thread_id (thread));
+	else
+	    thread_count++;
+
+	message_count += link_messages (messages,
+					lopts->rename_method,
+					lopts->maildir);
+
+	notmuch_messages_destroy (messages);
+	notmuch_thread_destroy (thread);
+    }
+
+    if (message_count > 0) {
+	printf("%d messages in %d threads %s under %s\n",
+	       message_count, thread_count,
+	       rename_method_verb(lopts->rename_method),
+	       lopts->maildir);
+    }
+
+    notmuch_threads_destroy (threads);
+
+    return 0;
+}
+
+static int
+do_link_messages (notmuch_query_t *query,
+		  const link_options_t *lopts)
+{
+    int message_count;
+    notmuch_messages_t *messages;
+
+    messages = notmuch_query_search_messages (query);
+    if (messages == NULL)
+	return 1;
+
+    if (!prepare_maildir(lopts->maildir,
+			 lopts->makedir,
+			 lopts->mode,
+			 lopts->clean_method))
+	return 1;
+
+    message_count = link_messages (messages,
+				   lopts->rename_method,
+				   lopts->maildir);
+    if (message_count > 0) {
+	printf("%d messages %s under %s\n",
+	       message_count,
+	       rename_method_verb(lopts->rename_method),
+	       lopts->maildir);
+    }
+
+    notmuch_messages_destroy (messages);
+
+    return 0;
+}
+
+int
+notmuch_link_command (void *ctx, int argc, char *argv[])
+{
+    int i, ret;
+    char *query_str;
+    char *opt;
+    notmuch_config_t *config;
+    notmuch_database_t *notmuch;
+    notmuch_query_t *query;
+    link_options_t options;
+
+    init_link_options(&options);
+
+    for (i = 0; i < argc && argv[i][0] == '-'; i++) {
+	if (strcmp (argv[i], "--") == 0) {
+	    i++;
+	    break;
+	}
+	if (STRNCMP_LITERAL (argv[i], "--rename=") == 0) {
+	    opt = argv[i] + sizeof ("--rename=") - 1;
+	    if (strcmp (opt, "symlink") == 0) {
+		options.rename_method = RENAME_SYMLINK;
+	    } else if (strcmp (opt, "hardlink") == 0) {
+		options.rename_method = RENAME_HARDLINK;
+#if 0
+#error TODO
+	    } else if (strcmp (opt, "copy") == 0) {
+		options.rename_method = RENAME_COPY;
+	    } else if (strcmp (opt, "move") == 0) {
+		options.rename_method = RENAME_MOVE;
+#endif
+	    } else {
+		fprintf (stderr, "Invalid value for --rename: %s\n", opt);
+		return 1;
+	    }
+	} else if (STRNCMP_LITERAL (argv[i], "--maildir=") == 0) {
+	    opt = argv[i] + sizeof ("--maildir=") - 1;
+	    options.maildir = talloc_strdup (ctx, opt);
+	} else if (STRNCMP_LITERAL (argv[i], "--clean=") == 0) {
+	    opt = argv[i] + sizeof ("--clean=") - 1;
+	    if (strcmp (opt, "dangling") == 0) {
+		options.clean_method = CLEAN_DANGLING;
+	    } else if (strcmp (opt, "symlink") == 0) {
+		options.clean_method = CLEAN_SYMLINK;
+	    } else if (strcmp (opt, "all") == 0) {
+		options.clean_method = CLEAN_ALL;
+	    } else if (strcmp (opt, "none") == 0) {
+		options.clean_method = CLEAN_NONE;
+	    } else {
+		fprintf (stderr, "Invalid value for --clean: %s\n", opt);
+		return 1;
+	    }
+	} else if (STRNCMP_LITERAL (argv[i], "--mkdir") == 0) {
+	    options.makedir = TRUE;
+
+	    opt = argv[i] + sizeof ("--mkdir") - 1;
+
+	    if (opt[0] == '\0') {
+		continue;
+	    } else if (opt[0] != '=') {
+		fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
+		return 1;
+	    } else {
+		opt++; /* skip '=' */
+	    }
+
+	    options.mode = 0;
+	    while (*opt >= '0' && *opt <= '7')
+		options.mode = options.mode * 8 + (*opt++ - '0');
+	    if (*opt) {
+		fprintf (stderr, "Invalid value for --mkdir: %s\n", opt);
+		return 1;
+	    }
+	} else if (STRNCMP_LITERAL (argv[i], "--entire-thread") == 0) {
+	    options.entire_thread = TRUE;
+	} else {
+	    fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
+	    return 1;
+	}
+    }
+
+    if (!options.maildir) {
+	fprintf (stderr, "Target directory must be specified "
+			 "using --maildir option\n");
+	return 1;
+    }
+
+    argc -= i;
+    argv += i;
+
+    config = notmuch_config_open (ctx, NULL, NULL);
+    if (config == NULL)
+	return 1;
+
+    notmuch = notmuch_database_open (notmuch_config_get_database_path (config),
+				     NOTMUCH_DATABASE_MODE_READ_ONLY);
+    if (notmuch == NULL)
+	return 1;
+
+    query_str = query_string_from_args (notmuch, argc, argv);
+    if (query_str == NULL) {
+	fprintf (stderr, "Out of memory.\n");
+	return 1;
+    }
+    if (*query_str == '\0') {
+	fprintf (stderr, "Error: notmuch link requires at least one search term.\n");
+	return 1;
+    }
+
+    query = notmuch_query_create (notmuch, query_str);
+    if (query == NULL) {
+	fprintf (stderr, "Out of memory\n");
+	return 1;
+    }
+
+    if (options.entire_thread) {
+	ret = do_link_threads (query, &options);
+    } else {
+	ret = do_link_messages (query, &options);
+    }
+
+    notmuch_query_destroy (query);
+    notmuch_database_close (notmuch);
+
+    return ret;
+}
diff --git a/notmuch.c b/notmuch.c
index f9d6629..2a8753c 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -374,6 +374,50 @@ static command_t commands[] = {
       "\n"
       "\tSee \"notmuch help search-terms\" for details of the search\n"
       "\tterms syntax." },
+    { "link", notmuch_link_command,
+      "--maildir=TARGET [options...] <search-terms> [...]",
+      "Link messages matching the given search terms.",
+      "\tMake links to the maildir specified with the --maildir option.\n"
+      "\tThis command may be used to create so-called \"virtual\" folders\n"
+      "\tfor integration with different mail agents.\n"
+      "\n"
+      "\tSupported options for link include:\n"
+      "\n"
+      "\t--entire-thread\n"
+      "\n"
+      "\t\tBy default only those messages that match the\n"
+      "\t\tsearch terms will be linked. With this option,\n"
+      "\t\tall messages in the same thread as any matched\n"
+      "\t\tmessage will be linked.\n"
+      "\n"
+      "\t--rename=(hardlink|symlink)\n"
+      "\n"
+      "\t\tSpecify the renaming method, either hardlink or\n"
+      "\t\tsymlink (default)\n"
+      "\n"
+      "\t--maildir=TARGET\n"
+      "\n"
+      "\t\tSpecify the target maildir. This option is mandatory.\n"
+      "\n"
+      "\t--mkdir[=OCTAL_MODE]\n"
+      "\n"
+      "\t\tCreate the target maildir specified with the --maildir option\n"
+      "\t\tand any non-existing parent directories.\n"
+      "\t\tAccepts an optional octal mode argument which may be used to\n"
+      "\t\tspecify permissions. Default is 0700.\n"
+      "\n"
+      "\t--clean=(dangling|symlink|all|none)\n"
+      "\n"
+      "\t\tClean the target maildir specified with --maildir option\n"
+      "\t\tbefore proceeding to create links, using the specified method.\n"
+      "\t\tMethod may be one of:\n"
+      "\t\t- dangling: Clean only dangling symbolic links\n"
+      "\t\t- symlink:  Clean all symbolic links\n"
+      "\t\t- all:      Clean regular files in addition to symbolic links\n"
+      "\t\t- none:     Clean no files (default)\n"
+      "\n"
+      "\tSee \"notmuch help search-terms\" for details of the search\n"
+      "\tterms syntax." },
     { "dump", notmuch_dump_command,
       "[<filename>]",
       "Create a plain-text dump of the tags for each message.",
-- 
1.7.6.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [RFC/PATCH] notmuch link
  2011-10-01  8:45 [RFC/PATCH] notmuch link Ali Polatel
  2011-10-01  8:45 ` [RFC/PATCH] link: Add new command Ali Polatel
@ 2011-10-03 21:15 ` Ali Polatel
  2011-10-06 14:42   ` Tomi Ollila
  1 sibling, 1 reply; 4+ messages in thread
From: Ali Polatel @ 2011-10-03 21:15 UTC (permalink / raw)
  To: Notmuch Mailing List

[-- Attachment #1: Type: text/plain, Size: 1581 bytes --]

Ali Polatel yazmış:
>From: Ali Polatel <alip@exherbo.org>
>
>Hello,
>
>I have been working on a new notmuch command namely 'link'. This command
>aims to help integrating notmuch with different mail agents. Basically
>it (sym)links messages matching the given search terms to the specified
>target maildir. You may use this maildir as a so-called "virtual"
>folder. After applying the patch call "notmuch help link" for basic
>help.
>
>The patch is also available on links branch under my notmuch repository:
>https://github.com/alip/notmuch
>
>Beware this is pretty experimental, I have been using it for a couple of
>days fixing the issues along the way. I will be sharing my workflow
>using this command with mutt after I'm done polishing my scripts.
>
>This mail is merely a request for comments and testing.

Sigh...
I have just noticed "notmuch show" learned --format=mbox which makes
this patch rather pointless for me. This changeset will keep living
under my notmuch repository possibly without receiving any updates.

>Ali Polatel (1):
>  link: Add new command
>
> Makefile.local   |    2 +
> maildir.c        |  262 +++++++++++++++++++++++++++++++++++++++++
> maildir.h        |   53 +++++++++
> notmuch-client.h |    4 +
> notmuch-link.c   |  339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> notmuch.c        |   44 +++++++
> 6 files changed, 704 insertions(+), 0 deletions(-)
> create mode 100644 maildir.c
> create mode 100644 maildir.h
> create mode 100644 notmuch-link.c
>
>-- 
>1.7.6.1
>


         -alip

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC/PATCH] notmuch link
  2011-10-03 21:15 ` [RFC/PATCH] notmuch link Ali Polatel
@ 2011-10-06 14:42   ` Tomi Ollila
  0 siblings, 0 replies; 4+ messages in thread
From: Tomi Ollila @ 2011-10-06 14:42 UTC (permalink / raw)
  To: Notmuch Mailing List

On Tue 04 Oct 2011 00:15, Ali Polatel <polatel@gmail.com> writes:

> Ali Polatel yazmış:
>>
>>This mail is merely a request for comments and testing.
>
> Sigh...
> I have just noticed "notmuch show" learned --format=mbox which makes
> this patch rather pointless for me. This changeset will keep living
> under my notmuch repository possibly without receiving any updates.
>
>>Ali Polatel (1):
>>  link: Add new command

The 'link' feature would have been pretty cool as the linking goes
blazingly fast. But, the unfortunate side effect of this would be
that if the file referenced by link is modified, the original file gets 
modified.I personally don't want this to happen after the mail is delivered
unless I intentionally do it (my delivered mails filenames are generated
from the md5sum of the original content, so re-comparing all content
will reveal what files been modified :D)

If one of the goals of notmuch is to not to change the contents of mail
files and avoid this happening accidentally by other programs (referencing
files in configured 'path' from other programs considered non-accidental 
action) then this feature should just be dropped (but not forgotten so it
doesn't get re-implemented).

>         -alip

Tomi

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2011-10-06 14:42 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-01  8:45 [RFC/PATCH] notmuch link Ali Polatel
2011-10-01  8:45 ` [RFC/PATCH] link: Add new command Ali Polatel
2011-10-03 21:15 ` [RFC/PATCH] notmuch link Ali Polatel
2011-10-06 14:42   ` Tomi Ollila

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).