[RFC] Add support for the Solaris platform

2010-04-30 Thread Tomas Carnecky
Like on Mac OS X, the linker doesn't automatically resolve dependencies.

Signed-off-by: Tomas Carnecky 
---
 Makefile.local |2 +-
 configure  |   28 ++--
 lib/Makefile.local |2 +-
 notmuch-new.c  |   70 ++--
 4 files changed, 83 insertions(+), 19 deletions(-)

diff --git a/Makefile.local b/Makefile.local
index 5bb570b..5bc872b 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -255,7 +255,7 @@ notmuch_client_srcs =   \
 notmuch_client_modules = $(notmuch_client_srcs:.c=.o)

 notmuch: $(notmuch_client_modules) lib/libnotmuch.a
-   $(call quiet,CXX $(CFLAGS)) $^ $(FINAL_LIBNOTMUCH_LDFLAGS) -o $@
+   $(call quiet,CXX $(CFLAGS)) $^ $(FINAL_NOTMUCH_LDFLAGS) -o $@

 notmuch-shared: $(notmuch_client_modules) lib/$(LINKER_NAME)
$(call quiet,$(FINAL_NOTMUCH_LINKER) $(CFLAGS)) 
$(notmuch_client_modules) $(FINAL_NOTMUCH_LDFLAGS) -o $@
diff --git a/configure b/configure
index c522ad8..91e08dd 100755
--- a/configure
+++ b/configure
@@ -257,15 +257,26 @@ else
 have_emacs=0
 fi

-printf "Checking for Mac OS X (for shared library)... "
+printf "Checking which platform we are on... "
 if [ `uname` = "Darwin" ] ; then
-printf "Yes.\n"
-mac_os_x=1
+printf "Mac OS X.\n"
+platform=MACOSX
 linker_resolves_library_dependencies=0
-else
-printf "No.\n"
-mac_os_x=0
+elif [ `uname` = "SunOS" ] ; then
+printf "Solaris.\n"
+platform=SOLARIS
+linker_resolves_library_dependencies=0
+elif [ `uname` = "Linux" ] ; then
+printf "Linux\n"
+platform=LINUX
 linker_resolves_library_dependencies=1
+else
+printf "Unknown.\n"
+cat <d_name, (*b)->d_name);
 }

+/* Helper functions to test if a given dirent is of a certain type
+ */
+static int
+_is_reg(const char *path, struct dirent *entry)
+{
+#ifdef DT_REG
+if (entry->d_type == DT_REG)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name);
+
+struct stat sbuf;
+if (!stat(buffer, ))
+return S_ISREG(sbuf.st_mode);
+
+return 0;
+}
+
+static int
+_is_dir(const char *path, struct dirent *entry)
+{
+#ifdef DT_DIR
+if (entry->d_type == DT_DIR)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name);
+
+struct stat sbuf;
+if (!stat(buffer, ))
+return S_ISDIR(sbuf.st_mode);
+
+return 0;
+}
+
+static int
+_is_lnk(const char *path, struct dirent *entry)
+{
+#ifdef DT_LNK
+if (entry->d_type == DT_LNK)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name);
+
+struct stat sbuf;
+if (!stat(buffer, ))
+return S_ISLNK(sbuf.st_mode);
+
+return 0;
+}
+
 /* Test if the directory looks like a Maildir directory.
  *
  * Search through the array of directory entries to see if we can find all
@@ -143,12 +199,12 @@ dirent_sort_strcmp_name (const struct dirent **a, const 
struct dirent **b)
  * Return 1 if the directory looks like a Maildir and 0 otherwise.
  */
 static int
-_entries_resemble_maildir (struct dirent **entries, int count)
+_entries_resemble_maildir (const char *path, struct dirent **entries, int 
count)
 {
 int i, found = 0;

 for (i = 0; i < count; i++) {
-   if (entries[i]->d_type != DT_DIR && entries[i]->d_type != DT_UNKNOWN)
+   if (!_is_dir(path, entries[i]))
continue;

if (strcmp(entries[i]->d_name, "new") == 0 ||
@@ -261,7 +317,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 }

 /* Pass 1: Recurse into all sub-directories. */
-is_maildir = _entries_resemble_maildir (fs_entries, num_fs_entries);
+is_maildir = _entries_resemble_maildir (path, fs_entries, num_fs_entries);

 for (i = 0; i < num_fs_entries; i++) {
if (interrupted)
@@ -276,9 +332,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 * scandir results, then it might be a directory (and if not,
 * then we'll stat and return immediately in the next level of
 * recursion). */
-   if (entry->d_type != DT_DIR &&
-   entry->d_type != DT_LNK &&
-   entry->d_type != DT_UNKNOWN)
+   if (!_is_dir(path, entry) && !_is_lnk(path, entry))
{
continue;
}
@@ -356,7 +410,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 *
 * In either case, a stat does the trick.
 */
-   if (entry->d_type == DT_LNK || entry->d_type == DT_UNKNOWN) {
+   if (_is_lnk(path, entry)) {
int err;

next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);
@@ -372,7 +426,7 @@ add_files_recursive (notmuch_database_t *notmuch,

if (! S_ISREG (st.st_mode))
continue;
-   } else if (entry->d_type != DT_REG) {
+   } else if (!_is_reg(path, entry)) {
continue;
}

-- 
1.7.1



[PATCH] Actually respect LDFLAGS as we say in the ./configure help

2010-04-30 Thread Tomas Carnecky

Signed-off-by: Tomas Carnecky 
---
 configure |3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/configure b/configure
index 91e08dd..0153655 100755
--- a/configure
+++ b/configure
@@ -400,6 +400,9 @@ CFLAGS = ${CFLAGS}
 # Default FLAGS for C++ compiler (can be overridden by user such as "make 
CXXFLAGS=-g")
 CXXFLAGS = ${CXXFLAGS}

+# Default FLAGS for the linker (can be overridden by user such as "make 
LDFLAGS=-uhm,whatever")
+LDFLAGS = ${LDFLAGS}
+
 # Flags to enable warnings when using the C++ compiler
 WARN_CXXFLAGS=-Wall -Wextra -Wwrite-strings -Wswitch-enum

-- 
1.7.1



[PATCH] Actually respect LDFLAGS as we say in the ./configure help

2010-04-30 Thread Tomas Carnecky

Signed-off-by: Tomas Carnecky t...@dbservice.com
---
 configure |3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/configure b/configure
index 91e08dd..0153655 100755
--- a/configure
+++ b/configure
@@ -400,6 +400,9 @@ CFLAGS = ${CFLAGS}
 # Default FLAGS for C++ compiler (can be overridden by user such as make 
CXXFLAGS=-g)
 CXXFLAGS = ${CXXFLAGS}
 
+# Default FLAGS for the linker (can be overridden by user such as make 
LDFLAGS=-uhm,whatever)
+LDFLAGS = ${LDFLAGS}
+
 # Flags to enable warnings when using the C++ compiler
 WARN_CXXFLAGS=-Wall -Wextra -Wwrite-strings -Wswitch-enum
 
-- 
1.7.1

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[RFC] Add support for the Solaris platform

2010-04-30 Thread Tomas Carnecky
Like on Mac OS X, the linker doesn't automatically resolve dependencies.

Signed-off-by: Tomas Carnecky t...@dbservice.com
---
 Makefile.local |2 +-
 configure  |   28 ++--
 lib/Makefile.local |2 +-
 notmuch-new.c  |   70 ++--
 4 files changed, 83 insertions(+), 19 deletions(-)

diff --git a/Makefile.local b/Makefile.local
index 5bb570b..5bc872b 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -255,7 +255,7 @@ notmuch_client_srcs =   \
 notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
 
 notmuch: $(notmuch_client_modules) lib/libnotmuch.a
-   $(call quiet,CXX $(CFLAGS)) $^ $(FINAL_LIBNOTMUCH_LDFLAGS) -o $@
+   $(call quiet,CXX $(CFLAGS)) $^ $(FINAL_NOTMUCH_LDFLAGS) -o $@
 
 notmuch-shared: $(notmuch_client_modules) lib/$(LINKER_NAME)
$(call quiet,$(FINAL_NOTMUCH_LINKER) $(CFLAGS)) 
$(notmuch_client_modules) $(FINAL_NOTMUCH_LDFLAGS) -o $@
diff --git a/configure b/configure
index c522ad8..91e08dd 100755
--- a/configure
+++ b/configure
@@ -257,15 +257,26 @@ else
 have_emacs=0
 fi
 
-printf Checking for Mac OS X (for shared library)... 
+printf Checking which platform we are on... 
 if [ `uname` = Darwin ] ; then
-printf Yes.\n
-mac_os_x=1
+printf Mac OS X.\n
+platform=MACOSX
 linker_resolves_library_dependencies=0
-else
-printf No.\n
-mac_os_x=0
+elif [ `uname` = SunOS ] ; then
+printf Solaris.\n
+platform=SOLARIS
+linker_resolves_library_dependencies=0
+elif [ `uname` = Linux ] ; then
+printf Linux\n
+platform=LINUX
 linker_resolves_library_dependencies=1
+else
+printf Unknown.\n
+cat EOF
+
+*** Warning: Unknown platform. Notmuch might or might not build correctly.
+
+EOF
 fi
 
 if [ $errors -gt 0 ]; then
@@ -433,9 +444,8 @@ HAVE_GETLINE = ${have_getline}
 # build its own version)
 HAVE_STRCASESTR = ${have_strcasestr}
 
-# Whether we are building on OS X.  This will affect how we build the
-# shared library.
-MAC_OS_X = ${mac_os_x}
+# Supported platforms (so far) are: LINUX, MACOSX, SOLARIS
+PLATFORM = ${platform}
 
 # Whether the linker will automatically resolve the dependency of one
 # library on another (if not, then linking a binary requires linking
diff --git a/lib/Makefile.local b/lib/Makefile.local
index 0cc1d39..62f2316 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -22,7 +22,7 @@ LIBNOTMUCH_VERSION_MINOR = 1
 # simply compatible changes to the implementation).
 LIBNOTMUCH_VERSION_RELEASE = 0
 
-ifeq ($(MAC_OS_X),1)
+ifeq ($(PLATFORM),MACOSX)
 LIBRARY_SUFFIX = dylib
 # On OS X, library version numbers go before suffix.
 LINKER_NAME = libnotmuch.$(LIBRARY_SUFFIX)
diff --git a/notmuch-new.c b/notmuch-new.c
index 8818728..aacb5a6 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -135,6 +135,62 @@ dirent_sort_strcmp_name (const struct dirent **a, const 
struct dirent **b)
 return strcmp ((*a)-d_name, (*b)-d_name);
 }
 
+/* Helper functions to test if a given dirent is of a certain type
+ */
+static int
+_is_reg(const char *path, struct dirent *entry)
+{
+#ifdef DT_REG
+if (entry-d_type == DT_REG)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, %s/%s, path, entry-d_name);
+
+struct stat sbuf;
+if (!stat(buffer, sbuf))
+return S_ISREG(sbuf.st_mode);
+
+return 0;
+}
+
+static int
+_is_dir(const char *path, struct dirent *entry)
+{
+#ifdef DT_DIR
+if (entry-d_type == DT_DIR)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, %s/%s, path, entry-d_name);
+
+struct stat sbuf;
+if (!stat(buffer, sbuf))
+return S_ISDIR(sbuf.st_mode);
+
+return 0;
+}
+
+static int
+_is_lnk(const char *path, struct dirent *entry)
+{
+#ifdef DT_LNK
+if (entry-d_type == DT_LNK)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, %s/%s, path, entry-d_name);
+
+struct stat sbuf;
+if (!stat(buffer, sbuf))
+return S_ISLNK(sbuf.st_mode);
+
+return 0;
+}
+
 /* Test if the directory looks like a Maildir directory.
  *
  * Search through the array of directory entries to see if we can find all
@@ -143,12 +199,12 @@ dirent_sort_strcmp_name (const struct dirent **a, const 
struct dirent **b)
  * Return 1 if the directory looks like a Maildir and 0 otherwise.
  */
 static int
-_entries_resemble_maildir (struct dirent **entries, int count)
+_entries_resemble_maildir (const char *path, struct dirent **entries, int 
count)
 {
 int i, found = 0;
 
 for (i = 0; i  count; i++) {
-   if (entries[i]-d_type != DT_DIR  entries[i]-d_type != DT_UNKNOWN)
+   if (!_is_dir(path, entries[i]))
continue;
 
if (strcmp(entries[i]-d_name, new) == 0 ||
@@ -261,7 +317,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 }
 
 /* Pass 1: Recurse into all sub-directories. */
-is_maildir = _entries_resemble_maildir (fs_entries

[PATCH] Wrap the compat header in extern "C" { } when compiling C++ sources

2010-04-27 Thread Tomas Carnecky
This fixes a build error on OpenSolaris where the final liking of
notmuch fails because the linker can't find strcasestr() referenced
from thread.cc.
---

Is it safe to use NOTMUCH_BEGIN/END_DECLS in the compat header? The sha1 header
also uses ifdef __cplusplus instead of that define..

 compat/compat.h |8 
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/compat/compat.h b/compat/compat.h
index 173ef68..7767fe8 100644
--- a/compat/compat.h
+++ b/compat/compat.h
@@ -26,6 +26,10 @@
 #ifndef NOTMUCH_COMPAT_H
 #define NOTMUCH_COMPAT_H

+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #if !HAVE_GETLINE
 #include 
 #include 
@@ -42,4 +46,8 @@ getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp);
 char* strcasestr(const char *haystack, const char *needle);
 #endif /* !HAVE_STRCASESTR */

+#ifdef __cplusplus
+}
+#endif
+
 #endif /* NOTMUCH_COMPAT_H */
-- 
1.7.0.5



[PATCH] Wrap the compat header in extern C { } when compiling C++ sources

2010-04-27 Thread Tomas Carnecky
This fixes a build error on OpenSolaris where the final liking of
notmuch fails because the linker can't find strcasestr() referenced
from thread.cc.
---

Is it safe to use NOTMUCH_BEGIN/END_DECLS in the compat header? The sha1 header
also uses ifdef __cplusplus instead of that define..

 compat/compat.h |8 
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/compat/compat.h b/compat/compat.h
index 173ef68..7767fe8 100644
--- a/compat/compat.h
+++ b/compat/compat.h
@@ -26,6 +26,10 @@
 #ifndef NOTMUCH_COMPAT_H
 #define NOTMUCH_COMPAT_H
 
+#ifdef __cplusplus
+extern C {
+#endif
+
 #if !HAVE_GETLINE
 #include stdio.h
 #include unistd.h
@@ -42,4 +46,8 @@ getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp);
 char* strcasestr(const char *haystack, const char *needle);
 #endif /* !HAVE_STRCASESTR */
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* NOTMUCH_COMPAT_H */
-- 
1.7.0.5

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] Use wrapper functions to find the type of struct dirent

2010-04-13 Thread Tomas Carnecky
Some platforms don't provide DT_REG/DT_LNK/DT_DIR. Create wrapper functions
which test the presence of those symbols and fall back to stat(2).

---
Not sure if I got the handling of DT_UNKNOWN correct in all cases. Someone
please double-check that.

 notmuch-new.c |   70 ++--
 1 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 44b50aa..95b 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -140,6 +140,62 @@ dirent_sort_strcmp_name (const struct dirent **a, const 
struct dirent **b)
 return strcmp ((*a)->d_name, (*b)->d_name);
 }

+/* Helper functions to test if a given dirent is of a certain type
+ */
+static int
+_is_reg(const char *path, struct dirent *entry)
+{
+#ifdef DT_REG
+if (entry->d_type == DT_REG)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name);
+
+struct stat sbuf;
+if (!stat(buffer, ))
+return S_ISREG(sbuf.st_mode);
+
+return 0;
+}
+
+static int
+_is_dir(const char *path, struct dirent *entry)
+{
+#ifdef DT_DIR
+if (entry->d_type == DT_DIR)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name);
+
+struct stat sbuf;
+if (!stat(buffer, ))
+return S_ISDIR(sbuf.st_mode);
+
+return 0;
+}
+
+static int
+_is_lnk(const char *path, struct dirent *entry)
+{
+#ifdef DT_LNK
+if (entry->d_type == DT_LNK)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name);
+
+struct stat sbuf;
+if (!stat(buffer, ))
+return S_ISLNK(sbuf.st_mode);
+
+return 0;
+}
+
 /* Test if the directory looks like a Maildir directory.
  *
  * Search through the array of directory entries to see if we can find all
@@ -148,12 +204,12 @@ dirent_sort_strcmp_name (const struct dirent **a, const 
struct dirent **b)
  * Return 1 if the directory looks like a Maildir and 0 otherwise.
  */
 static int
-_entries_resemble_maildir (struct dirent **entries, int count)
+_entries_resemble_maildir (const char *path, struct dirent **entries, int 
count)
 {
 int i, found = 0;

 for (i = 0; i < count; i++) {
-   if (entries[i]->d_type != DT_DIR && entries[i]->d_type != DT_UNKNOWN)
+   if (!_is_dir(path, entries[i]))
continue;

if (strcmp(entries[i]->d_name, "new") == 0 ||
@@ -265,7 +321,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 }

 /* Pass 1: Recurse into all sub-directories. */
-is_maildir = _entries_resemble_maildir (fs_entries, num_fs_entries);
+is_maildir = _entries_resemble_maildir (path, fs_entries, num_fs_entries);

 for (i = 0; i < num_fs_entries; i++) {
if (interrupted)
@@ -280,9 +336,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 * scandir results, then it might be a directory (and if not,
 * then we'll stat and return immediately in the next level of
 * recursion). */
-   if (entry->d_type != DT_DIR &&
-   entry->d_type != DT_LNK &&
-   entry->d_type != DT_UNKNOWN)
+   if (!_is_dir(path, entry) && !_is_lnk(path, entry))
{
continue;
}
@@ -360,7 +414,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 *
 * In either case, a stat does the trick.
 */
-   if (entry->d_type == DT_LNK || entry->d_type == DT_UNKNOWN) {
+   if (_is_lnk(path, entry)) {
int err;

next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);
@@ -376,7 +430,7 @@ add_files_recursive (notmuch_database_t *notmuch,

if (! S_ISREG (st.st_mode))
continue;
-   } else if (entry->d_type != DT_REG) {
+   } else if (!_is_reg(path, entry)) {
continue;
}

-- 
1.7.0.5



[PATCH] Add strcasestr v.3 - add compat implementation of strcasestr

2010-04-13 Thread Tomas Carnecky
On 4/13/10 6:47 PM, Dirk Hohndel wrote:
>
> v.3 of this patch, now with the changes to makefiles, configure script
> compat.h and all new files that I need
> Please test on platforms lacking strcasestr
>
> Signed-off-by: Dirk Hohndel

Tested-by: Tomas Carnecky 

(on OpenSolaris snv_134)

tom



[PATCH] Add simplistic reimplementation of strcasestr to compat library

2010-04-13 Thread Tomas Carnecky
On 4/13/10 6:10 AM, Dirk Hohndel wrote:
>
> While all systems that I have access to support strcasestr, it is
> in fact not part of POSIX. So here's a fallback reimplementation
> based on POSIX functions.

Your patch is missing the part where it adds -DHAVE_STRCASESTR=.. to 
CONFIGURE_C{XX,}FLAGS.

And I still have to figure out the licencing of my patch (need to wait 
for the original author to respond). So maybe your patch, with the 
missing parts added, is better.

tom



[PATCH] Add compat version of strcasestr

2010-04-13 Thread Tomas Carnecky
strcasestr is not part of any standard (unlike for example strcasecmp) and thus
not available on all platforms (in my case Solaris).

---
 compat/Makefile.local|4 
 compat/compat.h  |4 
 compat/have_strcasestr.c |8 
 compat/strcasestr.c  |   15 +++
 configure|   19 +--
 5 files changed, 48 insertions(+), 2 deletions(-)
 create mode 100644 compat/have_strcasestr.c
 create mode 100644 compat/strcasestr.c

diff --git a/compat/Makefile.local b/compat/Makefile.local
index 81e6c70..328eca2 100644
--- a/compat/Makefile.local
+++ b/compat/Makefile.local
@@ -8,3 +8,7 @@ notmuch_compat_srcs =
 ifneq ($(HAVE_GETLINE),1)
 notmuch_compat_srcs += $(dir)/getline.c $(dir)/getdelim.c
 endif
+
+ifneq ($(HAVE_STRCASESTR),1)
+notmuch_compat_srcs += $(dir)/strcasestr.c
+endif
diff --git a/compat/compat.h b/compat/compat.h
index d639e0f..be70bd8 100644
--- a/compat/compat.h
+++ b/compat/compat.h
@@ -38,4 +38,8 @@ getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp);

 #endif /* !HAVE_GETLINE */

+#if !HAVE_STRCASESTR
+char *strcasestr(char *a, char *b);
+#endif /* !HAVE_STRCASESTR */
+
 #endif /* NOTMUCH_COMPAT_H */
diff --git a/compat/have_strcasestr.c b/compat/have_strcasestr.c
new file mode 100644
index 000..36e760d
--- /dev/null
+++ b/compat/have_strcasestr.c
@@ -0,0 +1,8 @@
+
+#include 
+#include 
+
+int main()
+{
+   return strcasestr("","");
+}
diff --git a/compat/strcasestr.c b/compat/strcasestr.c
new file mode 100644
index 000..a4188b9
--- /dev/null
+++ b/compat/strcasestr.c
@@ -0,0 +1,15 @@
+
+#include 
+#include 
+
+char *strcasestr(char *a, char *b)
+{
+  size_t l;
+  char f[3];
+  
+  snprintf(f, sizeof(f), "%c%c", tolower(*b), toupper(*b));
+  for (l = strcspn(a, f); l != strlen(a); l += strcspn(a + l + 1, f) + 1)
+if (strncasecmp(a + l, b, strlen(b)) == 0)
+  return a + l;
+  return NULL;
+}  
diff --git a/configure b/configure
index 5af7852..add2da6 100755
--- a/configure
+++ b/configure
@@ -310,6 +310,17 @@ else
 fi
 rm -f compat/have_getline

+printf "Checking for strcasestr... "
+if ${CC} -o compat/have_strcasestr compat/have_strcasestr.c > /dev/null 2>&1
+then
+printf "Yes.\n"
+have_strcasestr=1
+else
+printf "No (will use our own instead).\n"
+have_strcasestr=0
+fi
+rm -f compat/have_strcasestr
+
 cat <

Use of strcasestr

2010-04-13 Thread Tomas Carnecky
On 4/12/10 10:18 PM, Mikhail Gusarov wrote:
>
> Twas brillig at 15:58:10 12.04.2010 UTC+02 when tom at dbservice.com did gyre 
> and gimble:
>
>   TC>  In 4fd9ea0 (guess From address from Received headers, 2010-04-06) you 
> introduced
>   TC>  strcasestr, which is not portable, see 82e47ec (notmuch reply: Use 
> strstr
>   TC>  instead of strcasestr for portability., 2010-02-04).
>
>   TC>  Is strcasestr really necessary there or can it be replaced with strstr?
>
> strcasecmp is POSIX.1-2001.

Indeed it is, but the code uses strcasestr and I couldn't find any 
indication which standard that function is part of.

Adding that function to compat/ probably is the way to go, but the whole 
compat mechanism doesn't work here. It's like if compat/Makefile.local 
was not included in the top-level makefile, notmuch_compat_srcs is empty 
there. Any ideas how to debug that?

tom



Re: [PATCH] Add strcasestr v.3 - add compat implementation of strcasestr

2010-04-13 Thread Tomas Carnecky

On 4/13/10 6:47 PM, Dirk Hohndel wrote:


v.3 of this patch, now with the changes to makefiles, configure script
compat.h and all new files that I need
Please test on platforms lacking strcasestr

Signed-off-by: Dirk Hohndelhohn...@infradead.org


Tested-by: Tomas Carnecky t...@dbservice.com

(on OpenSolaris snv_134)

tom

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] Use wrapper functions to find the type of struct dirent

2010-04-13 Thread Tomas Carnecky
Some platforms don't provide DT_REG/DT_LNK/DT_DIR. Create wrapper functions
which test the presence of those symbols and fall back to stat(2).

---
Not sure if I got the handling of DT_UNKNOWN correct in all cases. Someone
please double-check that.

 notmuch-new.c |   70 ++--
 1 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 44b50aa..95b 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -140,6 +140,62 @@ dirent_sort_strcmp_name (const struct dirent **a, const 
struct dirent **b)
 return strcmp ((*a)-d_name, (*b)-d_name);
 }
 
+/* Helper functions to test if a given dirent is of a certain type
+ */
+static int
+_is_reg(const char *path, struct dirent *entry)
+{
+#ifdef DT_REG
+if (entry-d_type == DT_REG)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, %s/%s, path, entry-d_name);
+
+struct stat sbuf;
+if (!stat(buffer, sbuf))
+return S_ISREG(sbuf.st_mode);
+
+return 0;
+}
+
+static int
+_is_dir(const char *path, struct dirent *entry)
+{
+#ifdef DT_DIR
+if (entry-d_type == DT_DIR)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, %s/%s, path, entry-d_name);
+
+struct stat sbuf;
+if (!stat(buffer, sbuf))
+return S_ISDIR(sbuf.st_mode);
+
+return 0;
+}
+
+static int
+_is_lnk(const char *path, struct dirent *entry)
+{
+#ifdef DT_LNK
+if (entry-d_type == DT_LNK)
+return 1;
+#endif
+
+char buffer[PATH_MAX];
+snprintf(buffer, PATH_MAX, %s/%s, path, entry-d_name);
+
+struct stat sbuf;
+if (!stat(buffer, sbuf))
+return S_ISLNK(sbuf.st_mode);
+
+return 0;
+}
+
 /* Test if the directory looks like a Maildir directory.
  *
  * Search through the array of directory entries to see if we can find all
@@ -148,12 +204,12 @@ dirent_sort_strcmp_name (const struct dirent **a, const 
struct dirent **b)
  * Return 1 if the directory looks like a Maildir and 0 otherwise.
  */
 static int
-_entries_resemble_maildir (struct dirent **entries, int count)
+_entries_resemble_maildir (const char *path, struct dirent **entries, int 
count)
 {
 int i, found = 0;
 
 for (i = 0; i  count; i++) {
-   if (entries[i]-d_type != DT_DIR  entries[i]-d_type != DT_UNKNOWN)
+   if (!_is_dir(path, entries[i]))
continue;
 
if (strcmp(entries[i]-d_name, new) == 0 ||
@@ -265,7 +321,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 }
 
 /* Pass 1: Recurse into all sub-directories. */
-is_maildir = _entries_resemble_maildir (fs_entries, num_fs_entries);
+is_maildir = _entries_resemble_maildir (path, fs_entries, num_fs_entries);
 
 for (i = 0; i  num_fs_entries; i++) {
if (interrupted)
@@ -280,9 +336,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 * scandir results, then it might be a directory (and if not,
 * then we'll stat and return immediately in the next level of
 * recursion). */
-   if (entry-d_type != DT_DIR 
-   entry-d_type != DT_LNK 
-   entry-d_type != DT_UNKNOWN)
+   if (!_is_dir(path, entry)  !_is_lnk(path, entry))
{
continue;
}
@@ -360,7 +414,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 *
 * In either case, a stat does the trick.
 */
-   if (entry-d_type == DT_LNK || entry-d_type == DT_UNKNOWN) {
+   if (_is_lnk(path, entry)) {
int err;
 
next = talloc_asprintf (notmuch, %s/%s, path, entry-d_name);
@@ -376,7 +430,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 
if (! S_ISREG (st.st_mode))
continue;
-   } else if (entry-d_type != DT_REG) {
+   } else if (!_is_reg(path, entry)) {
continue;
}
 
-- 
1.7.0.5

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Use of strcasestr

2010-04-12 Thread Tomas Carnecky
In 4fd9ea0 (guess From address from Received headers, 2010-04-06) you 
introduced strcasestr, which is not portable, see 82e47ec (notmuch 
reply: Use strstr instead of strcasestr for portability., 2010-02-04).

Is strcasestr really necessary there or can it be replaced with strstr?

tom



[PATCH] notmuch new --new-tags=tags...

2010-04-12 Thread Tomas Carnecky
On 4/12/10 1:59 PM, Jameson Rollins wrote:
> On Mon, 12 Apr 2010 10:00:37 +0200, "Sebastian Spaeth" SSpaeth.de>  wrote:
>> On 2010-04-10, Anthony Towns wrote:
>>> The attached patch makes "notmuch new --new-tags=unread,new" set the
>>> "unread" and "new" tags on any new mail it finds rather than "unread"
>>> and "inbox". Or whatever other tags you happen to specify.
>>
>> Thanks for the patch. I can't comment on the code quality, but rather
>> than having to specify the set of new tags on the command line every
>> time, I think it would make more sense to put them in the notmuch config
>> file as this patch does:
>> id:1268432006-24333-2-git-send-email-bgamari.foss at gmail.com
>
> I was thinking about this, and it seems to me that we really need is a
> way to just specify which tags should be applied to new messages based
> on search terms.  It's becoming pretty clear that most people are doing
> some sort of post-notmuch-new tag processing to modify the tags of new
> messages to suite their needs.  Why not just integrate this directly
> into the notmuch-new processing itself?  It seems like if this was
> integrated into notmuch-new directly, the entire processing of new
> messages could be sped up considerably, so that one wouldn't have to
> call multiple notmuch-new processes in succession.
>
> I'm not sure exactly what the best way to handle it would be, but I can
> imagine something like this:
>
> [new-tags]
> +sent -new -- from:jrollins at finestructure.net
> +drafts -new -- folder:draft
> +notmuch -- from:notmuch at notmuchmail.org
> +unread +inbox -new -- tag:new
>
> These are all just commands for "notmuch tag" that would be run on all
> the new messages as they're processed.  Each new message would be given
> "new" tag by default, and then the new tag commands would be run.  So it
> would be the equivalent of running the following commands:
>
> notmuch new --new-tags=new
> notmuch tag +sent -new -- from:jrollins at finestructure.net
> notmuch tag +drafts -new -- folder:draft
> notmuch tag +notmuch -- from:notmuch at notmuchmail.org
> notmuch tag +unread +inbox -- tag:new
>
> This would make things much easier for everyone who is doing post-new
> tag processing, which I think is probably most people.  And I'm sure it
> could be made much more efficient (if coded properly) than running all
> these notmuch commands in succession, especially for people who have a
> lot of post-new tag processing to do.  Keeping the syntax identical to
> the notmuch-tag command syntax would keep things simple as well.
>
> Do people who do a lot of post-notmuch-new tag processing think
> something like this would suite their needs?

I have a patch which adds support for hooks which are run when tags are 
added, removed or new messages added to notmuch. But perhaps the 
fork/exec overhead of running the hooks would slow the processing down 
too much.
See http://caurea.org/2009/12/22/a-different-approach-to-email-tagging/, 
though that didn't work out quite how I expected. Classifying spam/ham 
is easy (that's what dspam was written for), but patch/not-patch 
resulted in a lot false-positives, especially when people quote emails 
which included patches. Same with the 'notmuch' and 'xorg' tags: dspam 
had trouble figuring out to which mailing list Carl sent the email (he 
sends emails to both lists).

tom




Re: [PATCH] notmuch new --new-tags=tags...

2010-04-12 Thread Tomas Carnecky

On 4/12/10 1:59 PM, Jameson Rollins wrote:

On Mon, 12 Apr 2010 10:00:37 +0200, Sebastian Spaethsebast...@sspaeth.de  
wrote:

On 2010-04-10, Anthony Towns wrote:

The attached patch makes notmuch new --new-tags=unread,new set the
unread and new tags on any new mail it finds rather than unread
and inbox. Or whatever other tags you happen to specify.


Thanks for the patch. I can't comment on the code quality, but rather
than having to specify the set of new tags on the command line every
time, I think it would make more sense to put them in the notmuch config
file as this patch does:
id:1268432006-24333-2-git-send-email-bgamari.f...@gmail.com


I was thinking about this, and it seems to me that we really need is a
way to just specify which tags should be applied to new messages based
on search terms.  It's becoming pretty clear that most people are doing
some sort of post-notmuch-new tag processing to modify the tags of new
messages to suite their needs.  Why not just integrate this directly
into the notmuch-new processing itself?  It seems like if this was
integrated into notmuch-new directly, the entire processing of new
messages could be sped up considerably, so that one wouldn't have to
call multiple notmuch-new processes in succession.

I'm not sure exactly what the best way to handle it would be, but I can
imagine something like this:

[new-tags]
+sent -new -- from:jroll...@finestructure.net
+drafts -new -- folder:draft
+notmuch -- from:notmuch@notmuchmail.org
+unread +inbox -new -- tag:new

These are all just commands for notmuch tag that would be run on all
the new messages as they're processed.  Each new message would be given
new tag by default, and then the new tag commands would be run.  So it
would be the equivalent of running the following commands:

notmuch new --new-tags=new
notmuch tag +sent -new -- from:jroll...@finestructure.net
notmuch tag +drafts -new -- folder:draft
notmuch tag +notmuch -- from:notmuch@notmuchmail.org
notmuch tag +unread +inbox -- tag:new

This would make things much easier for everyone who is doing post-new
tag processing, which I think is probably most people.  And I'm sure it
could be made much more efficient (if coded properly) than running all
these notmuch commands in succession, especially for people who have a
lot of post-new tag processing to do.  Keeping the syntax identical to
the notmuch-tag command syntax would keep things simple as well.

Do people who do a lot of post-notmuch-new tag processing think
something like this would suite their needs?


I have a patch which adds support for hooks which are run when tags are 
added, removed or new messages added to notmuch. But perhaps the 
fork/exec overhead of running the hooks would slow the processing down 
too much.
See http://caurea.org/2009/12/22/a-different-approach-to-email-tagging/, 
though that didn't work out quite how I expected. Classifying spam/ham 
is easy (that's what dspam was written for), but patch/not-patch 
resulted in a lot false-positives, especially when people quote emails 
which included patches. Same with the 'notmuch' and 'xorg' tags: dspam 
had trouble figuring out to which mailing list Carl sent the email (he 
sends emails to both lists).


tom


___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Use of strcasestr

2010-04-12 Thread Tomas Carnecky
In 4fd9ea0 (guess From address from Received headers, 2010-04-06) you 
introduced strcasestr, which is not portable, see 82e47ec (notmuch 
reply: Use strstr instead of strcasestr for portability., 2010-02-04).


Is strcasestr really necessary there or can it be replaced with strstr?

tom

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Use of strcasestr

2010-04-12 Thread Tomas Carnecky

On 4/12/10 10:18 PM, Mikhail Gusarov wrote:


Twas brillig at 15:58:10 12.04.2010 UTC+02 when t...@dbservice.com did gyre and 
gimble:

  TC  In 4fd9ea0 (guess From address from Received headers, 2010-04-06) you 
introduced
  TC  strcasestr, which is not portable, see 82e47ec (notmuch reply: Use strstr
  TC  instead of strcasestr for portability., 2010-02-04).

  TC  Is strcasestr really necessary there or can it be replaced with strstr?

strcasecmp is POSIX.1-2001.


Indeed it is, but the code uses strcasestr and I couldn't find any 
indication which standard that function is part of.


Adding that function to compat/ probably is the way to go, but the whole 
compat mechanism doesn't work here. It's like if compat/Makefile.local 
was not included in the top-level makefile, notmuch_compat_srcs is empty 
there. Any ideas how to debug that?


tom

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] Add compat version of strcasestr

2010-04-12 Thread Tomas Carnecky
strcasestr is not part of any standard (unlike for example strcasecmp) and thus
not available on all platforms (in my case Solaris).

---
 compat/Makefile.local|4 
 compat/compat.h  |4 
 compat/have_strcasestr.c |8 
 compat/strcasestr.c  |   15 +++
 configure|   19 +--
 5 files changed, 48 insertions(+), 2 deletions(-)
 create mode 100644 compat/have_strcasestr.c
 create mode 100644 compat/strcasestr.c

diff --git a/compat/Makefile.local b/compat/Makefile.local
index 81e6c70..328eca2 100644
--- a/compat/Makefile.local
+++ b/compat/Makefile.local
@@ -8,3 +8,7 @@ notmuch_compat_srcs =
 ifneq ($(HAVE_GETLINE),1)
 notmuch_compat_srcs += $(dir)/getline.c $(dir)/getdelim.c
 endif
+
+ifneq ($(HAVE_STRCASESTR),1)
+notmuch_compat_srcs += $(dir)/strcasestr.c
+endif
diff --git a/compat/compat.h b/compat/compat.h
index d639e0f..be70bd8 100644
--- a/compat/compat.h
+++ b/compat/compat.h
@@ -38,4 +38,8 @@ getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp);
 
 #endif /* !HAVE_GETLINE */
 
+#if !HAVE_STRCASESTR
+char *strcasestr(char *a, char *b);
+#endif /* !HAVE_STRCASESTR */
+
 #endif /* NOTMUCH_COMPAT_H */
diff --git a/compat/have_strcasestr.c b/compat/have_strcasestr.c
new file mode 100644
index 000..36e760d
--- /dev/null
+++ b/compat/have_strcasestr.c
@@ -0,0 +1,8 @@
+
+#include string.h
+#include strings.h
+
+int main()
+{
+   return strcasestr(,);
+}
diff --git a/compat/strcasestr.c b/compat/strcasestr.c
new file mode 100644
index 000..a4188b9
--- /dev/null
+++ b/compat/strcasestr.c
@@ -0,0 +1,15 @@
+
+#include string.h
+#include strings.h
+
+char *strcasestr(char *a, char *b)
+{
+  size_t l;
+  char f[3];
+  
+  snprintf(f, sizeof(f), %c%c, tolower(*b), toupper(*b));
+  for (l = strcspn(a, f); l != strlen(a); l += strcspn(a + l + 1, f) + 1)
+if (strncasecmp(a + l, b, strlen(b)) == 0)
+  return a + l;
+  return NULL;
+}  
diff --git a/configure b/configure
index 5af7852..add2da6 100755
--- a/configure
+++ b/configure
@@ -310,6 +310,17 @@ else
 fi
 rm -f compat/have_getline
 
+printf Checking for strcasestr... 
+if ${CC} -o compat/have_strcasestr compat/have_strcasestr.c  /dev/null 21
+then
+printf Yes.\n
+have_strcasestr=1
+else
+printf No (will use our own instead).\n
+have_strcasestr=0
+fi
+rm -f compat/have_strcasestr
+
 cat EOF
 
 All required packages were found. You may now run the following
@@ -384,6 +395,10 @@ zsh_completion_dir = 
\$(prefix)/share/zsh/functions/Completion/Unix
 # build its own version)
 HAVE_GETLINE = ${have_getline}
 
+# Whether the strcasestr function is available (if not, then notmuch will
+# build its own version) 
+HAVE_STRCASESTR = ${have_strcasestr} 
+
 # Flags needed to compile and link against Xapian
 XAPIAN_CXXFLAGS = ${xapian_cxxflags}
 XAPIAN_LDFLAGS = ${xapian_ldflags}
@@ -405,9 +420,9 @@ VALGRIND_CFLAGS = ${valgrind_cflags}
 # Combined flags for compiling and linking against all of the above
 CONFIGURE_CFLAGS = -DHAVE_GETLINE=\$(HAVE_GETLINE) \$(GMIME_CFLAGS)  \\
   \$(TALLOC_CFLAGS) -DHAVE_VALGRIND=\$(HAVE_VALGRIND)   \\
-  \$(VALGRIND_CFLAGS)
+  \$(VALGRIND_CFLAGS) -DHAVE_STRCASESTR=\$(HAVE_STRCASESTR)
 CONFIGURE_CXXFLAGS = -DHAVE_GETLINE=\$(HAVE_GETLINE) \$(GMIME_CFLAGS)\\
 \$(TALLOC_CFLAGS) -DHAVE_VALGRIND=\$(HAVE_VALGRIND) \\
-\$(VALGRIND_CFLAGS) \$(XAPIAN_CXXFLAGS)
+\$(VALGRIND_CFLAGS) \$(XAPIAN_CXXFLAGS) 
-DHAVE_STRCASESTR=\$(HAVE_STRCASESTR)
 CONFIGURE_LDFLAGS =  \$(GMIME_LDFLAGS) \$(TALLOC_LDFLAGS) \$(XAPIAN_LDFLAGS)
 EOF
-- 
1.7.0.2

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH] Add simplistic reimplementation of strcasestr to compat library

2010-04-12 Thread Tomas Carnecky

On 4/13/10 6:10 AM, Dirk Hohndel wrote:


While all systems that I have access to support strcasestr, it is
in fact not part of POSIX. So here's a fallback reimplementation
based on POSIX functions.


Your patch is missing the part where it adds -DHAVE_STRCASESTR=.. to 
CONFIGURE_C{XX,}FLAGS.


And I still have to figure out the licencing of my patch (need to wait 
for the original author to respond). So maybe your patch, with the 
missing parts added, is better.


tom

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[notmuch] [PATCH] Add post-add and post-tag hooks

2009-12-23 Thread Tomas Carnecky
On 12/23/09 12:02 AM, Olly Betts wrote:
> Tomas Carnecky writes:
>> #if defined(__sun__)
>>  ... sprintf, stat etc
>> #else
>>  (void) path;
>>  return dirent->d_type == DT_DIR;
>> #endif
>
> Rather than a platform-specific check, it would be better to check if DT_DIR
> is defined.
>
> Beware that even on Linux (where the d_type field is present), it may always
> contain DT_UNKNOWN for some filesystems, so you really should check for that
> case and fall back to using stat() instead.

Currently configure is a simple shell script and not some autoconf 
magic. And I don't know how eager Carl is to use autoconf, scons, cmake 
or similar.

tom



[notmuch] [PATCH] Add post-add and post-tag hooks

2009-12-22 Thread Tomas Carnecky
On 12/22/09 3:56 AM, Tomas Carnecky wrote:
 > The post-add hook is run by 'notmuch new' after each new message is 
added,
 > post-tag is run after a tag has been added or removed. The hooks are 
stored
 > in the users home directory (~/.notmuch/hooks/).
 >
 > Since post-tag is run unconditionally every time a new tag is added 
or removed,
 > that means it is also invoked when 'notmuch new' adds the two implicit
 > tags (inbox, unread). So make sure your scripts don't choke on that 
and can
 > be both executed in parallel.

What are these good for? I (try to) use these two hooks to automatically 
tag messages. But not in the usual way, I don't use static scripts, I 
use a spam filter. I hope to be able to teach it to classify the 
messages, not only spam/ham but also add tags such as patch (does that 
message contain a patch?), tag messages based on which mailing lists the 
messages belong etc.

I use dspam as the spam filter. Each tag is actually a virtual user that 
exists in dspam. When adding new messages dspam classifies the mails and 
I assign the tags based on the result. If dspam deemed the message Spam 
then I set the tag. To train dspam I use the post-tag hook: whenever I 
change a tag (for example add 'spam' to a falsely unrecognized spam), 
the post-tag hook retrains dspam.

Since the post-add hook is running synchronously with 'notmuch new', 
this adds quite a bit overhead. Depending on how fast the spam filter 
is, it adds more or less time to do the import of new messages. It also 
depends on how many tags you want to assign - dspam has to run once for 
each tag to see if the tag should be assigned or not.

tom

--- >8 --- post-add
#!/bin/bash

# This is so that the post-tag doesn't trigger retraining!
export NOTMUCH_POST_ADD=1

MESSAGEID=$1
FILENAME=$2

# Array of tags.
tags=( spam )
for tag in "${tags[@]}"; do
 RESULT="$(/opt/dspam/bin/dspam --user $tag --deliver=summary < 
$FILENAME)"

 if echo $RESULT | grep -q 'result="Spam";'; then
 echo $tag
 fi
done

# I remove the inbox flag from all new messages and keep only 'unread'
echo "-inbox"
--- >8 ---

--- >8 --- post-tag
#!/bin/sh

if [ "$NOTMUCH_POST_ADD" ]; then
 echo "Exiting due to running in post-add"
 exit
fi

MESSAGEID=$1
FILENAME=$2
TAG=$3
ADDREMOVE=$4

if [ "x$ADDREMOVE" = "xadded" ]; then
 CLASS="spam"
else
 CLASS="innocent"
fi

/opt/dspam/bin/dspam --user $TAG --source=error --class=$CLASS < $FILENAME
--- >8 ---



[notmuch] [PATCH] Add post-add and post-tag hooks

2009-12-22 Thread Tomas Carnecky
The post-add hook is run by 'notmuch new' after each new message is added,
post-tag is run after a tag has been added or removed. The hooks are stored
in the users home directory (~/.notmuch/hooks/).

Since post-tag is run unconditionally every time a new tag is added or removed,
that means it is also invoked when 'notmuch new' adds the two implicit
tags (inbox, unread). So make sure your scripts don't choke on that and can
be both executed in parallel.

Signed-off-by: Tomas Carnecky 
---
 lib/message.cc |   45 ++
 notmuch-new.c  |   66 
 2 files changed, 111 insertions(+), 0 deletions(-)

diff --git a/lib/message.cc b/lib/message.cc
index 49519f1..bcd8abb 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -664,6 +664,47 @@ _notmuch_message_remove_term (notmuch_message_t *message,
 return NOTMUCH_PRIVATE_STATUS_SUCCESS;
 }

+/* Run the post-tag hook */
+static void
+post_tag_hook (notmuch_message_t *message, const char *tag, int added)
+{
+/* Skip tags that notmuch itself assigns to new messages */
+const char *skip[] = {
+"inbox", "unread"
+};
+
+for (int i = 0; i < sizeof (skip) / sizeof (skip[0]); ++i) {
+if (strcmp(skip[i], tag) == 0)
+return;
+}
+
+char proc[PATH_MAX];
+snprintf (proc, PATH_MAX, "%s/.notmuch/hooks/post-tag", getenv("HOME"));
+if (access (proc, X_OK))
+return;
+
+int pid = fork ();
+if (pid == -1)
+return;
+
+/* Wait for the hook to finish. This behaviour might be changed in the
+ * future, but for now I think it's better to take the safe route. */
+if (pid > 0) {
+waitpid (0, NULL, 0);
+return;
+}
+
+const char *filename = notmuch_message_get_filename (message);
+const char *message_id = notmuch_message_get_message_id (message);
+
+const char *args[] = {
+proc, message_id, filename, tag, added ? "added" : "removed", NULL
+};
+
+execv (proc, (char *const *) );
+exit (0);
+}
+
 notmuch_status_t
 notmuch_message_add_tag (notmuch_message_t *message, const char *tag)
 {
@@ -684,6 +725,8 @@ notmuch_message_add_tag (notmuch_message_t *message, const 
char *tag)
 if (! message->frozen)
_notmuch_message_sync (message);

+post_tag_hook (message, tag, 1);
+
 return NOTMUCH_STATUS_SUCCESS;
 }

@@ -707,6 +750,8 @@ notmuch_message_remove_tag (notmuch_message_t *message, 
const char *tag)
 if (! message->frozen)
_notmuch_message_sync (message);

+post_tag_hook (message, tag, 0);
+
 return NOTMUCH_STATUS_SUCCESS;
 }

diff --git a/notmuch-new.c b/notmuch-new.c
index 837ae4f..d984aae 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -42,6 +42,71 @@ handle_sigint (unused (int sig))
 interrupted = 1;
 }

+/* Run the post-add hook. The hook is given the chance to specify additional 
tags
+ * that should be added to the message. The hook writes the tags to its stdout,
+ * separated by a newline. The script's stdout is redirected to a pipe so that
+ * notmuch can process its output. The tags can be prefixed with '+' or '-' to
+ * indicate if the tag should be added or removed. Absence of one of these 
prefixes
+ * means that the tag will be added. */
+static void
+post_add_hook (notmuch_message_t *message)
+{
+char proc[PATH_MAX];
+snprintf (proc, PATH_MAX, "%s/.notmuch/hooks/post-add", getenv ("HOME"));
+if (access (proc, X_OK))
+return;
+
+/* The pipe between the hook and the notmuch process. The script writes
+ * into fds[0], notmuch reads from fds[1]. */
+int fds[2];
+if (pipe (fds))
+   return;
+
+int pid = fork ();
+if (pid == -1) {
+   close (fds[0]);
+   close (fds[1]);
+   return;
+} else if (pid > 0) {
+   close (fds[0]);
+   waitpid (0, NULL, 0);
+
+   char buffer[256] = { 0, };
+   read (fds[1], buffer, sizeof (buffer));
+
+   char *tag;
+   for (tag = buffer; tag && *tag; ) {
+   char *end = strchr (tag, '\n');
+   if (end)
+   *end = 0;
+
+   if (tag[0] == '+')
+   notmuch_message_add_tag (message, tag + 1);
+   else if (tag[0] == '-')
+   notmuch_message_remove_tag (message, tag + 1);
+   else
+   notmuch_message_add_tag (message, tag);
+
+   tag = end ? end + 1 : end;
+   }
+
+   return;
+}
+
+/* This is the child process (where the hook runs) */
+close (fds[1]);
+dup2 (fds[0], 1);
+
+const char *filename = notmuch_message_get_filename (message);
+const char *message_id = notmuch_message_get_message_id (message);
+const char *args[] = {
+   proc, message_id, filename, NULL
+};
+
+execv (proc, (char *const *) );
+exit (0);
+}
+
 static void
 tag_inbox_and_unre

[notmuch] [PATCH] Solaris doesn't have 'struct dirent::d_type'

2009-12-21 Thread Tomas Carnecky
On 12/20/09 7:02 PM, James Westby wrote:
> From: Tomas Carnecky
>
> Use stat(2) instead.
>
> Signed-off-by: Tomas Carnecky
> Signed-off-by: James Westby<jw+debian at jameswestby.net>
> ---
>
>The original patch duplicated asprintf and stat calls, rearraging
>the code means we don't need to.
>
>I have a concern about the duplicated stats in is_maildir, but they
>are not so easy to save. I ran a quick timing test (3931 files), dropping
>caches before each set:
>
>  master:
>real  2m3.545s
>real  1m34.571s
>real  1m36.005s
>
>  original patch:
>real  2m18.114s
>real  1m34.843s
>real  1m36.317s
>
>  revised patch:
>real  2m5.890s
>real  1m36.387s
>real  1m36.453s
>
>This shoes there is little impact of the code, but given that it is
>around one percent we may want to make it conditional on platform
>and save the extra stat calls.

If performance regression is an issue, something like this could be used 
to keep the current code paths in linux and stat() on other platforms:

static bool
is_dir(const char *path, struct dirent *dirent)
{
#if defined(__sun__)
... sprintf, stat etc
#else
(void) path;
return dirent->d_type == DT_DIR;
#endif
}

tom



[notmuch] [PATCH] Solaris doesn't have 'struct dirent::d_type'

2009-12-20 Thread Tomas Carnecky
Use stat(2) instead.

Signed-off-by: Tomas Carnecky 
---

There is a second issue that prevents notmuch from working on Solaris:
the getpwuid_r() prototype doesn't have the last argument. But that can
be easily worked around by setting -D_POSIX_PTHREAD_SEMANTICS on the
compiler commandline. Do you want to use uname to detect the platform
and define platform-specific code or can I unconditionally add that
define to CFLAGS?

 notmuch-new.c |   22 +-
 1 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 9d20616..837ae4f 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -90,12 +90,18 @@ static int ino_cmp(const struct dirent **a, const struct 
dirent **b)
  * Return 1 if the directory looks like a Maildir and 0 otherwise.
  */
 static int
-is_maildir (struct dirent **entries, int count)
+is_maildir (const char *path, struct dirent **entries, int count)
 {
 int i, found = 0;

 for (i = 0; i < count; i++) {
-   if (entries[i]->d_type != DT_DIR) continue;
+   char pbuf[PATH_MAX];
+snprintf(pbuf, PATH_MAX, "%s/%s", path, entries[i]->d_name);
+
+   struct stat buf;
+   if (stat(pbuf, ) == -1 || !S_ISDIR(buf.st_mode))
+   continue;
+
if (strcmp(entries[i]->d_name, "new") == 0 ||
strcmp(entries[i]->d_name, "cur") == 0 ||
strcmp(entries[i]->d_name, "tmp") == 0)
@@ -178,7 +184,13 @@ add_files_recursive (notmuch_database_t *notmuch,
/* If this directory hasn't been modified since the last
 * add_files, then we only need to look further for
 * sub-directories. */
-   if (path_mtime <= path_dbtime && entry->d_type == DT_REG)
+   struct stat buf;
+   char pbuf[PATH_MAX];
+   snprintf(pbuf, PATH_MAX, "%s/%s", path, entry->d_name);
+   if (stat(pbuf, ) == -1)
+   continue;
+
+   if (path_mtime <= path_dbtime && S_ISREG(buf.st_mode))
continue;

/* Ignore special directories to avoid infinite recursion.
@@ -188,9 +200,9 @@ add_files_recursive (notmuch_database_t *notmuch,
 * user specify files to be ignored. */
if (strcmp (entry->d_name, ".") == 0 ||
strcmp (entry->d_name, "..") == 0 ||
-   (entry->d_type == DT_DIR &&
+   (S_ISDIR(buf.st_mode) &&
 (strcmp (entry->d_name, "tmp") == 0) &&
-is_maildir (namelist, num_entries)) ||
+is_maildir (path, namelist, num_entries)) ||
strcmp (entry->d_name, ".notmuch") ==0)
{
continue;
-- 
1.6.6.rc1.39.g9a42