Re: [PATCH] emacs: add missing paren to fix defun in notmuch-address.el.

2013-04-08 Thread Jed Brown
David Bremner  writes:

> Squashed sounds good to me too. Sorry I'm too lazy/busy at the moment to
> do it myself.

I tested the attached and it's working as expected.  Sent as an
attachment to preserve author information.

>From 5404ac5bf13f8b5349d5b94f9f2000e9d1832b83 Mon Sep 17 00:00:00 2001
From: Daniel Bergey 
Date: Mon, 8 Apr 2013 19:55:04 -0500
Subject: [PATCH] emacs: functions to import sender or recipient into BBDB [v2]

>From a show buffer, notmuch-bbdb/snarf-from imports the sender into
bbdb.  notmuch-bbdb/snarf-to imports all recipients.  Newly imported
contacts are reported in the minibuffer / Messages buffer.

Both functions use the BBDB parser to recognize email address formats.

[v2] Fixes missing close parenthesis in original.
 Spotted by Karl Fogel .
---
 emacs/notmuch-address.el | 41 +
 1 file changed, 41 insertions(+)

diff --git a/emacs/notmuch-address.el b/emacs/notmuch-address.el
index 2bf762b..4eda098 100644
--- a/emacs/notmuch-address.el
+++ b/emacs/notmuch-address.el
@@ -96,6 +96,47 @@ line."
 (when (notmuch-address-locate-command notmuch-address-command)
   (notmuch-address-message-insinuate))
 
+;; functions to add sender / recipients to BBDB
+
+(defun notmuch-bbdb/snarf-headers (headers)
+  ;; Helper function to avoid code duplication in the two below
+  ;; headers should have the same format as bbdb-get-addresses-headers
+
+  ;; bbdb-get-addresses reads these
+  ;; Ugh, pass-by-global
+  (let ((addrs (bbdb-get-addresses nil nil 'notmuch-bbdb/get-header-content))
+	(bbdb-get-addresses-headers headers) ; headers to read
+	(bbdb-gag-messages t)) ; suppress m/n processed message)
+(bbdb-update-records addrs t t)))
+
+(defun notmuch-bbdb/snarf-from ()
+  "Import the sender of the current message into BBDB"
+  (interactive)
+  (notmuch-bbdb/snarf-headers
+   (list (assoc 'authors bbdb-get-addresses-headers
+
+(defun notmuch-bbdb/snarf-to ()
+  "Import all recipients of the current message into BBDB"
+  (interactive)
+  (notmuch-bbdb/snarf-headers
+   (list (assoc 'recipients bbdb-get-addresses-headers
+
+(defvar notmuch-bbdb/header-by-name
+  ;; both are case sensitive
+  '( ("From" . :From)
+ ("To" . :To)
+ ("CC" . :Cc)
+ ("BCC" . :Bcc)
+ ("Resent-From" . nil)
+ ("Reply-To" . nil)
+ ("Resent-To" . nil)
+ ("Resent-CC" . nil))
+  "Alist for dispatching header symbols as used by notmuch-show-get-header
+from strings as used by bbdb-get-addresses")
+
+(defun notmuch-bbdb/get-header-content (name)
+  (notmuch-show-get-header (cdr (assoc name notmuch-bbdb/header-by-name
+
 ;;
 
 (provide 'notmuch-address)
-- 
1.8.2.1

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


[RFC/PATCH] python: search parent lib directory for libnotmuch.so

2013-04-08 Thread Jed Brown
If libnotmuch.so is installed to a path that is not searched by
dlopen(3), we must import it using an absolute path because the Python
bindings do not have the luxury of RPATH linking.  So strip off the
trailing directories from the install location and try CDLL with an
absolute path.
---
This is sort of a hack, but I don't know a less intrusive way to get
libnotmuch.so from somewhere dlopen(3) doesn't already search.

The absolute path version won't do the right thing in case of 'setup.py
develop', otherwise we could use it in all cases.  It may still make
sense to make the absolute path version take precedence.

An alternative would be to find libnotmuch.so using the notmuch
executable.

 bindings/python/notmuch/globals.py | 19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/bindings/python/notmuch/globals.py 
b/bindings/python/notmuch/globals.py
index c7632c3..2473f04 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -24,7 +24,24 @@ from ctypes import CDLL, Structure, POINTER
 try:
 nmlib = CDLL("libnotmuch.so.3")
 except:
-raise ImportError("Could not find shared 'notmuch' library.")
+try:
+# If Notmuch is installed to a location not searched by
+# dlopen(3), we must import it using an absolute path.  We
+# can't just reset LD_LIBRARY_PATH because ld.so reads it when
+# Python is starting and will not reread the environment.  We
+# assume the install directory structure has the form:
+#
+#   /base-path/lib/pythonX.Y/site-packages/notmuch/globals.py
+#
+# so that we can get the library directory by stripping off
+# the last four elements of the path.
+import os.path
+path = os.path.abspath(__file__)
+for i in range(4):
+path = os.path.dirname(path)
+nmlib = CDLL(os.path.join(path, 'libnotmuch.so.3'))
+except:
+raise ImportError("Could not find shared 'notmuch' library.")
 
 from .compat import Python3StringMixIn, encode_utf8 as _str
 
-- 
1.8.2.1

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


Re: [RFC/PATCH] python: search parent lib directory for libnotmuch.so

2013-04-09 Thread Jed Brown
Justus Winter <4win...@informatik.uni-hamburg.de> writes:
>
> May I ask why you cannot use LD_LIBRARY_PATH? I too install libnotmuch
> to a non-standard location as unprivileged user and to make this
> library available I add its path to LD_LIBRARY_PATH. 

See libdir_in_ldconfig testing in configure: we make a significant
effort to set RPATH appropriately when installing to a location that is
not already searched (perhaps via LD_LIBRARY_PATH).  This currently does
not apply to the Python bindings, so while you can install without
LD_LIBRARY_PATH and still run the notmuch executable fine, you must set
LD_LIBRARY_PATH to use the Python bindings.  That is the inconsistency I
wanted to fix here.

>> This is sort of a hack, but I don't know a less intrusive way to get
>> libnotmuch.so from somewhere dlopen(3) doesn't already search.
>> 
>> The absolute path version won't do the right thing in case of 'setup.py
>> develop', otherwise we could use it in all cases.  It may still make
>> sense to make the absolute path version take precedence.
>
> Well, if something like this is necessary and wanted (opinions
> anyone?) at least let's not hardcode the assumption about the
> directory layout but just walk up the tree until we find notmuch.so.3
> or lib/notmuch.so.3. This way the bindings will find the correct
> library even when they are included directly from within the source
> tree.

I actually wrote the more permissive version below, then decided I
preferred the stricter behavior because there was less chance of
accidentally finding a stale libnotmuch.so.3.  Note that in the source
tree, notmuch-shared already has RPATH pointing to the install location
so it's not valid without install.  The strict version of my patch has
similar behavior in that Python bindings are only valid when installed.
If you want to run them from the source tree, you'd have to add
/path/to/notmuch/lib to LD_LIBRARY_PATH.

diff --git a/bindings/python/notmuch/globals.py 
b/bindings/python/notmuch/globals.py
index c7632c3..2fd383f 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -24,7 +24,16 @@ from ctypes import CDLL, Structure, POINTER
 try:
 nmlib = CDLL("libnotmuch.so.3")
 except:
-raise ImportError("Could not find shared 'notmuch' library.")
+import os.path
+path = os.path.abspath(__file__)
+while True:
+path = os.path.dirname(path)
+try:
+nmlib = CDLL(os.path.join(path, 'libnotmuch.so.3'))
+break
+except:
+if path == '/':
+raise ImportError("Could not find shared 'notmuch' library.")
 
 from .compat import Python3StringMixIn, encode_utf8 as _str
 

> Otoh, adding such behavior might be 'surprising' and lead to many
> problems down the road like spurious bug reports just because the
> magic library finder locates a rogue libnotmuch.so.3 somewhere.
>
>> An alternative would be to find libnotmuch.so using the notmuch
>> executable.
>
> How would you do that? fork'ing and exec'ing is not an option (and I'm
> not sure what one could achieve by exec'ing it, but how else would you
> talk to the dynamic linker?) , and poking around in binaries to get
> their rpath isn't either in my opinion. And you would have to locate
> the 'right' binary in the first place?

I don't like the indirection either, but the binary is compiled with
knowledge of prefix/RPATH, so if we wanted a single canonical location
to specify this information, I would make it the binary.

If you don't want to trust Python install directory hierarchy, we could
have 'setup.py install' write some info about RPATH.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [RFC/PATCH] python: search parent lib directory for libnotmuch.so

2013-04-09 Thread Jed Brown
Justus Winter <4win...@informatik.uni-hamburg.de> writes:
> But why do we do that? I always thought that rpath causes more
> problems and is to be avoided if possible [0]. But otoh, I didn't even
> knew that the notmuch build system uses rpath.
>
> 0: e.g. http://wiki.debian.org/RpathIssue

RPATH is bad for distributions, but great for private installs.

> I actually have no strong feelings for or against this proposal. I'm
> merely surprised that there is an issue that you are trying to fix
> here since exactly this configuration has worked for me since the day
> I started using notmuch.

Sure, but you always set LD_LIBRARY_PATH instead of relying on RPATH.

> And from my point of view LD_LIBRARY_PATH is the correct way to
> instruct the dynamic linker (and as a similar facility the ctypes
> library loader) where to look for additional libraries.

LD_LIBRARY_PATH is inconvenient as hell if you have multiple installs
living in different places, i.e., you write /path/to/A/bin/notmuch and
have it use /path/to/B/lib/libnotmuch.so.3 just because you placed
/path/to/B/lib in your LD_LIBRARY_PATH at some point in the distant past
when it was needed by /path/to/B/bin/other-thing that may not even be
installed any more.

This happens a lot more with languages other than C and when you have
different compilers with mutually-incompatible ABIs or packages that
didn't bother with soname versioning.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Xapian recovery after kernel oops

2013-05-09 Thread Jed Brown
My laptop had a kernel oops this morning, apparently triggered by
getting bumped (not very hard, actually).  Upon restarting, I have a
corrupt database:

  $ notmuch search tag:inbox
 
  A Xapian exception occurred opening database: The revision being read has 
been discarded - you should call Xapian::Database::reopen() and retry the 
operation

This is with Linux 3.8.11 and btrfs, though nothing else on the file
systems appears to have been affected.

  $ xapian-check Mail/.notmuch/xapian/
  Database couldn't be opened for reading: DatabaseModifiedError: The revision 
being read has been discarded - you should call Xapian::Database::reopen() and 
retry the operation
  Continuing check anyway
  Cross-checking document lengths between the postlist and termlist tables 
would use more than 1GB of memory, so skipping that check
  record:
  xapian-check: DatabaseCorruptError: Db block overwritten - are there multiple 
writers?

>From the xapian list archives, recovery doesn't look likely.  According
to this mail, it sounds like the commit should have been atomic.

  http://lists.xapian.org/pipermail/xapian-discuss/2009-September/007126.html

Is there likely to be any information in my database that would help
track down the reason why the commit was not atomic?  I don't rule out
the possibility that the corruption was entirely the kernel's fault, but
I don't want to leap to conclusions either.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH 1/1] build: remove trailing '/.' when doing mkdir -p .deps/.

2013-11-03 Thread Jed Brown
Tomi Ollila  writes:

>  %.o: %.cc $(global_deps)
> - @mkdir -p .deps/$(@D)
> + @mkdir -p $(patsubst %/.,%,.deps/$(@D))
>   $(call quiet,CXX $(CPPFLAGS) $(CXXFLAGS)) -c $(FINAL_CXXFLAGS) $< -o $@ 
> -MD -MP -MF .deps/$*.d

An alternative approach is to use directory marker files [1] to clean up
the recipes that need output directories and to satisfy Paul's second
rule of makefiles [2].

.SECONDEXPANSION:

%.o: %.cc $(global_deps) | .deps/$$(@D)/.DIR
$(call quiet,CXX $(CPPFLAGS) $(CXXFLAGS)) -c $(FINAL_CXXFLAGS) $< -o $@ 
-MD -MP -MF .deps/$*.d

%/.DIR:
@mkdir -p $(patsubst %/.,%,$(@D))
@touch $@

.PRECIOUS: %.DIR



[1] http://www.cmcrossroads.com/article/making-directories-gnu-make
[2] http://make.paulandlesley.org/rules.html


pgpBRYtw3Lebn.pgp
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] emacs: update alist for mail-archive.com API change

2014-02-11 Thread Jed Brown
Searching by Message-Id no longer works via the old mail-archive.com
API, though I have contacted them in hopes that they restore it to
prevent dead links.  Anyway, the new API is cleaner.
---
 emacs/notmuch-show.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 1ac80ca..88752f1 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -171,7 +171,7 @@ each attachment handler is logged in buffers with names 
beginning
 (defcustom notmuch-show-stash-mlarchive-link-alist
   '(("Gmane" . "http://mid.gmane.org/";)
 ("MARC" . "http://marc.info/?i=";)
-("Mail Archive, The" . "http://mail-archive.com/search?l=mid&q=";)
+("Mail Archive, The" . "http://mid.mail-archive.com/";)
 ("LKML" . "http://lkml.kernel.org/r/";)
 ;; FIXME: can these services be searched by `Message-Id' ?
 ;; ("MarkMail" . "http://markmail.org/";)
-- 
1.8.5.4

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


[PATCH] emacs: update alist for mail-archive.com API change

2014-02-13 Thread Jed Brown
Searching by Message-Id no longer works via the old mail-archive.com
API, though I have contacted them in hopes that they restore it to
prevent dead links.  Anyway, the new API is cleaner.

Acked-by: Austin Clements 
---
Fixed the test.  Thanks, David.

 emacs/notmuch-show.el | 2 +-
 test/T310-emacs.sh| 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 1ac80ca..88752f1 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -171,7 +171,7 @@ each attachment handler is logged in buffers with names 
beginning
 (defcustom notmuch-show-stash-mlarchive-link-alist
   '(("Gmane" . "http://mid.gmane.org/";)
 ("MARC" . "http://marc.info/?i=";)
-("Mail Archive, The" . "http://mail-archive.com/search?l=mid&q=";)
+("Mail Archive, The" . "http://mid.mail-archive.com/";)
 ("LKML" . "http://lkml.kernel.org/r/";)
 ;; FIXME: can these services be searched by `Message-Id' ?
 ;; ("MarkMail" . "http://markmail.org/";)
diff --git a/test/T310-emacs.sh b/test/T310-emacs.sh
index 7dc9a8e..00ae96a 100755
--- a/test/T310-emacs.sh
+++ b/test/T310-emacs.sh
@@ -727,7 +727,7 @@ inbox,stashtest
 ${gen_msg_filename}
 http://mid.gmane.org/bought
 http://marc.info/?i=bought
-http://mail-archive.com/search?l=mid&q=bought
+http://mid.mail-archive.com/bought
 EOF
 test_expect_equal_file OUTPUT EXPECTED
 
-- 
1.8.5.4

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


Emacs client scalability for long, deeply-nested threads

2015-03-23 Thread Jed Brown
I occasionally end up with threads containing several hundred messages
and deep nesting.  Eventually, displaying them exceeds the default
max-specpdl-size and later max-lisp-eval-depth.  These variables can be
increased, but the time required to display the thread stretches to
minutes.  Does anyone have suggestions for improving performance in such
scenarios?


signature.asc
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Emacs client scalability for long, deeply-nested threads

2015-03-23 Thread Jed Brown
Michael Hudson-Doyle  writes:

> I have encountered this too.  A C-u before entering the thread helps
> (this means already read messages are not rendered I think), as does a
> M-x notmuch-show-toggle-thread-indentation .  

Thanks, Michael.  This does help, though it makes it hard to interpret
context.  I'd love a solution that does not degrade utility so
drastically.


signature.asc
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: Emacs client scalability for long, deeply-nested threads

2015-03-24 Thread Jed Brown
David Bremner  writes:

> How is the performance of tree-view on these threads?

tree-view?  Loading is about equally slow with/without
notmuch-show-indent-messages-width=0.  Navigation is pretty fast once
loaded.  "notmuch show --format=sexp" for an 1100 message thread with
7.5 MB of non-attachment takes 0.5 seconds.  This thread is much too big
to display in a normal Emacs buffer, though I can see specific messages
fast using C-u (notmuch-search-show-thread ELIDE-TOGGLE).


signature.asc
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[notmuch] [PATCH] Drop redundant CFLAGS, was already included in CXXFLAGS

2009-11-20 Thread Jed Brown
---
 Makefile |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
-- next part --
A non-text attachment was scrubbed...
Name: 0001-Drop-redundant-CFLAGS-was-already-included-in-CXXFLA.patch
Type: text/x-patch
Size: 330 bytes
Desc: not available
URL: 



[notmuch] [PATCH] Quote file names passed to the shell

2009-11-21 Thread Jed Brown

Prior to this, notmuch-show-pipe-message could not handle file names
with spaces and similar.
---
 notmuch.el |3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

-- next part --
A non-text attachment was scrubbed...
Name: 0001-Quote-file-names-passed-to-the-shell.patch
Type: text/x-patch
Size: 796 bytes
Desc: not available
URL: 



[notmuch] Asynchronous tagging

2009-11-21 Thread Jed Brown
I'm really enjoying notmuch, thanks!  I have a minor issue and a couple
observations worth noting.

1. Changing tags (like removing inbox/unread) has really high latency.
For example, notmuch-show-advance-marking-read-and-archiving takes 2 to
4 seconds (by comparison, this is as long as a vague search returning
1000+ threads).  I have about 100k messages in a maildir on
linux-2.6.31-6, ext4, xapian-1.0.17.  I tried switching to the
development version of xapian, but the notmuch configure didn't pick it
up (maybe it would still work though).  Is this a known issue?  Is it
worth making certain notmuch.el operations asynchronous to hide this
latency?

2. I have 'notmuch new' in an offlineimap postsync hook, but
notmuch-search-refresh-view occasionally complains that another process
has the lock (since I might press '=' when 'notmuch new' is running).
Waiting a moment and trying again works fine, but it would be nice to
clean this up eventually.

3. I had initially put 'notmuch new' in a cron job (instead of
offlineimap postsync hook) and new/search would sometimes complain about
missing files in the maildir.  The first time this happened, it did not
correct itself and I ended up reimporting the database (I had moved some
things around so I could have been at fault).  Since then I have seen
these errors on a couple occasions, but they always go away upon
rerunning 'notmuch new'.  My guess is that it has to do with offlineimap
changing flags so I moved 'notmuch new' to the postsync hook and have
not seen the errors since.  If it is important that notmuch never runs
concurrently with an offlineimap sync, it should eventually go in the
docs.


Thanks again,

Jed


[notmuch] Asynchronous tagging

2009-11-21 Thread Jed Brown
On Sat, 21 Nov 2009 19:35:39 +0100, Jed Brown  wrote:

[...]

> 3. I had initially put 'notmuch new' in a cron job (instead of
> offlineimap postsync hook) and new/search would sometimes complain about
> missing files in the maildir.  The first time this happened, it did not
> correct itself and I ended up reimporting the database (I had moved some
> things around so I could have been at fault).  Since then I have seen
> these errors on a couple occasions, but they always go away upon
> rerunning 'notmuch new'.  My guess is that it has to do with offlineimap
> changing flags so I moved 'notmuch new' to the postsync hook and have
> not seen the errors since.  If it is important that notmuch never runs
> concurrently with an offlineimap sync, it should eventually go in the
> docs.

Actually, this popped up again.  I have a workaround, but here's the story if 
you are interested.

After changing a flag in Gmail and syncing with offlineimap, I get this
in my inbox

 Today 19:18 [1/2] (null)   (null) (inbox 
unread)

And when I try to open it, the buffer is full of stderr.

  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory

It is present in any searches that contain the problem files

  $ notmuch search tag:inbox | wc
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258826583_1.20705.kunyang,U=174235,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/.mail-archive/gmail-all/new/1258827595_0.20705.kunyang,U=174288,FMD5=844bb96d088d057aa1b32ac1fbc67b56:2,:
 No such file or directory
  Error opening 
/home/jed/

[notmuch] Asynchronous tagging

2009-11-21 Thread Jed Brown
On Sat, 21 Nov 2009 21:01:20 +0100, Carl Worth  wrote:
> Yes, this is a known bug in Xapian (it rewrites all of the indexed terms
> for the email message even though you're just trying to add/remove one
> term). The Xapian ticket for this is here:
> 
>   replace_document should make minimal changes to database file
>   http://trac.xapian.org/ticket/250

This bug report is concerned that it could require an API change, it
sounds like you think this is unnecessary.  Thanks for the detailed
explanation.

> Chris Wilson just contributed a patch to enable read-only usage of
> notmuch while another notmuch process holds the write lock.

I'm running it.

> Does offlineimap use tmp while it's delivering message and then move
> things to new? If so, then maybe all we need to do to fix notmuch to not
> look into tmp directories?

Yes, that's how maildir is supposed to work.  Deliver to tmp, hard link
from new, then unlink in tmp.  The client should never look in tmp.
Should be very quick to fix in notmuch.

Jed


[notmuch] Asynchronous tagging

2009-11-21 Thread Jed Brown
On Sat, 21 Nov 2009 21:50:10 +0100, Jan Janak  wrote:
> I get errors about missing files too. There are several reasons why
> that can happen:
> 
>  1) A message is moved from one folder to another in other mail
> clients that work with the Maildir spool.

Not a problem in my case because I currently have everything in one big
maildir (100k in one directory is a lot, but not too painful at 0.3s for
ls and 2s to stat everything).

>  2) A client changes the flags on a message, for example, when you
> read a message or mark it as deleted. Maildir stores flags in
> filenames.

This seems like a problem.  I'm not familiar with xapian, is it
necessarily an expensive operation to correct these inconsistencies?
Matching by thread id ought to be cheap.

>  3) Message flags are updated on the IMAP server (for example when you
> mark a message as read in gmail). Offlineimap keeps message flags
> synchronized.  If you mark a local message as read then the change is
> propagated to the IMAP server and vice versa.

Do you know if Offlineimap (or some similar tool) can be told not to
bother keeping flags synchronized?

Jed


[notmuch] Asynchronous tagging

2009-11-21 Thread Jed Brown
On Sat, 21 Nov 2009 22:00:13 +0100, Carl Worth  wrote:
> Ah, OK. So you made a change on the Gmail side and that caused a file to
> be renamed locally.

yes

> Or did you mean you removed the tag from within emacs? In that case, the
> search term used to find the message is the message id itself. (Try
> running "M-x visible-mode" from a notmuch-search view in emacs to see
> what those look like.)

Exactly, that's what I meant by manually.  Those messages don't match a
nice generic pattern.

> Meanwhile, just archiving the message won't make things perfect for
> you. The document in the database point to the broken file is still
> there. And it should still have all of its terms, so will likely show up
> if you do more searches. (The "(null)" stuff you're seeing isn't because
> the message is NULL---for example, notmuch was able to find the date,
> etc. It's just that notmuch couldn't find the subject and authors when
> it went to look for the file.)

Yeah.

> So if GMail+offlineimap continues to shuffle your files around, you're
> going to keep seeing more and more confusion like this buildup.
> 
> So we really just need to teach notmuch how to handle an unstable file
> store in order to be able to use it in this kind of setup.

This seems unavoidable with maildir in the presence of any
synchronization, or use of a different client.

An ugly, but possible solution would be to mirror the entire maildir via
hard links with whatever naming scheme you like.  You then have a stable
link to the file and can resolve changing names in the real maildir.
This eats up a lot of inodes.

Jed


[notmuch] [PATCH] _READ_Write -> _READ_WRITE

2009-11-21 Thread Jed Brown
---
 lib/notmuch.h |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

-- next part --
A non-text attachment was scrubbed...
Name: 0001-_READ_Write-_READ_WRITE.patch
Type: text/x-patch
Size: 403 bytes
Desc: not available
URL: 



[notmuch] 25 minutes load time with emacs -f notmuch

2009-11-21 Thread Jed Brown
On Sat, 21 Nov 2009 17:36:18 -0500, Brett Viren  
wrote:
> How can I purge the index?  I can't locate it.

I believe you can just remove /path/to/maildir/.notmuch

Jed


[notmuch] [PATCH 2/2] notmuch list: A new command to produce various lists.

2009-11-22 Thread Jed Brown
On Sun, 22 Nov 2009 00:07:57 +0100, Carl Worth  wrote:
> One thing we'll still have to think about is how to remove the "virtual
> tags" from the completion list, (once we have virtual tags in the
> configuration file---that is, tags applied automatically based on search
> specifications).

Do these need to be real tags?  Would it be sufficient for them to just
be aliases for search patterns?  I think I would prefer the latter
because I could modify the pattern and not have to rewrite tags to the
whole database.  Maybe real tags are needed to optimize expensive
patterns, but I wouldn't think the user needs to know about that.

Jed


[notmuch] Guide for new users?

2009-11-22 Thread Jed Brown
On Sun, 22 Nov 2009 09:41:16 -0500, Brett Viren  
wrote:
> On Sat, Nov 21, 2009 at 11:44 PM, Jjgod Jiang  wrote:
> 
> > 1. What's the most efficient way to sync mails from my gmail
> > account to a local Maildir? I've tried offlineimap but it
> > keeps crashing python (!) on my system (python 2.6, Mac OS X
> > 10.6.2).
> 
> OfflineIMAP would have been my suggestion.

Yes, however it will change flags which changes file names and currently
confuses notmuch.  I synced [Gmail].All Mail with OfflineIMAP and am now
using Getmail to pull via POP.  In the Gmail settings, activate POP
starting at the current time.  I'll switch back to OfflineIMAP when
notmuch is happy with changing file names.

The following should save notmuch + Gmail users some time.


~/.getmail/gmail:

[retriever]
# Getmail can also do IMAP
# type = SimpleIMAPSSLRetriever
# server = imap.gmail.com
type = SimplePOP3SSLRetriever
server = pop.gmail.com
username = yourname at gmail.com
password = Pa55W0rd
# Use this with IMAP to only download one copy of each message
# mailboxes = ('[Gmail]/All Mail',)

[destination]
type = Maildir
path = ~/.mail-archive/gmail/pop/

[options]
# print messages about each action (verbose = 2)
# Other options:
# 0 prints only warnings and errors
# 1 prints messages about retrieving and deleting messages only
verbose = 2
message_log = ~/.getmail/gmail.log


With getmail, put something like this in your crontab (checks every 2
minutes)

# MIN HOUR DAY MONTH DAYOFWEEK   COMMAND
*/2 * * * * getmail -r gmail && notmuch new




~/.offlineimaprc:

[general]
accounts = GMail
maxsyncaccounts = 1
ui = Noninteractive.Basic

[Account GMail]
localrepository = Local
remoterepository = Remote
autorefresh = 1
quick = 10
postsynchook = notmuch new

[Repository Local]
type = Maildir
localfolders = /home/jed/.mail-archive/gmail/imap

[Repository Remote]
type = Gmail
folderfilter = lambda foldername: foldername in ['[Gmail]/All Mail']
remotehost = imap.gmail.com
remoteuser = yourname at gmail.com
remotepass = Pa55W0rd
ssl = yes
maxconnections = 2

#Setting realdelete = yes will Really Delete email from the server.
#Otherwise "deleting" a message will just remove any labels and
#retain the message in the All Mail folder.
realdelete = no




Note that with IMAP, your messages in '[Gmail]/All Mail' will be
delivered to a path with spaces which notmuch handles fine, but you will
need a patch

  <1258771074-25997-1-git-send-email-jed at 59A2.org>

for start-process-shell-command, e.g. to apply patches from within emacs via

  | git am



* Sending messages

To send messages from Emacs via Gmail, put something like this in your ~/.emacs

(setq smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil)) ; Must be 
set BEFORE loading smtpmail
  smtpmail-auth-credentials (expand-file-name "~/.authinfo")
  smtpmail-default-smtp-server "smtp.gmail.com"
  smtpmail-smtp-server "smtp.gmail.com"
  smtpmail-smtp-service 587
  smtpmail-debug-info t ; change to nil once it works
  smtpmail-debug-verb t)
(require 'smtpmail)
(setq message-send-mail-function 'smtpmail-send-it)
(require 'starttls)


you can inline authentication, but especially if you keep ~/.emacs under
version control, you should put it separately (chmod 600).

~/.authinfo:

machine smtp.gmail.com login yourname at gmail.com password Pa55W0rd port 587


* Git
Git + Gmail users can use git send-email by putting this in your
.gitconfig

[sendemail]
smtpserver = smtp.gmail.com
smtpserverport = 587
smtpencryption = tls
smtpuser = yourname at gmail.com
smtppass = Pa55W0rd



I hope this helps.

Jed


[notmuch] [PATCH] Add SCons build files.

2009-11-22 Thread Jed Brown
On Sun, 22 Nov 2009 10:00:26 -0600, Jeffrey Ollie  wrote:

> Yes, I'm sure that make is widely available, but as notmuch gets used
> on a wider variety of systems some sort of configuration system will
> become necessary.  If I can prevent another project from going down
> the autoconf/automake path I'll be happy.  I started creating CMake
> build files but I don't know CMake well enough to come up with a
> working build.

I can do a CMake build if that's desirable.  While I prefer it to SCons,
particularly when config/build times are an issue and you want to have
several active build trees, it is a significantly heavier dependency.
With SCons, you can dump scons-local (a pure Python script) into the
source tree and then users only need Python.  There are lots of other
lightweight build tools.

Jed


[notmuch] [PATCH] New function notmuch-search-operate-all: operate on all messages in the current query.

2009-11-22 Thread Jed Brown
It is often convenient to change tags on several messages at once.  This
function applies any number of tag whitespace-delimited tag
modifications to all messages matching the current query.

I have bound this to `*'.

Signed-off-by: Jed Brown 
---
 notmuch.el |   24 
 1 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index a547415..b848e9a 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -764,6 +764,7 @@ thread from that buffer can be show when done with this 
one)."
 (define-key map (kbd "RET") 'notmuch-search-show-thread)
 (define-key map "+" 'notmuch-search-add-tag)
 (define-key map "-" 'notmuch-search-remove-tag)
+(define-key map "*" 'notmuch-search-operate-all)
 (define-key map "<" 'beginning-of-buffer)
 (define-key map ">" 'notmuch-search-goto-last-thread)
 (define-key map "=" 'notmuch-search-refresh-view)
@@ -940,6 +941,29 @@ This function advances point to the next line when 
finished."
   (notmuch-search-remove-tag "inbox")
   (forward-line))

+(defun notmuch-search-operate-all (action)
+  "Operate on all messages matching the current query.  Any
+number of whitespace separated actions can be given.  Each action
+must have one of the two forms
+
+  +tagname  Add the tag `tagname'
+  -tagname  Remove the tag `tagname'
+
+Each character of the tag name may consist of alphanumeric
+characters as well as `_.+-'.
+"
+  (interactive "sOperation (+add -drop): notmuch tag ")
+  (let ((action-split (split-string action " +")))
+;; Perform some validation
+(let ((words action-split))
+  (when (null words) (error "No operation given"))
+  (while words
+   (unless (string-match-p "^[\+\-][_\+\-\\w]+$" (car words))
+ (error "Action must be of the form `+thistag -that_tag'"))
+   (setq words (cdr words
+(apply 'notmuch-call-notmuch-process "tag"
+  (append action-split (list notmuch-search-query-string) nil
+
 (defun notmuch-search (query &optional oldest-first)
   "Run \"notmuch search\" with the given query string and display results."
   (interactive "sNotmuch search: ")
-- 
1.6.5.3



[notmuch] How to index /var/spool/mail with notmuch

2009-11-22 Thread Jed Brown
On Sun, 22 Nov 2009 21:24:47 +0100, Tassilo Horn  
wrote:
> Hi all,
> 
> I'd like to try out notmuch.  My mail setup is as follows:
> 
>   - I run a local IMAP server (dovecot) and access it using Gnus
>   - Dovecot stores its mails in /var/spool/mail/ in some one file per
> message format

How about

$ mkdir -p ~/mail/spool
$ ln -s /var/spool/mail/$USER/{cur,new,tmp} ~/mail/spool

and point notmuch at ~/mail (or specifically ~/mail/spool).


Jed


[notmuch] [RFC] Precedence of OR and AND

2009-11-22 Thread Jed Brown
Currently OR binds more weakly than AND, which is natural in most
contexts, but I think it is rarely desirably for this sort of search.
Suppose I am in looking at my inbox and decide to filter by

  term1 OR term2

Notmuch makes the query

  tag:inbox AND term1 OR term2

which is actually

  (tag:inbox AND term1) OR term2

and not at all what I wanted.  Adding the necessary parentheses to
notmuch-search-filter is trivial but it requires more parentheses for
the overwhelming majority of searches that I think are more common.

Are most searches indeed closer to conjunctive form?

Should OR bind tighter than AND?


Jed


[notmuch] [RFC] Precedence of OR and AND

2009-11-22 Thread Jed Brown
On Sun, 22 Nov 2009 16:36:49 -0500, Bart Trojanowski  wrote:
> Wouldn't this problem be solved by each filter appending a bracketed
> version of your filter?
> 
> You start with tag:inbox and you filter on "term1 or term2" you'd get:
> 
> tag:inbox and (term1 or term2)

Absolutely, and I have this applied locally to notmuch.el, but I didn't
fix notmuch-search-filter-by-tag because that would really need to parse
the expression.  I'm just asking if anyone else thinks binding OR
tighter than AND would be desirable.

Jed


[notmuch] Catching up unread messages

2009-11-22 Thread Jed Brown
On Sun, 22 Nov 2009 22:48:52 +0100, Tassilo Horn  
wrote:
> Ok, so new the question: I indexed all my 63.000 mails, and because it
> was a first-time indexing, all my mail now has the tags inbox and
> unread.  Of course, I don't want to SPC through all threads (using the
> great emacs interface) to remove the unread status.  So is there some
> catchup command, which marks all messages in the buffer as read?

With this patch

  <1258920736-14205-1-git-send-email-jed at 59A2.org>

you would do

  * -inbox

or

  * -inbox -unread

On the command line, you can clear it with

$ notmuch tag -inbox tag:inbox

> BTW, what's the intention of the inbox tag?  When I've read a thread,
> both inbox as well as unread disappear, so I don't get the difference
> between them.

That is because SPC is bound to
notmuch-show-advance-marking-read-and-archiving which removes both tags.
The idea is that you can clear your inbox while retaining unread status,
or leave something important in your inbox even though you have read it.

Jed


[notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-11-23 Thread Jed Brown
notmuch-search-filter accepts now accepts an arbitrary query and will
group if necessary so that we get

  tag:inbox AND (gravy OR biscuits)

notmuch-search-filter-tag now handles multiple terms.  All terms in the
query except AND and OR are interpreted as tags.

Signed-off-by: Jed Brown 
---
 notmuch.el |   23 ++-
 1 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 0cabbe2..43e0566 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -1057,15 +1057,28 @@ search."
 Runs a new search matching only messages that match both the
 current search results AND the additional query string provided."
   (interactive "sFilter search: ")
-  (notmuch-search (concat notmuch-search-query-string " and " query) 
notmuch-search-oldest-first))
+  (let ((grouped-query (if (string-match-p "\\<[oO][rR]\\>" query) (concat "( 
" query " )") query)))
+(notmuch-search (concat notmuch-search-query-string " and " grouped-query) 
notmuch-search-oldest-first)))

-(defun notmuch-search-filter-by-tag (tag)
-  "Filter the current search results based on a single tag.
+(defun notmuch-search-filter-by-tag (query)
+  "Filter the current search results based on one or more tags.

 Runs a new search matching only messages that match both the
-current search results AND that are tagged with the given tag."
+current search results AND that are tagged with the given
+expression involving tags.  For example, the input
+
+  chicken and (gravy or biscuits)
+
+will filter the current search by
+
+  tag:chicken and ( tag:gravy or tag:biscuits )"
   (interactive "sFilter by tag: ")
-  (notmuch-search (concat notmuch-search-query-string " and tag:" tag) 
notmuch-search-oldest-first))
+  (let ((tagged-query (replace-regexp-in-string "\\([_\+\-]\\|\\w\\)+"
+   (lambda (match) ; Prepend 
`tag:' to all matches except AND and OR
+ (if (string-match-p 
"\\([aA][nN][dD]\\)\\|\\([oO][rR]\\)" match)
+ match (concat "tag:" 
match)))
+   query)))
+(notmuch-search-filter tagged-query)))

 (defun notmuch ()
   "Run notmuch to display all mail with tag of 'inbox'"
-- 
1.6.5.3



[notmuch] [PATCH] New function notmuch-search-operate-all: operate on all messages in the current query.

2009-11-23 Thread Jed Brown
On Mon, 23 Nov 2009 05:14:25 +0100, Carl Worth  wrote:
> Second, I like that you just used the search string again, (as opposed
> to just walking through the buffer looking at thread IDs). That seems
> elegant.

It was *easy*.

> First, this creates a race condition in that the user will rightly
> expect to only be adding/removing tags from the visible results. But if
> new mail has been incorporated between creating the current view and
> running '*' then threads could be tagged that were never seen and that
> could be problematic.

Agreed and I had also thought of the case you described.  Note that
Gmail does not solve the race condition.  When in summary mode:

* Marking a thread as read applies to all messages in the thread.  The
  thread contents are being updated concurrently so you may mark threads
  you have already seen.

* Same story with archiving (aka. remove inbox).

* Starring a thread applies to the last message in the thread, this
  could be a newly arrived message that is not currently displayed.

I think that handling a concurrent changes to the match results is a
somewhat hard problem.  You have to store the message ids of everything
in the current query if you want to avoid the race.

> Second, since we're in the search view which shows threads, we should
> really be operating on threads. But this tag command won't work like the
> '+' and '-' commands in this buffer. Those commands will add/remove a
> tag to/from every message in the thread[*]. The new '*' command, however
> will only be changing tags on messages that match the query.

I'm not convinced that we want to operate on the entire thread.
Applying the tag only to the matched messages is enough to find the
thread, and it may really be desirable to only have it applied to
certain messages in the thread.  For example, I might have constructed
an elaborate query to find five messages, including a couple that are
burried in 100-message threads in which case I would definitely not want
to tag entire threads.

> So I think we should fix both of these issues by looping over each line
> of the buffer and calling (notmuch-search-add-tag) or
> (notmuch-search-remove-tag).

Presumably you don't mean this literally because that would be horribly
slow.  What you want is to gather up all the message ids in all the
threads with at least one message matching the current query (and
currently displayed).  I think this is only possible if notmuch-search
holds message IDs for everything in the matched threads.  If we are
happy to just tag the matched messages instead of the entire thread, we
would only store the message ids for the matched messages.

> Oh, here's one: We could add something like "notmuch tag --expecting=
> 1/23 " that would not do the tag unless the search string
> matched 1 message out of 23 total messages in the thread. Then we could
> give a warning to the user.

I like this, but it still presents a minor race condition (suppose
another client swaps the unread tag on two messages in the same thread).
The only way to guarantee that you are operating on the displayed
messages is to store their message ids.

> That works for the single-thread case, but the warning would be harder
> for the user to deal with in the '*' case. Or maybe not---the emacs
> function could just stop on the first line with the error and then the
> user would see what's going on.

If you can implement notmuch tag --expecting with similar efficiency to
the present, then I would vote for notifying the user and asking for
confirmation if the number of matches has changed.  This would be
significantly safer than what Gmail does which ought to be sufficient
for now given the age of notmuch.


Jed


[notmuch] [PATCH 1/2] * avoid gcc 4.4.1 compiler warnings due to ignored write return values

2009-11-23 Thread Jed Brown
On Mon, 23 Nov 2009 14:19:18 +0100, Karl Wiberg  wrote:
> On Mon, Nov 23, 2009 at 12:11 PM, Dirk-Jan Binnema  
> wrote:
> 
> > On Mon, Nov 23, 2009 at 9:34 AM, Karl Wiberg  wrote:
> >
> > > Didn't the "(void)" suggestion work?
> >
> > I actually preferred that solution, but unfortunately, it didn't
> > stop gcc from complaining...
> 
> Hmpf. I'd argue that that's a gcc bug, forcing the user to use an
> unnecessarily complicated way to pretend to use the return value. Oh
> well.

>From the gcc man page:

   -Wunused-value
   Warn whenever a statement computes a result that is explicitly
   not used. To suppress this warning cast the unused expression
   to void. This includes an expression-statement or the left-
   hand side of a comma expression that contains no side effects.
   For example, an expression such as x[i,j] will cause a
   warning, while x[(void)i,j] will not.

   This warning is enabled by -Wall.


But I'm confused here because I don't currently see any warnings with
gcc-4.4.2.  Actually this must be a bug because I get no warnings for
the blatantly unused

  malloc(5);

with -Wall -Wextra -pedantic.  Anyway, if your system headers specify
__attribute__((warn_unused_result)) for write, then you could be running
into this bug/feature

  http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35579


Jed


[notmuch] Notmuch doesn't index new mails when mail location contains symlinks

2009-11-23 Thread Jed Brown
On Mon, 23 Nov 2009 15:43:41 +0100, Tassilo Horn  
wrote:
> First, I only touched the two symlinks.

Unfortunately, this actually touched the file pointed to by the symlink,
if you stat the symlink you will see that mtime did not change.

> This didn't help.  Then I used
> "find . -type d | xargs touch" to touch all directories inside the
> directories the symlinks point to.

Actually, this would not have followed the symlinks so it does the same
thing as before.  I think it is actually hard (or not possible) to
change mtime on symlinks under Linux.

> But still no luck.  Finally, I deleted the symlinks and created them
> anew, and then it indexed the 12 new mails that arrived in the
> meantime.

If /var is on the same filesystem, you could use hard links instead of
symlinks.  Otherwise I would just add the appropriate ln -sf in the hook
before notmuch new.

The real solution is for notmuch to check mtime of whatever the
symlink's target.

Jed


[notmuch] Notmuch doesn't index new mails when mail location contains symlinks

2009-11-23 Thread Jed Brown
On Mon, 23 Nov 2009 16:01:41 +0100, Tassilo Horn  
wrote:
> Tassilo Horn  writes:

> I don't have to touch the symlinks or the directories inside the
> locations the symlinks point to, but instead I have to touch the
> top-level directory where the symlinks are contained in.

Ah, it's slightly more subtle.  Notmuch correctly uses stat() instead of
lstat() to check whether the link target changed.  However, mtime for
your mail root directory (containing the symlinks) does not get updated
when the target of the symlinks is updated.  I think the only way to fix
this is to replace the current search (which skips a directory as soon
as it's mtime is older than the database) with one that enters all
directories so that symlinks are actually followed.

Jed


[notmuch] [PATCH 1/2] * avoid gcc 4.4.1 compiler warnings due to ignored write return values

2009-11-23 Thread Jed Brown
On Mon, 23 Nov 2009 18:14:12 +0200, Dirk-Jan Binnema  
wrote:
> Did you try it with -O2? Without optimizations many of the warnings are not
> issued.

Yes,

$ cat > foo.c
#include 
#include 
int main()
{
  malloc(5);
  write(2,0,10);
  return 0;
}
$ gcc -static -std=c89 -O0 -Wall -Wextra -pedantic -o foo foo.c
$ objdump -d -M intel foo |grep -A12 ''
004002a4 :
  4002a4:   55  push   rbp
  4002a5:   48 89 e5movrbp,rsp
  4002a8:   bf 05 00 00 00  movedi,0x5
  4002ad:   e8 6e 61 00 00  call   406420 <__libc_malloc>
  4002b2:   ba 0a 00 00 00  movedx,0xa
  4002b7:   be 00 00 00 00  movesi,0x0
  4002bc:   bf 02 00 00 00  movedi,0x2
  4002c1:   e8 ea a0 00 00  call   40a3b0 <__libc_write>
  4002c6:   b8 00 00 00 00  moveax,0x0
  4002cb:   c9  leave  
  4002cc:   c3  ret
  4002cd:   90  nop
$ gcc -v
Using built-in specs.
Target: x86_64-unknown-linux-gnu
Configured with: ../configure --prefix=/usr --enable-shared 
--enable-languages=c,c++,fortran,objc,obj-c++,ada --enable-threads=posix 
--mandir=/usr/share/man --infodir=/usr/share/info --enable-__cxa_atexit 
--disable-multilib --libdir=/usr/lib --libexecdir=/usr/lib --enable-clocale=gnu 
--disable-libstdcxx-pch --with-tune=generic
Thread model: posix
gcc version 4.4.2 (GCC)
$ uname -a
Linux kunyang 2.6.31-ARCH #1 SMP PREEMPT Tue Nov 10 19:01:40 CET 2009 x86_64 
Intel(R) Core(TM)2 Duo CPU P8700 @ 2.53GHz GenuineIntel GNU/Linux


Seems fishy.

Jed


[notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-11-23 Thread Jed Brown
notmuch-search-filter accepts now accepts an arbitrary query and will
group if necessary so that we get

  tag:inbox AND (gravy OR biscuits)

notmuch-search-filter-tag now handles multiple terms.  All terms in the
query except AND and OR are interpreted as tags.

This version has nice regexes and handles NOT.

Signed-off-by: Jed Brown 
---
 notmuch.el |   27 ++-
 1 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 0cabbe2..fdd30ae 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -828,6 +828,10 @@ thread from that buffer can be show when done with this 
one)."
 (defvar notmuch-search-query-string)
 (defvar notmuch-search-oldest-first)

+(defvar notmuch-search-boolean-operator-regexp 
"\\([aA][nN][dD]\\|[oO][rR]\\|[nN][oO][tT]\\)")
+(defvar notmuch-search-valid-term-regexp   "\\([-+_.[:word:]]+\\)")
+(defvar notmuch-search-disjunctive-regexp  "\\<[oO][rR]\\>")
+
 (defun notmuch-search-scroll-up ()
   "Scroll up, moving point to last message in thread if at end."
   (interactive)
@@ -1057,15 +1061,28 @@ search."
 Runs a new search matching only messages that match both the
 current search results AND the additional query string provided."
   (interactive "sFilter search: ")
-  (notmuch-search (concat notmuch-search-query-string " and " query) 
notmuch-search-oldest-first))
+  (let ((grouped-query (if (string-match-p notmuch-search-disjunctive-regexp 
query) (concat "( " query " )") query)))
+(notmuch-search (concat notmuch-search-query-string " and " grouped-query) 
notmuch-search-oldest-first)))

-(defun notmuch-search-filter-by-tag (tag)
-  "Filter the current search results based on a single tag.
+(defun notmuch-search-filter-by-tag (query)
+  "Filter the current search results based on one or more tags.

 Runs a new search matching only messages that match both the
-current search results AND that are tagged with the given tag."
+current search results AND that are tagged with the given
+expression involving tags.  For example, the input
+
+  chicken and (gravy or biscuits)
+
+will filter the current search by
+
+  tag:chicken and ( tag:gravy or tag:biscuits )"
   (interactive "sFilter by tag: ")
-  (notmuch-search (concat notmuch-search-query-string " and tag:" tag) 
notmuch-search-oldest-first))
+  (let ((tagged-query (replace-regexp-in-string 
notmuch-search-valid-term-regexp
+   (lambda (match) ; Prepend 
`tag:' to all except boolean operators
+ (if (string-match-p 
notmuch-search-boolean-operator-regexp match)
+ match (concat "tag:" 
match)))
+   query)))
+(notmuch-search-filter tagged-query)))

 (defun notmuch ()
   "Run notmuch to display all mail with tag of 'inbox'"
-- 
1.6.5.3



[notmuch] [PATCH] Make addresses case insensitive for the purpose of constructing replies.

2009-11-23 Thread Jed Brown
The domain is alway case insensitive, but in principle the username is
case sensitive.  Few systems actually enforce this so I think a good
default is to treat the entire address as case insensitive, it will
eliminate a lot of superfluous self-addressed messages and reply from
the correct address in these cases.

Signed-off-by: Jed Brown 
---
 notmuch-reply.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 44e1766..cd81e76 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -97,12 +97,12 @@ address_is_users (const char *address, notmuch_config_t 
*config)
 size_t i, other_len;

 primary = notmuch_config_get_user_primary_email (config);
-if (strcmp (primary, address) == 0)
+if (strcasecmp (primary, address) == 0)
return 1;

 other = notmuch_config_get_user_other_email (config, &other_len);
 for (i = 0; i < other_len; i++)
-   if (strcmp (other[i], address) == 0)
+   if (strcasecmp (other[i], address) == 0)
return 1;

 return 0;
-- 
1.6.5.3



[notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-11-23 Thread Jed Brown
On Mon, 23 Nov 2009 10:26:47 -0800, Keith Packard  wrote:

> Remember to split patches which do more than one thing into separate
> commits.

These are variants of the same operation, but I'll split in the future.

> > +  (let ((grouped-query (if (string-match-p 
> > notmuch-search-disjunctive-regexp query) (concat "( " query " )") query)))
> > +(notmuch-search (concat notmuch-search-query-string " and " 
> > grouped-query) notmuch-search-oldest-first)))
> 
> Is there some reason not to just always add the parens?

That's what I did initially, but it's messy to look at in the mode line
after applying successive filters.

> This seems useful; how does it deal with the tag completion stuff?

It doesn't do anything special, but I haven't been following that
carefully.  My thought was that eventually the regular interactive
search and filters, would have semantic completion, e.g. the user enters

  tag:ab

and tags would be completed, but they could also do

  from:long.unwieldy.addr

In filter-by-tag, the natural thing would be to only complete tags, the
user would be on their own to spell out AND, OR, and NOT.  Unfortunately
I'm not familiar enough with elisp to implement this quickly.

A closely related issue is managing the address book.  I guess the usual
advice is to use BBDB.  I don't know if it's better to hook into that or
for Notmuch to have it's own lightweight approach.  I could imagine
harvesting addresses of everyone I've sent mail to and giving me a
semi-automated way to merge addresses that are likely to point to the
same person.


Jed


[notmuch] [PATCH] Stay out of tmp to respect the Maildir spec.

2009-11-23 Thread Jed Brown
---
 notmuch-new.c |1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/notmuch-new.c b/notmuch-new.c
index 8172b49..e32b92a 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -159,6 +159,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 * user specify files to be ignored. */
if (strcmp (entry->d_name, ".") == 0 ||
strcmp (entry->d_name, "..") == 0 ||
+   strcmp (entry->d_name, "tmp") == 0 ||
strcmp (entry->d_name, ".notmuch") ==0)
{
continue;
-- 
1.6.5.3



[notmuch] notmuch 'index' mode.

2009-11-24 Thread Jed Brown
On Mon, 23 Nov 2009 19:43:26 -0800, Keith Packard  wrote:
> On Mon, 23 Nov 2009 19:16:54 -0800, Carl Worth  wrote:
> > Then tags become something that are just for manual manipulation. What
> > do you think?

I really think this is the way to go.

> And disadvantages as searching might actually be slow at some point?

If this happens, there is nothing to prevent notmuch from caching the
search by actually writing a corresponding tag.  This could be made
automatic by logging the cost of each named search (and perhaps the
frequency of making that search), and using a tradeoff function to
decide which searches to optimize.  Once a search was selected for
optimization, there are at least two alternatives, depending on which
queries xapian can answer quickly.

  1. Log the time and spawn an asynchronous notmuch tag process.  Searches
  for

vtag:named-search

  (vtag: doesn't need to be a keyword, but I'm only distinguishing here
  for clarity) which was normally translated into

 long search expression

  becomes

tag:named-search OR newer:timestamp AND (long search expression)

  This option guarantees that notmuch new remains fast and simple because
  it does no special tagging, but this query might not be any better.

  2. Inform notmuch new that it should apply the chosen tag to messages
  matching the query and spawn the asynchronous notmuch tag process.  Once
  the tag process has finished, searches for vtag:named-search are
  translated to tag:named-search.  This implies concurrent modification of
  the database, otherwise it would cause a stall in incoming mail (not
  important if mass tagging somehow became faster).


Admittedly my archive is not huge (100k messages in 3.5 GB plus 1.1 GB
for .notmuch) but queries returning a reasonable number of messages are
still quite fast.  Additionally, searches for tags do not seem to be
greatly faster than queries for complex queries returning a similar
number of results.

Jed


[notmuch] notmuch 'index' mode.

2009-11-24 Thread Jed Brown
On Tue, 24 Nov 2009 08:38:20 -0800, Keith Packard  wrote:
> A disadvantage I see is that you would not see this 'virtual tags' in
> the list of tags on each message.

Is it not cheap to check the current search results against the vtags
(named searches) that you have defined.  Then you can show them right up
there with the real tags.

Jed


[notmuch] [PATCH] New function notmuch-show-kill-message-id, puts current message ID in the kill ring.

2009-11-24 Thread Jed Brown
This is useful any time you want to explicitly refer to the message,
such as in the body of another message, through git format-patch, or on
IRC.

It is bound to "C-c i".

Signed-off-by: Jed Brown 
---
 notmuch.el |   12 
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index fa6e7de..071ee5a 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -84,6 +84,7 @@
 (define-key map "?" 'describe-mode)
 (define-key map (kbd "TAB") 'notmuch-show-next-button)
 (define-key map (kbd "M-TAB") 'notmuch-show-previous-button)
+(define-key map (kbd "C-c i") 'notmuch-show-kill-ring-save-message-id)
 map)
   "Keymap for \"notmuch show\" buffers.")
 (fset 'notmuch-show-mode-map notmuch-show-mode-map)
@@ -698,6 +699,17 @@ which this thread was originally shown."
   (force-window-update)
   (redisplay t))

+(defun notmuch-show-kill-ring-save-message-id ()
+  "Put the current message id in the kill ring.
+
+This is useful for referencing messages or running external
+queries."
+  (interactive)
+  (let ((message-id (notmuch-show-get-message-id)))
+(kill-new message-id)
+(when (called-interactively-p 'interactive)
+  (message "Saved message ID: \"%s\"" message-id
+
 ;;;###autoload
 (defun notmuch-show-mode ()
   "Major mode for viewing a thread with notmuch.
-- 
1.6.5.3



[notmuch] [PATCH] New function notmuch-show-kill-ring-save-message-id.

2009-11-24 Thread Jed Brown
Puts current message ID in the kill ring.  This is useful any time you
want to explicitly refer to the message, such as in the body of another
message, through git format-patch, or on IRC.

It is bound to "C-c i".

Corrected spelling of function name in commit message, and updated to
apply against HEAD after c1e16435cfe4471c3415d9f625f7230d59c8afb4

Signed-off-by: Jed Brown 
---
 notmuch.el |   12 
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 907df2c..e3e0e06 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -80,6 +80,7 @@
 (define-key map "?" 'describe-mode)
 (define-key map (kbd "TAB") 'notmuch-show-next-button)
 (define-key map (kbd "M-TAB") 'notmuch-show-previous-button)
+(define-key map (kbd "C-c i") 'notmuch-show-kill-ring-save-message-id)
 map)
   "Keymap for \"notmuch show\" buffers.")
 (fset 'notmuch-show-mode-map notmuch-show-mode-map)
@@ -663,6 +664,17 @@ which this thread was originally shown."
   (notmuch-show-markup-message)))
   (notmuch-show-hide-markers))

+(defun notmuch-show-kill-ring-save-message-id ()
+  "Put the current message id in the kill ring.
+
+This is useful for referencing messages or running external
+queries."
+  (interactive)
+  (let ((message-id (notmuch-show-get-message-id)))
+(kill-new message-id)
+(when (called-interactively-p 'interactive)
+  (message "Saved message ID: \"%s\"" message-id
+
 ;;;###autoload
 (defun notmuch-show-mode ()
   "Major mode for viewing a thread with notmuch.
-- 
1.6.5.3



[notmuch] [PATCH] New function notmuch-show-kill-ring-save-message-id.

2009-11-24 Thread Jed Brown
It turns out that this ID has id: prefixed (which I thought was fine
because I'm frequently doing another query with it).  But git send-email
doesn't strip that, so this was not threaded correctly.  Would this be
better with the id: prefix stripped?

Jed


[notmuch] Notmuch-side support for git send-email --notmuch id:

2009-11-25 Thread Jed Brown
These two patches provide support for features like the one in the
subject line.  Along with these two patches, I have one for git
format-patch (which I will submit upstream soon) that uses the output
from notmuch reply --format=headers-only to build a reply with proper
referencing, To, and Cc fields.

Since options for git send-email are passed to git format-patch,

  git send-email --notmuch id:

is a substitute for

  git send-email --in-reply-to  --to  --cc  --add-header 
'References: ...'




[notmuch] [PATCH 1/2] notmuch-reply.c: accept the --format=default default option.

2009-11-25 Thread Jed Brown
This factors actual generation of the reply out of notmuch_reply_command
into notmuch_reply_format_default(), in preparation for other --format=
options.

Signed-off-by: Jed Brown 
---
 notmuch-reply.c |  121 +++---
 1 files changed, 78 insertions(+), 43 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 65bd356..17eb38d 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -23,6 +23,17 @@
 #include "notmuch-client.h"
 #include "gmime-filter-reply.h"

+static const struct {
+const char *header;
+const char *fallback;
+GMimeRecipientType recipient_type;
+} reply_to_map[] = {
+{ "reply-to", "from", GMIME_RECIPIENT_TYPE_TO  },
+{ "to", NULL, GMIME_RECIPIENT_TYPE_TO  },
+{ "cc", NULL, GMIME_RECIPIENT_TYPE_CC  },
+{ "bcc",NULL, GMIME_RECIPIENT_TYPE_BCC }
+};
+
 static void
 reply_part_content (GMimeObject *part)
 {
@@ -182,58 +193,17 @@ add_recipients_for_string (GMimeMessage *message,
 return add_recipients_for_address_list (message, config, type, list);
 }

-int
-notmuch_reply_command (void *ctx, int argc, char *argv[])
+static int
+notmuch_reply_format_default(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query)
 {
-notmuch_config_t *config;
-notmuch_database_t *notmuch;
-notmuch_query_t *query;
 GMimeMessage *reply;
-char *query_string;
 notmuch_messages_t *messages;
 notmuch_message_t *message;
-int ret = 0;
 const char *subject, *recipients, *from_addr = NULL;
 const char *in_reply_to, *orig_references, *references;
 char *reply_headers;
-struct {
-   const char *header;
-   const char *fallback;
-   GMimeRecipientType recipient_type;
-} reply_to_map[] = {
-   { "reply-to", "from", GMIME_RECIPIENT_TYPE_TO  },
-   { "to", NULL, GMIME_RECIPIENT_TYPE_TO  },
-   { "cc", NULL, GMIME_RECIPIENT_TYPE_CC  },
-   { "bcc",NULL, GMIME_RECIPIENT_TYPE_BCC }
-};
 unsigned int i;

-config = notmuch_config_open (ctx, NULL, NULL);
-if (config == NULL)
-   return 1;
-
-query_string = query_string_from_args (ctx, argc, argv);
-if (query_string == NULL) {
-   fprintf (stderr, "Out of memory\n");
-   return 1;
-}
-
-if (*query_string == '\0') {
-   fprintf (stderr, "Error: notmuch reply requires at least one search 
term.\n");
-   return 1;
-}
-
-notmuch = notmuch_database_open (notmuch_config_get_database_path (config),
-NOTMUCH_DATABASE_MODE_READ_ONLY);
-if (notmuch == NULL)
-   return 1;
-
-query = notmuch_query_create (notmuch, query_string);
-if (query == NULL) {
-   fprintf (stderr, "Out of memory\n");
-   return 1;
-}
-
 for (messages = notmuch_query_search_messages (query);
 notmuch_messages_has_more (messages);
 notmuch_messages_advance (messages))
@@ -310,6 +280,71 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])

notmuch_message_destroy (message);
 }
+return 0;
+}
+
+int
+notmuch_reply_command (void *ctx, int argc, char *argv[])
+{
+notmuch_config_t *config;
+notmuch_database_t *notmuch;
+notmuch_query_t *query;
+char *opt, *query_string;
+int i, ret = 0;
+int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query);
+
+reply_format_func = notmuch_reply_format_default;
+
+for (i = 0; i < argc && argv[i][0] == '-'; i++) {
+   if (strcmp (argv[i], "--") == 0) {
+   i++;
+   break;
+   }
+if (STRNCMP_LITERAL (argv[i], "--format=") == 0) {
+   opt = argv[i] + sizeof ("--format=") - 1;
+   if (strcmp (opt, "default") == 0) {
+   reply_format_func = notmuch_reply_format_default;
+   } else {
+   fprintf (stderr, "Invalid value for --format: %s\n", opt);
+   return 1;
+   }
+   } else {
+   fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
+   return 1;
+   }
+}
+
+argc -= i;
+argv += i;
+
+config = notmuch_config_open (ctx, NULL, NULL);
+if (config == NULL)
+   return 1;
+
+query_string = query_string_from_args (ctx, argc, argv);
+if (query_string == NULL) {
+   fprintf (stderr, "Out of memory\n");
+   return 1;
+}
+
+if (*query_string == '\0') {
+   fprintf (stderr, "Error: notmuch reply requires at least one search 
term.\n");
+   return 1;
+}
+
+notmuch = notmuch_database_open (notmuch_config_get_database_path (config),
+NOTMUCH_DATABASE_MODE_READ_ONLY);
+ 

[notmuch] [PATCH 2/2] notmuch-reply.c: implement notmuch_reply_format_headers_only

2009-11-25 Thread Jed Brown
This command only generates References, To, and Cc headers.
The purpose is primarily for use in

  git send-email --notmuch id:

to get proper threading and address the relevant parties.  Hooks for
other SCMs may come later.

Signed-off-by: Jed Brown 
---
 notmuch-reply.c |   70 +++
 1 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 17eb38d..e85568c 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -283,6 +283,74 @@ notmuch_reply_format_default(void *ctx, notmuch_config_t 
*config, notmuch_query_
 return 0;
 }

+/* This format is currently tuned for a git send-email --notmuch hook */
+static int
+notmuch_reply_format_headers_only(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query)
+{
+GMimeMessage *reply;
+notmuch_messages_t *messages;
+notmuch_message_t *message;
+const char *recipients, *in_reply_to, *orig_references, *references;
+char *reply_headers;
+unsigned int i;
+
+for (messages = notmuch_query_search_messages (query);
+notmuch_messages_has_more (messages);
+notmuch_messages_advance (messages))
+{
+   message = notmuch_messages_get (messages);
+
+   /* The 0 means we do not want headers in a "pretty" order. */
+   reply = g_mime_message_new (0);
+   if (reply == NULL) {
+   fprintf (stderr, "Out of memory\n");
+   return 1;
+   }
+
+   in_reply_to = talloc_asprintf (ctx, "<%s>",
+notmuch_message_get_message_id (message));
+
+   orig_references = notmuch_message_get_header (message, "references");
+
+   /* We print References first because git format-patch treats it 
specially.
+* Git uses the first entry of References to create In-Reply-To.
+*/
+   references = talloc_asprintf (ctx, "%s%s%s",
+ in_reply_to,
+ orig_references ? orig_references : "",
+ orig_references ? " " : "");
+   g_mime_object_set_header (GMIME_OBJECT (reply),
+ "References", references);
+
+   for (i = 0; i < ARRAY_SIZE (reply_to_map); i++) {
+   const char *addr;
+
+   recipients = notmuch_message_get_header (message,
+reply_to_map[i].header);
+   if ((recipients == NULL || recipients[0] == '\0') && 
reply_to_map[i].fallback)
+   recipients = notmuch_message_get_header (message,
+
reply_to_map[i].fallback);
+
+   addr = add_recipients_for_string (reply, config,
+ reply_to_map[i].recipient_type,
+ recipients);
+   }
+
+   g_mime_object_set_header (GMIME_OBJECT (reply), "Bcc",
+  notmuch_config_get_user_primary_email (config));
+
+   reply_headers = g_mime_object_to_string (GMIME_OBJECT (reply));
+   printf ("%s", reply_headers);
+   free (reply_headers);
+
+   g_object_unref (G_OBJECT (reply));
+   reply = NULL;
+
+   notmuch_message_destroy (message);
+}
+return 0;
+}
+
 int
 notmuch_reply_command (void *ctx, int argc, char *argv[])
 {
@@ -304,6 +372,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
opt = argv[i] + sizeof ("--format=") - 1;
if (strcmp (opt, "default") == 0) {
reply_format_func = notmuch_reply_format_default;
+   } else if (strcmp (opt, "headers-only") == 0) {
+   reply_format_func = notmuch_reply_format_headers_only;
} else {
fprintf (stderr, "Invalid value for --format: %s\n", opt);
return 1;
-- 
1.6.5.3



[notmuch] [PATCH 1/2] reply --format=headers-only: set In-Reply-To header, with ID *last* in References

2009-11-25 Thread Jed Brown
Apparently this is actually the correct way to do it, it's silly to do
it wrong just to conform to one of git's internal data structures.
---
 notmuch-reply.c |   12 
 1 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index e85568c..9ca1236 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -310,15 +310,19 @@ notmuch_reply_format_headers_only(void *ctx, 
notmuch_config_t *config, notmuch_q
in_reply_to = talloc_asprintf (ctx, "<%s>",
 notmuch_message_get_message_id (message));

+g_mime_object_set_header (GMIME_OBJECT (reply),
+ "In-Reply-To", in_reply_to);
+
+
orig_references = notmuch_message_get_header (message, "references");

-   /* We print References first because git format-patch treats it 
specially.
-* Git uses the first entry of References to create In-Reply-To.
+   /* We print In-Reply-To followed by References because git format-patch 
treats them
+ * specially.  Git does not interpret the other headers specially
 */
references = talloc_asprintf (ctx, "%s%s%s",
- in_reply_to,
  orig_references ? orig_references : "",
- orig_references ? " " : "");
+ orig_references ? " " : "",
+ in_reply_to);
g_mime_object_set_header (GMIME_OBJECT (reply),
  "References", references);

-- 
1.6.5.3



[notmuch] [PATCH 2/2] Recognize reply --format=headers-only-git

2009-11-25 Thread Jed Brown
This currently means the same thing as --format=headers-only, but this
name gives more freedom to change --format=headers-only without breaking
existing versions of git.
---
 notmuch-reply.c |3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 9ca1236..2b16dae 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -376,7 +376,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
opt = argv[i] + sizeof ("--format=") - 1;
if (strcmp (opt, "default") == 0) {
reply_format_func = notmuch_reply_format_default;
-   } else if (strcmp (opt, "headers-only") == 0) {
+   } else if (strcmp (opt, "headers-only") == 0 ||
+  strcmp (opt, "headers-only-git") == 0) {
reply_format_func = notmuch_reply_format_headers_only;
} else {
fprintf (stderr, "Invalid value for --format: %s\n", opt);
-- 
1.6.5.3



[notmuch] Notmuch doesn't index new mails when mail location contains symlinks

2009-11-26 Thread Jed Brown
On Thu, 26 Nov 2009 10:34:12 -0800, Carl Worth  wrote:
> I'm a little confused here. Notmuch only uses stat, so it should be
> looking at the target's mtime already. It actually takes special effort
> (via lstat) to get at the mtime of the link itself.
> 
> So why aren't things just working?

Because mtime doesn't change on the directory *above* the symlinks.

I think.

Jed


[notmuch] Notmuch doesn't index new mails when mail location contains symlinks

2009-11-26 Thread Jed Brown
On Thu, 26 Nov 2009 13:14:22 -0800, Carl Worth  wrote:

> Then I'm still being really dense here. The non-propagation of mtime is
> the with actual directories. And the code is trying to do the right
> thing for that.

The stat() is correct, it's the check for the d_type field coming out of 
scandir().

20:08 [   jedbrown  ] cworth: I think there are two problems with symlinks.
20:08 [   jedbrown  ] cworth: First, notmuch-new.c:152 checks path_mtime which 
is mtime for the current directory.
20:09 [   jedbrown  ] cworth: Additionally, won't entry->d_type == DT_LNK for a 
symlink?
20:14 [ aneesh  ] jedbrown,  i already have a patch posted for that
20:15 [ aneesh  ] 1259125104-18785-1-git-send-email-aneesh.kumar at 
linux.vnet.ibm.com


Jed


[notmuch] [PATCH 1/2] New function notmuch-search-operate-all: operate on all messages in the current query.

2009-11-26 Thread Jed Brown
It is often convenient to change tags on several messages at once.  This
function applies any number of tag whitespace-delimited tag
modifications to all messages matching the current query.

I have bound this to `*'.

Signed-off-by: Jed Brown 
---
 notmuch.el |   24 
 1 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index d7c973c..6adac9e 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -801,6 +801,7 @@ thread from that buffer can be show when done with this 
one)."
 (define-key map [mouse-1] 'notmuch-search-show-thread)
 (define-key map "+" 'notmuch-search-add-tag)
 (define-key map "-" 'notmuch-search-remove-tag)
+(define-key map "*" 'notmuch-search-operate-all)
 (define-key map "<" 'beginning-of-buffer)
 (define-key map ">" 'notmuch-search-goto-last-thread)
 (define-key map "=" 'notmuch-search-refresh-view)
@@ -1001,6 +1002,29 @@ This function advances point to the next line when 
finished."
  (set 'more nil))
   (delete-process proc

+(defun notmuch-search-operate-all (action)
+  "Operate on all messages matching the current query.  Any
+number of whitespace separated actions can be given.  Each action
+must have one of the two forms
+
+  +tagname  Add the tag `tagname'
+  -tagname  Remove the tag `tagname'
+
+Each character of the tag name may consist of alphanumeric
+characters as well as `_.+-'.
+"
+  (interactive "sOperation (+add -drop): notmuch tag ")
+  (let ((action-split (split-string action " +")))
+;; Perform some validation
+(let ((words action-split))
+  (when (null words) (error "No operation given"))
+  (while words
+   (unless (string-match-p "^[\+\-][_\+\-\\w]+$" (car words))
+ (error "Action must be of the form `+thistag -that_tag'"))
+   (setq words (cdr words
+(apply 'notmuch-call-notmuch-process "tag"
+  (append action-split (list notmuch-search-query-string) nil
+
 (defun notmuch-search (query &optional oldest-first)
   "Run \"notmuch search\" with the given query string and display results."
   (interactive "sNotmuch search: ")
-- 
1.6.5.3



[notmuch] [PATCH 2/2] notmuch-search-add/remove-tag: restrict to messages in current query

2009-11-26 Thread Jed Brown
Rather than tagging the everything in the thread.  This is arguably more
desirable behavior and is consistent with clearly desirably behavior of
notmuch-search-operate-all.

Note that this change applies indirectly to
notmuch-search-archive-thread (which is actually equivalent behavior
since this function is primarily used when browsing an inbox).

Signed-off-by: Jed Brown 
---
 notmuch.el |8 ++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 6adac9e..e9786c0 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -935,15 +935,19 @@ and will also appear in a buffer named \"*Notmuch 
errors*\"."
(split-string (buffer-substring beg end))

 (defun notmuch-search-add-tag (tag)
+  "Add a tag to messages in the current thread matching the
+active query."
   (interactive
(list (notmuch-select-tag-with-completion "Tag to add: ")))
-  (notmuch-call-notmuch-process "tag" (concat "+" tag) 
(notmuch-search-find-thread-id))
+  (notmuch-call-notmuch-process "tag" (concat "+" tag) 
(notmuch-search-find-thread-id) " and " notmuch-search-query-string)
   (notmuch-search-set-tags (delete-dups (sort (cons tag 
(notmuch-search-get-tags)) 'string<

 (defun notmuch-search-remove-tag (tag)
+  "Remove a tag from messages in the current thread matching the
+active query."
   (interactive
(list (notmuch-select-tag-with-completion "Tag to remove: " 
(notmuch-search-find-thread-id
-  (notmuch-call-notmuch-process "tag" (concat "-" tag) 
(notmuch-search-find-thread-id))
+  (notmuch-call-notmuch-process "tag" (concat "-" tag) 
(notmuch-search-find-thread-id) " and " notmuch-search-query-string)
   (notmuch-search-set-tags (delete tag (notmuch-search-get-tags

 (defun notmuch-search-archive-thread ()
-- 
1.6.5.3



[notmuch] [PATCH] New function notmuch-show-kill-ring-save-message-id.

2009-11-27 Thread Jed Brown
On Fri, 27 Nov 2009 05:41:44 -0800, Carl Worth  wrote:
> Thanks for the patch, Jed, I almost pushed it, but noticed that it's
> calling `called-interactively-p' with an argument even though that
> function does not accept an argument.

My docs say it does take an argument:

  called-interactively-p is a built-in function in `C source code'.

  (called-interactively-p KIND)

  Return t if the containing function was called by `call-interactively'.
  If KIND is `interactive', then only return t if the call was made
  interactively by the user, i.e. not in `noninteractive' mode nor
  when `executing-kbd-macro'.
  If KIND is `any', on the other hand, it will return t for any kind of
  interactive call, including being called as the binding of a key, or
  from a keyboard macro, or in `noninteractive' mode.

  The only known proper use of `interactive' for KIND is in deciding
  whether to display a helpful message, or how to display it.  If you're
  thinking of using it for any other purpose, it is quite likely that
  you're making a mistake.  Think: what do you want to do when the
  command is called from a keyboard macro?

  This function is meant for implementing advice and other
  function-modifying features.  Instead of using this, it is sometimes
  cleaner to give your function an extra optional argument whose
  `interactive' spec specifies non-nil unconditionally ("p" is a good
  way to do this), or via (not (or executing-kbd-macro noninteractive)).

> Meanwhile, the documentation of called-interactively-p suggests that
> using (interactive "p") is an easier way to check whether the function
> is called interactively.

I thought my usage fell precisely under "in deciding whether to display
a helpful message, or how to display it".  This message is just noise if
executed inside a macro.  As further evidence, see copy-region-as-kill
(simple.el):

  ;; This use of called-interactively-p is correct
  ;; because the code it controls just gives the user visual feedback.
  (if (called-interactively-p 'interactive)

Let me know if you still want me to change it.

> No, "git send-email" wouldn't strip that since it's a custom thing for
> notmuch.

Of course, I was just sloppy when pasting it into my shell, which rubbed
this issue in my face:

> So for passing the thread ID to notmuch users, the "id:" prefix is
> convenient. For passing it not non-notmuch-based consumers it won't be
> desired. And that's hard to fix.

I'm thinking of having a prefix determine whether it is stripped or not.
Do you have a preference about which is the non-prefix behavior?

> I think long-term, a good solution would be to switch from "id:foo" to
> "" as the syntax for message-ID-based search strings. That's then a
> syntax that almost any consumer of a message ID should be prepared to
> accept.

Downside is that it requires shell escapes when pasting into a terminal.

Jed
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: 



[notmuch] [PATCH 1/2] New function notmuch-search-operate-all: operate on all messages in the current query.

2009-11-27 Thread Jed Brown
On Fri, 27 Nov 2009 06:02:45 -0800, Carl Worth  wrote:
> Since this operates via a single call to "notmuch tag" you might mention
> here that all tag removals occur before any tag additions.

I was unaware of this point, if I do

  notmuch tag -inbox +star tag:inbox some-expression

I will have starred nothing?

> > +   (unless (string-match-p "^[\+\-][_\+\-\\w]+$" (car words))
> > + (error "Action must be of the form `+thistag -that_tag'"))
> 
> The error message has inconsistent "thistag" and "that_tag".

That was somewhat intentional to illustrate that non-alphanumeric
characters could be used in tags.  Should the alphabet for tags be based
on a whitelist or blacklist?  It would be rather hard to validate a tag
operation when there is no assumption/restriction on the alphabet.

Jed
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: 



[notmuch] [PATCH] New function notmuch-show-kill-ring-save-message-id.

2009-11-28 Thread Jed Brown
On Fri, 27 Nov 2009 21:54:11 -0800, Carl Worth  wrote:
> Ah. So we have our first case of emacs-lisp portability issues.

Bummer, my docs say nothing about this changing, let alone in a way
that's going to break anything that used it.

> I'm using "GNU emacs 23.1.1" currently, for what it's worth.

GNU Emacs 23.1.50.1 (x86_64-unknown-linux-gnu, GTK+ Version 2.16.5) of 
2009-10-08 on home.sergej.pp.ru

I'll fix it up and add the prefix argument.

Jed
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: 



[notmuch] Mailing list Reply-To munging and notmuch reply

2009-11-28 Thread Jed Brown
First, I'm aware that such munging is A Bad Thing

  http://www.unicom.com/pw/reply-to-harmful.html

but a lot of lists do it anyway (mostly to work around widely used
mailers with lame defaults).  After munging, we get headers looking like
this

  From: Some User 
  To: Sample users list 
  Reply-To: Sample users list 

Notmuch reply produces

  To: Sample users list ,
  Sample users list 

Handling this is a bit messy, I think we want the current behavior
unless To matches Reply-To, in which case we use From and Reply-To.  If
this is indeed the least bad behavior, I will make a patch for it.

Jed
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: 



[notmuch] [PATCH] Documentation for notmuch reply --format=(default|headers-only)

2009-11-28 Thread Jed Brown
Signed-off-by: Jed Brown 
---
 notmuch.1 |   22 +++---
 notmuch.c |   16 ++--
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/notmuch.1 b/notmuch.1
index 2be77f9..04bd0cf 100644
--- a/notmuch.1
+++ b/notmuch.1
@@ -211,9 +211,9 @@ section below for details of the supported syntax for 
.
 The
 .B reply
 command is useful for preparing a template for an email reply.
-
-.TP
-.BR reply " ..."
+.RS 4
+.TP 4
+.BR reply " [options...] ..."

 Constructs a reply template for a set of messages.

@@ -236,6 +236,21 @@ each line with '> ' and included in the body.

 The resulting message template is output to stdout.

+Supported options for
+.B reply
+include
+.RS
+.TP 4
+.BR \-\-format= ( default | headers\-only )
+.RS
+.TP 4
+.BR default
+Includes subject and quoted message body.
+.TP
+.BR headers-only
+Only produces In-Reply-To, References, To, Cc, and Bcc headers.
+.RE
+
 See the
 .B "SEARCH SYNTAX"
 section below for details of the supported syntax for .
@@ -248,6 +263,7 @@ once. For example, when a series of patches are sent in a 
single
 thread, replying to the entire thread allows for the reply to comment
 on issue found in multiple patches.
 .RE
+.RE

 The
 .B tag
diff --git a/notmuch.c b/notmuch.c
index 5b0284c..d9846ce 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -204,7 +204,7 @@ command_t commands[] = {
   "\t\tSee \"notmuch help search-terms\" for details of the search\n"
   "\t\tterms syntax." },
 { "reply", notmuch_reply_command,
-  " [...]",
+  "[options...]  [...]",
   "\t\tConstruct a reply template for a set of messages.",
   "\t\tConstructs a new message as a reply to a set of existing\n"
   "\t\tmessages. The Reply-To: header (if any, otherwise From:) is\n"
@@ -213,10 +213,22 @@ command_t commands[] = {
   "\n"
   "\t\tA suitable subject is constructed. The In-Reply-to: and\n"
   "\t\tReferences: headers are set appropriately, and the content\n"
-  "\t\tof the original messages is quoted and included in the body.\n"
+  "\t\tof the original messages is quoted and included in the body\n"
+  "\t\t(unless --format=headers-only is given).\n"
   "\n"
   "\t\tThe resulting message template is output to stdout.\n"
   "\n"
+  "\t\tSupported options for reply include:\n"
+  "\n"
+  "\t\t--format=(default|headers-only)\n"
+  "\n"
+  "\t\t\tdefault:\n"
+  "\t\t\t\tIncludes subject and quoted message body.\n"
+  "\n"
+  "\t\t\theaders-only:\n"
+  "\t\t\t\tOnly produces In-Reply-To, References, To\n"
+  "\t\t\t\tCc, and Bcc headers.\n"
+  "\n"
   "\t\tSee \"notmuch help search-terms\" for details of the search\n"
   "\t\tterms syntax." },
 { "tag", notmuch_tag_command,
-- 
1.6.5.3



[notmuch] Mailing list Reply-To munging and notmuch reply

2009-11-28 Thread Jed Brown
On Sat, 28 Nov 2009 09:55:43 -0800, Carl Worth  wrote:
> On Sat, 28 Nov 2009 17:05:06 +0100, Jed Brown  wrote:
> > Handling this is a bit messy, I think we want the current behavior
> > unless To matches Reply-To, in which case we use From and Reply-To.  If
> > this is indeed the least bad behavior, I will make a patch for it.
> 
> Oh, I really like that. The condition there avoids breaking legitimate
> uses of Reply-To, (such as the cairo lists I run, where cairo-commit@
> has no user-generated From:---just a single automated address, but has
> Reply-To: set to the cairo@ list instead so that replies to committed
> patches go to the right place).

I'm not sure I follow (at least not when comparing to the sanitized
headers shown in the online archives).  Could you send me one of these
headers?

When mailing lists munge, do they ever just add to that field (RFC-2822
says Reply-To may contain multiple addresses)?

Jed
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20091128/c82be920/attachment.pgp>


[notmuch] [PATCH] More portable and easier to read regex in notmuch-search-operate-all

2009-11-28 Thread Jed Brown
The former one worked in 23.1.50.1 but not in 23.1.1.

Signed-off-by: Jed Brown 
---
 notmuch.el |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 96c5d96..65473ba 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -1152,7 +1152,7 @@ characters as well as `_.+-'.
 (let ((words action-split))
   (when (null words) (error "No operation given"))
   (while words
-   (unless (string-match-p "^[\+\-][_\+\-\\w]+$" (car words))
+   (unless (string-match-p "^[-+][-+_.[:word:]]+$" (car words))
  (error "Action must be of the form `+thistag -that_tag'"))
(setq words (cdr words
 (apply 'notmuch-call-notmuch-process "tag"
-- 
1.6.5.3



[notmuch] [PATCH 1/2] notmuch-reply.c: factor adding recipients into common function

2009-11-29 Thread Jed Brown
add_recipients_from_message, in order to isolate more sophisticated
mailing list logic.

Signed-off-by: Jed Brown 
---
 notmuch-reply.c |   88 ---
 1 files changed, 45 insertions(+), 43 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 9ca1236..b91a830 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -23,17 +23,6 @@
 #include "notmuch-client.h"
 #include "gmime-filter-reply.h"

-static const struct {
-const char *header;
-const char *fallback;
-GMimeRecipientType recipient_type;
-} reply_to_map[] = {
-{ "reply-to", "from", GMIME_RECIPIENT_TYPE_TO  },
-{ "to", NULL, GMIME_RECIPIENT_TYPE_TO  },
-{ "cc", NULL, GMIME_RECIPIENT_TYPE_CC  },
-{ "bcc",NULL, GMIME_RECIPIENT_TYPE_BCC }
-};
-
 static void
 reply_part_content (GMimeObject *part)
 {
@@ -193,16 +182,56 @@ add_recipients_for_string (GMimeMessage *message,
 return add_recipients_for_address_list (message, config, type, list);
 }

+/* Augments the recipients of reply from the headers of message.
+ *
+ * If any of the user's addresses were found in these headers, the first
+ * of these returned, otherwise NULL is returned.
+ */
+static const char *
+add_recipients_from_message (GMimeMessage *reply,
+notmuch_config_t *config,
+notmuch_message_t *message)
+{
+static const struct {
+   const char *header;
+   const char *fallback;
+   GMimeRecipientType recipient_type;
+} reply_to_map[] = {
+   { "reply-to", "from", GMIME_RECIPIENT_TYPE_TO  },
+   { "to", NULL, GMIME_RECIPIENT_TYPE_TO  },
+   { "cc", NULL, GMIME_RECIPIENT_TYPE_CC  },
+   { "bcc",NULL, GMIME_RECIPIENT_TYPE_BCC }
+};
+const char *from_addr = NULL;
+unsigned int i;
+
+for (i = 0; i < ARRAY_SIZE (reply_to_map); i++) {
+   const char *addr, *recipients;
+
+   recipients = notmuch_message_get_header (message,
+reply_to_map[i].header);
+   if ((recipients == NULL || recipients[0] == '\0') && 
reply_to_map[i].fallback)
+   recipients = notmuch_message_get_header (message,
+reply_to_map[i].fallback);
+
+   addr = add_recipients_for_string (reply, config,
+ reply_to_map[i].recipient_type,
+ recipients);
+   if (from_addr == NULL)
+   from_addr = addr;
+}
+return from_addr;
+}
+
 static int
 notmuch_reply_format_default(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query)
 {
 GMimeMessage *reply;
 notmuch_messages_t *messages;
 notmuch_message_t *message;
-const char *subject, *recipients, *from_addr = NULL;
+const char *subject, *from_addr = NULL;
 const char *in_reply_to, *orig_references, *references;
 char *reply_headers;
-unsigned int i;

 for (messages = notmuch_query_search_messages (query);
 notmuch_messages_has_more (messages);
@@ -223,21 +252,7 @@ notmuch_reply_format_default(void *ctx, notmuch_config_t 
*config, notmuch_query_
subject = talloc_asprintf (ctx, "Re: %s", subject);
g_mime_message_set_subject (reply, subject);

-   for (i = 0; i < ARRAY_SIZE (reply_to_map); i++) {
-   const char *addr;
-
-   recipients = notmuch_message_get_header (message,
-reply_to_map[i].header);
-   if ((recipients == NULL || recipients[0] == '\0') && 
reply_to_map[i].fallback)
-   recipients = notmuch_message_get_header (message,
-
reply_to_map[i].fallback);
-
-   addr = add_recipients_for_string (reply, config,
- reply_to_map[i].recipient_type,
- recipients);
-   if (from_addr == NULL)
-   from_addr = addr;
-   }
+   from_addr = add_recipients_from_message (reply, config, message);

if (from_addr == NULL)
from_addr = notmuch_config_get_user_primary_email (config);
@@ -290,9 +305,8 @@ notmuch_reply_format_headers_only(void *ctx, 
notmuch_config_t *config, notmuch_q
 GMimeMessage *reply;
 notmuch_messages_t *messages;
 notmuch_message_t *message;
-const char *recipients, *in_reply_to, *orig_references, *references;
+const char *in_reply_to, *orig_references, *references;
 char *reply_headers;
-unsigned int i;

 for (messages = notmuch_query_search_messages (query);
 notmuch_messages_has_more (messages);
@@ -326,19 +340,7 @@ notmuch_reply_format_headers_only(voi

[notmuch] [PATCH 2/2] notmuch-reply.c: Handle munged `Reply-To' headers.

2009-11-29 Thread Jed Brown
Some mailing lists engage in the evil practice of changing the Reply-To
header so that replies from all mailers go to the list by default, at
the expense of not responding to the person who actually sent the
message.  When this is detected, we reply to `From' and remove the
duplicate response to the mailing list.  Consider a reply to the
following message.

  From: Some User 
  To: Sample users list 
  Reply-To: Sample users list 

Prior to this patch, `notmuch reply' produces

  To: Sample users list ,
  Sample users list 

and after the patch,

  To: Some User ,
  Sample users list 

Signed-off-by: Jed Brown 
---
 notmuch-reply.c |   47 ++-
 1 files changed, 46 insertions(+), 1 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index b91a830..9b9e9ab 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -182,6 +182,39 @@ add_recipients_for_string (GMimeMessage *message,
 return add_recipients_for_address_list (message, config, type, list);
 }

+/* Some mailing lists munge the Reply-To header despite it being A Bad
+ * Thing, see http://www.unicom.com/pw/reply-to-harmful.html
+ *
+ * This function detects such munging so that reasonable headers can be
+ * generated anyway.  Returns 1 if munged, else 0.
+ *
+ * The current logic is fairly naive, Reply-To is diagnosed as munged if
+ * it contains exactly one address, and this address is also present in
+ * the To or Cc fields.
+ */
+static int
+mailing_list_munged_reply_to (notmuch_message_t *message)
+{
+const char *header, *addr;
+InternetAddressList *list;
+InternetAddress *address;
+InternetAddressMailbox *mailbox;
+
+header = notmuch_message_get_header (message, "reply-to");
+list = internet_address_list_parse_string (header);
+if (internet_address_list_length (list) != 1)
+   return 0;
+address = internet_address_list_get_address (list, 0);
+if (INTERNET_ADDRESS_IS_GROUP (address))
+   return 0;
+mailbox = INTERNET_ADDRESS_MAILBOX (address);
+addr = internet_address_mailbox_get_addr (mailbox);
+/* Note that strcasestr() is a GNU extension, strstr() might be sufficient 
*/
+if (strcasestr (notmuch_message_get_header (message, "to"), addr) == 0 ||
+   strcasestr (notmuch_message_get_header (message, "cc"), addr) == 0)
+   return 1;
+return 0; }
+
 /* Augments the recipients of reply from the headers of message.
  *
  * If any of the user's addresses were found in these headers, the first
@@ -192,7 +225,7 @@ add_recipients_from_message (GMimeMessage *reply,
 notmuch_config_t *config,
 notmuch_message_t *message)
 {
-static const struct {
+struct {
const char *header;
const char *fallback;
GMimeRecipientType recipient_type;
@@ -205,6 +238,18 @@ add_recipients_from_message (GMimeMessage *reply,
 const char *from_addr = NULL;
 unsigned int i;

+/* When we have detected Reply-To munging, we ignore the Reply-To
+ * field (because it appears in the To or Cc headers) and use the
+ * From header so that person will get pinged and will actually
+ * receive the response if not subscribed to the list.  Note that
+ * under no circumstances does this fail to reply to the address in
+ * the Reply-To header.
+ */
+if (mailing_list_munged_reply_to (message)) {
+   reply_to_map[0].header = "from";
+   reply_to_map[0].fallback = NULL;
+}
+
 for (i = 0; i < ARRAY_SIZE (reply_to_map); i++) {
const char *addr, *recipients;

-- 
1.6.5.3



[notmuch] [PATCH] notmuch-reply.c: early exit for munged Reply-To when header is not present

2009-11-30 Thread Jed Brown
This avoids erroneously calling internet_address_list_length() with a
NULL list (which was causing a gmime exception).

Signed-off-by: Jed Brown 
---
 notmuch-reply.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 9b9e9ab..6c9118e 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -202,7 +202,7 @@ mailing_list_munged_reply_to (notmuch_message_t *message)

 header = notmuch_message_get_header (message, "reply-to");
 list = internet_address_list_parse_string (header);
-if (internet_address_list_length (list) != 1)
+if (list == NULL || internet_address_list_length (list) != 1)
return 0;
 address = internet_address_list_get_address (list, 0);
 if (INTERNET_ADDRESS_IS_GROUP (address))
-- 
1.6.5.3



[notmuch] Problem building notmuch

2009-12-01 Thread Jed Brown
On Tue, 1 Dec 2009 10:33:05 +0100, Steen Manniche  wrote:
> Probably unusable system info:
> % uname -a
> Linux algorithm 2.6.31-ARCH #1 SMP PREEMPT Fri Oct 23 11:12:58 CEST
> 2009 i686 Intel(R) Core(TM)2 Duo CPU P9500 @ 2.53GHz GenuineIntel
> GNU/Linux

This is pretty much my fault because I made the talloc package that is
on AUR.  The problem is that you have both talloc-1 (from the smbclient
package) and talloc-2 (from the AUR talloc).  The libtalloc.so symlink
points at smbclient's copy, but smbclient doesn't include a pkgconfig
for talloc, thus you are using the talloc-2 header and talloc-1 library.

How do other distros handle talloc-1/talloc-2 incompatibility?

Jed


[notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-12-02 Thread Jed Brown
A patch for notmuch-search-filter follows, my change to
notmuch-search-filter-by-tag is not very useful since
notmuch-select-tag-with-completion does not allow a space to be
inserted.  I don't know how to get completion on multiple
space-separated terms.

On Tue, 01 Dec 2009 18:56:59 -0800, Carl Worth  wrote:
> PS. Hmm... "notmuch reply" needs to be more clever to avoid duplicate
> addresses in the To: and Cc: lines. See above.

Yes, uniquifying the headers actually requires some effort, unless I'm
missing something in the gmime API (which I've never looked at before).

Jed


[notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-12-02 Thread Jed Brown
notmuch-search-filter now accepts an arbitrary query and will group if
necessary so that we get

  tag:inbox AND (gravy OR biscuits)

instead of the former

  tag:inbox AND gravy OR biscuits

Signed-off-by: Jed Brown 
---
 notmuch.el |5 -
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 2509651..0bf82f5 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -995,6 +995,8 @@ thread from that buffer can be show when done with this 
one)."
 (defvar notmuch-search-oldest-first t
   "Show the oldest mail first in the search-mode")

+(defvar notmuch-search-disjunctive-regexp  "\\<[oO][rR]\\>")
+
 (defun notmuch-search-scroll-up ()
   "Move forward through search results by one window's worth."
   (interactive)
@@ -1327,7 +1329,8 @@ search."
 Runs a new search matching only messages that match both the
 current search results AND the additional query string provided."
   (interactive "sFilter search: ")
-  (notmuch-search (concat notmuch-search-query-string " and " query) 
notmuch-search-oldest-first))
+  (let ((grouped-query (if (string-match-p notmuch-search-disjunctive-regexp 
query) (concat "( " query " )") query)))
+(notmuch-search (concat notmuch-search-query-string " and " grouped-query) 
notmuch-search-oldest-first)))

 (defun notmuch-search-filter-by-tag (tag)
   "Filter the current search results based on a single tag.
-- 
1.6.5.3



[notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-12-02 Thread Jed Brown
On Wed, 2 Dec 2009 14:18:08 +0100, Jan Janak  wrote:
> I haven't been really following this thread in detail. What is that you need
> from notmuch-select-tag-with-completion? To be able to process a list of tags
> separated by spaces? Maybe I could help you with that.

No, it would need to take input separated by spaces, now I just get `[No
match]' when I try to enter a space.  I think it's just not how
completing-read works, the idea would be for the user to be able to type

  shorttag and not long

which would complete to

  shorttag and not longboringtagname

The point of my patch was to be able to filter using arbitrary
expressions where every non-operator, i.e. `and', `or', `not', `(', and
`)', is interpreted as a tag name.  Is there an easy way to accept this
input without sacrificing completion?

Jed


[notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-12-02 Thread Jed Brown
Jan, thanks for looking into this.

On Wed, 2 Dec 2009 15:38:54 +0100, Jan Janak  wrote:
> This seems close enough to what you want and maybe we could somehow make it
> work with notmuch, too. This would be interesting to have, because then we
> could complete multiple tag names with a single TAB press not only in your
> expressions, but everywhere.

Yes, I think that is desirable.

> Let me know if you do not plan to work on this and I'll see if I can make it
> work.

I'm not using tags heavily at the moment, and am busy with other things
so I'm unlikely to get to it in the next couple weeks.  If you can make
completion work with this sort of input, I'll update my filter-by-tags
patch.

Jed


[notmuch] Trouble with notmuch-show

2009-12-03 Thread Jed Brown
I know html support is still poor, but the following seems worse than
not showing anything.  When I visit this message, I get prompted to save
the MIME part and the following is displayed (including all the hidden
stuff).  Original message is attached.

Jed


message{ id:4B182A91.9020304 at sandia.gov depth:0 match:1 
filename:/home/jed/.mail-archive/gmail-all/pop/new/1259875803.M47630P27852Q0R271bd14e8c36baf4.localhost
header{
"Raymond Tuminaro"  (46 mins. ago) (inbox unread)
Subject: [SIAM-CSE] Copper Mountain Iterative Methods Announcement Posting, 
April 4-9, 2010
From: "Raymond Tuminaro" 
To: siam-cse at siam.org
Cc: 
Bcc: 
Date: Thu, 3 Dec 2009 13:16:01 -0800

header}
body{
part{ ID: 2, Content-type: text/html
Non-text part: text/html
part}
part{ ID: 3, Content-type: text/plain
___
SIAM-CSE mailing list
To post messages to the list please send them to: SIAM-CSE at siam.org
http://lists.siam.org/mailman/listinfo/siam-cse
part}
body}
message}



-- next part --
A non-text attachment was scrubbed...
Name: 1259875803.M47630P27852Q0R271bd14e8c36baf4.localhost
Type: application/octet-stream
Size: 12176 bytes
Desc: Problem html message
URL: 



[notmuch] [PATCH 1/2] notmuch-reply: Add support for replying only to sender

2009-12-04 Thread Jed Brown
On Fri, 04 Dec 2009 11:07:54 -0800, Carl Worth  wrote:

> But surely there's a way to implement this with dramatically less code
> duplication?

It should just be very short after this series

  id:1259450376-24523-1-git-send-email-jed at 59A2.org

I think --format= should not be used for this, formatting is orthogonal
to selecting recipients.

Speaking of code duplication, perhaps it is worth abstracting options
parsing (or using an existing library).

Jed


[notmuch] [Orgmode] Notmuch: An emacs interface for fast global search and tagging of email

2009-12-10 Thread Jed Brown
On Wed, 09 Dec 2009 12:00:21 -0800, Carl Worth  wrote:
> 1. Rewriting the code to not use apply-partially

1b. Use apply-partially

(defun apply-partially (fun &rest args)
  "Return a function that is a partial application of FUN to ARGS.
ARGS is a list of the first N arguments to pass to FUN.
The result is a new function which does the same as FUN, except that
the first N arguments are fixed at the values with which this function
was called."
  (lexical-let ((fun fun) (args1 args))
(lambda (&rest args2) (apply fun (append args1 args2)


Jed


[notmuch] keeping a copy of sent mail locally

2009-12-19 Thread Jed Brown
On Sat, 19 Dec 2009 15:41:14 +1100, Alex Ghitza  wrote:
> Bcc-ing myself on every sent message is suboptimal for a number of
> reasons: (1) gmail throws away the bcc-ed copy since it has the same
> message id as the one sitting in the gmail sent mail, and so the
> bcc-ed copy never makes it back to my local mail;

I agree it is suboptimal, but are you sure this is true?  I send
messages via gmail and those having Bcc to me are marked as new and
downloaded by the next pass of getmail (via POP).

Jed


[notmuch] Xapian::DatabaseError on notmuch new upgrade

2010-01-11 Thread Jed Brown
I rebuilt notmuch and got a Xapian exception while notmuch new was
upgrading my database.  This seemed like a decent time to try the latest
Xapian, so I built a copy and the crash remained (and maintainer-mode
still optimizes so I built Xapian again so I could get decent
debugging).  Here is a trace from

  XAPIAN_PREFER_CHERT=1 notmuch new

I got the same error without setting XAPIAN_PREFER_CHERT.  It's not
clear to me whether this is a usage issue or Xapian problem.  The core
is 245 MB, I can provide it if someone wants to try debugging.

Jed

(gdb) bt
#0  0x7fa687d9e035 in raise () from /lib/libc.so.6
#1  0x7fa687d9f460 in abort () from /lib/libc.so.6
#2  0x7fa688622925 in __gnu_cxx::__verbose_terminate_handler() () from 
/usr/lib/libstdc++.so.6
#3  0x7fa688620d56 in __cxxabiv1::__terminate(void (*)()) () from 
/usr/lib/libstdc++.so.6
#4  0x7fa688620d83 in std::terminate() () from /usr/lib/libstdc++.so.6
#5  0x7fa688620e7e in __cxa_throw () from /usr/lib/libstdc++.so.6
#6  0x7fa688a221bc in FlintTable::read_block (this=0x16395c8, n=2569, 
p=0xe3fd8e0 "") at backends/flint/flint_table.cc:243
#7  0x7fa688a22bda in FlintTable::block_to_cursor (this=0x16395c8, 
C_=0xe4074e0, j=0, n=2569) at backends/flint/flint_table.cc:393
#8  0x7fa688a299fc in FlintTable::next_default (this=0x16395c8, 
C_=0xe4074e0, j=1) at backends/flint/flint_table.cc:2219
#9  0x7fa688a29983 in FlintTable::next_default (this=0x16395c8, 
C_=0xe4074e0, j=0) at backends/flint/flint_table.cc:2214
#10 0x7fa688a022c5 in FlintTable::next (this=0x16395c8, C_=0xe4074e0, j=0) 
at backends/flint/flint_table.h:692
#11 0x7fa688a020d5 in FlintCursor::read_tag (this=0xe43ece0, 
keep_compressed=false) at backends/flint/flint_cursor.cc:264
#12 0x7fa688a1a6d8 in FlintPostListTable::get_chunk (this=0x16395c8, 
tname=..., did=82407, adding=false, from=0x7fff849be358, to=0x7fff849be350) at 
backends/flint/flint_postlist.cc:946
#13 0x7fa688a1b5e3 in FlintPostListTable::merge_changes (this=0x16395c8, 
mod_plists=..., doclens=..., freq_deltas=...) at 
backends/flint/flint_postlist.cc:1100
#14 0x7fa688a08d89 in FlintWritableDatabase::flush_postlist_changes 
(this=0x1639590) at backends/flint/flint_database.cc:1053
#15 0x7fa688a0bb5f in FlintWritableDatabase::replace_document 
(this=0x1639590, did=45341, document=...) at 
backends/flint/flint_database.cc:1425
#16 0x7fa688975b7d in Xapian::WritableDatabase::replace_document 
(this=0x16393a0, did=45341, document=...) at api/omdatabase.cc:817
#17 0x00416c6f in _notmuch_message_sync (message=0xe327130) at 
lib/message.cc:609
#18 0x00410ca5 in notmuch_database_upgrade (notmuch=0x1639460, 
progress_notify=0x40a890 , closure=0x7fff849bef20) at 
lib/database.cc:751
#19 0x0040ad4a in notmuch_new_command (ctx=0x162b120, argc=0, 
argv=0x7fff849bf0f8) at notmuch-new.c:746
#20 0x0040862e in main (argc=2, argv=0x7fff849bf0e8) at notmuch.c:449
(gdb) f 17
#17 0x00416c6f in _notmuch_message_sync (message=0xe327130) at 
lib/message.cc:609
609 db->replace_document (message->doc_id, message->doc);
Current language:  auto
The current source language is "auto; currently c++".
(gdb) p *message
$1 = {notmuch = 0x1639460, doc_id = 45341, frozen = 0, message_id = 0x0, 
thread_id = 0x0, in_reply_to = 0x0, filename = 0x0, message_file = 0x0, replies 
= 0xbaea960, flags = 0, doc = {internal = {dest = 0xe3816c0}}}


[notmuch] Xapian::DatabaseError on notmuch new upgrade

2010-01-15 Thread Jed Brown
Looks like this was just a bug in Xapian HEAD, today's build works just
fine and I'm enjoying the faster CHERT backend.  Bulk tagging is really
loads faster now, and the interactivity is better than before, but SPC
still has a noticeable pause (at least 200 ms) since (apparently) it's
doing an fsync, and this is worse when the disk is getting hit by some
other job (like when I'm reading email while something big compiles).
It wouldn't bother me at all if I lost my last few seconds of
interactive tagging due to something catastrophic like losing power.  I
think there is still (post #250) a case for supporting some asynchronous
operations.

Jed


[notmuch] asynch operations protocol

2010-01-15 Thread Jed Brown
On Fri, 15 Jan 2010 09:59:54 -0400, David Bremner  wrote:
> Is this over/under engineered?  I spent roughly as long on the design as
> it took me to type :). Maybe the whole session id thing is redundant and
> could be done at the socket level. Or, getting more serious about the
> whole thing, maybe each queue operation should return an identifier.

The asynchronous interface I work with most is MPI.  There you get a
Request object when the operation is initiated and you can
{test,block}{one,some,any,all}, where the latter takes a list of
requests.  These variants are all useful, but of course they could be
implemented as needed.  I don't think that being able to support these
variants places any particular burden on the design.

I believe in performing operations with appropriate granularity, so I
wouldn't expect cases where you need to manage thousands of active
requests, thus I'm not sure the "session" grouping offers any real
benefit.  In any case, I'm not in favor of a single global flush.

Jed


[notmuch] tag dir proposal [was: Re: Git as notmuch object store]

2010-01-28 Thread Jed Brown
On Thu, 28 Jan 2010 15:49:34 -0500, Ben Gamari  wrote:
> Sounds like you need to add a line to crontab.

I haven't been following this thread closely so I hope this isn't too
out of context.  I agree that certain things like notmuch-new should go
in the crontab, but I think that notmuch-new should need to be run
exactly once to process a new batch of messages into the desired state.

Having notmuch-new apply one set of tags and then relying on another
process run afterwards to change the tags according to a filter is
undesirable in my opinion, both for the mild performance reason of
making two passes, but more importantly because of lock contention
between the two processes and the ease of viewing the database in the
inconsistent state.  As far as I understand the situation, my favorite
solution is to have notmuch-new run a hook on each message as it is
indexed.

Jed


[notmuch] [PATCH 2/2] notmuch-reply.c: Handle munged `Reply-To' headers.

2010-02-05 Thread Jed Brown
On Thu, 04 Feb 2010 12:54:20 -0800, Carl Worth  wrote:
> And I'm glad I did because that turned up a bug in the patch, (using
> == instead of != for the return value of strcasestr resulted in *all*
> messages with a Reply-To header being considered as munged).

Yikes, I've been using this thing for two months and hadn't noticed.

> Here's one cleanup I made which you might find interesting as a style
> issue (where I prefer naming a function based on what it *does* rather
> than on what it's being *used* for):

Yup, I do the same, but must have been too lazy to think of a decent name.

Jed


[notmuch] strange behavior of indexing of and searching for strings containing '[]'

2010-02-08 Thread Jed Brown
On Mon, 08 Feb 2010 12:24:06 -0500, Jameson Rollins  wrote:
> I don't think that this is exactly correct.  The quoting is interpreted
> by the shell in order to construct a single string that is then passed
> as an argument to the program.

The command line distinguishes, but the constructed query does not.
Look at query-string.c, the arguments are just concatenated.

Jed


[notmuch] [PATCH] Switch from random to sequential thread identifiers.

2010-02-09 Thread Jed Brown
On Tue, 09 Feb 2010 11:19:54 -0800, Carl Worth  wrote:
> I did verify the above in a copy of WG14/N1124. For anyone that doesn't
> recognize that, that's the draft from the C99 working group that I've
> been told is remarkably similar to C99 but distinct in that it's freely
> available[*]. I haven't verified the similarity, but I have found that
> document quite useful in cases like this one.

This one is more recent (TC3):

  http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf

I don't know the legality of this copy:

  http://www.ishiboo.com/~danny/c++/C_STANDARD-ISOIEC9899-1999.pdf


Jed


Re: notmuch-next branch

2010-10-11 Thread Jed Brown
On Mon, Oct 11, 2010 at 22:00, Jameson Rollins
 wrote:
> As long as all the repos are synced, then you only need to track one.
> But notmuch already has "official" repos [0], and making another
> pseudo-"official" repo will probably just makes things more confusing.

Patches show up in a different order in each person's "personal, but
'synced'" repository.  Then you need a mess of merges to actually get
them synced (if they are published, you can't rebase).

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


Re: [PATCH 2/3] build: fix DSO dependencies

2010-11-01 Thread Jed Brown
On Fri, Oct 29, 2010 at 18:17, Felipe Contreras
 wrote:
>
> Well, it's not possible: pkg-config is supposed to work on win32 and
> osx, so all the dependencies must be there, so:
>
> % pkg-config --libs gmime-2.6
> -pthread -lgmime-2.6 -lgio-2.0 -lgobject-2.0 -lgmodule-2.0
> -lgthread-2.0 -lrt -lglib-2.0

This is what the Libs.private field is for (see the pkg-config man page).  E.g.

$ pkg-config --libs libavdevice
-lavdevice
$ pkg-config --libs --static libavdevice
-pthread -lavdevice -lavformat -lavcodec -ldl -lX11 -lXext -lXfixes
-lasound -lxvidcore -lx264 -lvpx -lvorbisenc -lvorbis -ltheoraenc
-ltheoradec -logg -lschroedinger-1.0 -lpthread -lorc-0.4 -lopenjpeg
-lopencore-amrwb -lopencore-amrnb -lmp3lame -lfaac -lva -lm -lbz2 -lz
-lavcore -lavutil

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


[PATCH] Support function values in notmuch-saved-searches so that searches can be generated dynamically

2010-11-19 Thread Jed Brown
This permits saved searches like "today".
---
This is similar functionality to David's patch, but uses an accessor so that 
queries are always evaluated dynamically.

 emacs/notmuch-hello.el |4 ++--
 emacs/notmuch-lib.el   |   11 ++-
 emacs/notmuch.el   |2 +-
 3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index e58dd24..15eaafb 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -234,7 +234,7 @@ should be. Returns a cons cell `(tags-per-line width)'."
;; (not elem) indicates an empty slot in the matrix.
(when elem
  (let* ((name (car elem))
-(query (cdr elem))
+(query (notmuch-saved-search-get-query elem))
 (formatted-name (format "%s " name)))
(widget-insert (format "%8s "
   (notmuch-hello-nice-number
@@ -393,7 +393,7 @@ Complete list of currently available key bindings:
  (if notmuch-show-empty-saved-searches
  notmuch-saved-searches
(loop for elem in notmuch-saved-searches
- if (> (string-to-number (notmuch-saved-search-count (cdr 
elem))) 0)
+ if (> (string-to-number (notmuch-saved-search-count 
(notmuch-saved-search-get-query elem))) 0)
  collect elem)))
 (saved-widest (notmuch-hello-longest-label saved-alist))
 (alltags-alist (if notmuch-show-all-tags-list
diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index dd180ee..3fcb837 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -37,7 +37,9 @@
 
 (defcustom notmuch-saved-searches nil
   "A list of saved searches to display."
-  :type '(alist :key-type string :value-type string)
+  :type '(alist :key-type (string :tag "Name")
+:value-type (choice (string :tag "Search")
+(function :tag "Function")))
   :group 'notmuch)
 
 (defvar notmuch-folders nil
@@ -56,6 +58,13 @@ the user hasn't set this variable with the old or new value."
   '(("inbox" . "tag:inbox")
("unread" . "tag:unread")
 
+(defun notmuch-saved-search-get-query (tuple)
+  "Get the query string for a saved tuple."
+  (let ((q (cdr tuple)))
+(if (stringp q)
+q
+  (funcall q
+
 (defun notmuch-version ()
   "Return a string with the notmuch version number."
   (let ((long-string
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 5933747..5864b21 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -763,7 +763,7 @@ characters as well as `_.+-'.
  (let (longest
(longest-length 0))
(loop for tuple in notmuch-saved-searches
- if (let ((quoted-query (regexp-quote (cdr tuple
+ if (let ((quoted-query (regexp-quote 
(notmuch-saved-search-get-query tuple
   (and (string-match (concat "^" quoted-query) query)
(> (length (match-string 0 query))
   longest-length)))
-- 
1.7.3.2

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


Re: Handling PATCH from notmuchmail

2010-11-23 Thread Jed Brown
On Tue, 23 Nov 2010 16:41:40 +0100, Michal Sojka  wrote:
> On Mon, 22 Nov 2010, Xavier Maillard wrote:
> M-x cd  ~/src/notmuch 
> | git am 

An arguable refinement is

  | (cd ~/src/notmuch; git am -3)

> Then I manually switch to *notmuch-pipe* buffer to see whether the
> command failed or not. It would be nice if *notmuch-pipe* buffer is
> shown automatically when the command exits with non-zero status.

Agreed.

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


Re: branchs and tags and merges oh my!

2011-07-02 Thread Jed Brown
On Sat, Jul 2, 2011 at 07:44, David Bremner  wrote:
>
> A third strategy is "git checkout master && git merge -s ours 0.6".
> Then history will look like this:
>
>  freeze
> --.-.- master
>   \           /
>    ---
>               release
>
> As long as every patch on the release branch is already on master, -s
> ours (which throws away all the changes from the side branch) is
> reasonable.

Remind me of why bugfix patches can't (usually) be applied to the
release branch first, then merged into master? When the patch is
(accidentally or otherwise) applied to master first, then I think you
have no choice but to have it appear twice in the history, once in
master and once in release, and using the model you describe above
seems the most sensible way to do that.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [notmuch] Notmuch doesn't index new mails when mail location contains symlinks

2009-11-26 Thread Jed Brown
On Thu, 26 Nov 2009 10:34:12 -0800, Carl Worth  wrote:
> I'm a little confused here. Notmuch only uses stat, so it should be
> looking at the target's mtime already. It actually takes special effort
> (via lstat) to get at the mtime of the link itself.
> 
> So why aren't things just working?

Because mtime doesn't change on the directory *above* the symlinks.

I think.

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


Re: [notmuch] Notmuch doesn't index new mails when mail location contains symlinks

2009-11-26 Thread Jed Brown
On Thu, 26 Nov 2009 13:14:22 -0800, Carl Worth  wrote:

> Then I'm still being really dense here. The non-propagation of mtime is
> the with actual directories. And the code is trying to do the right
> thing for that.

The stat() is correct, it's the check for the d_type field coming out of 
scandir().

20:08 [   jedbrown  ] cworth: I think there are two problems with symlinks.
20:08 [   jedbrown  ] cworth: First, notmuch-new.c:152 checks path_mtime which 
is mtime for the current directory.
20:09 [   jedbrown  ] cworth: Additionally, won't entry->d_type == DT_LNK for a 
symlink?
20:14 [ aneesh  ] jedbrown,  i already have a patch posted for that
20:15 [ aneesh  ] 
1259125104-18785-1-git-send-email-aneesh.ku...@linux.vnet.ibm.com


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


[notmuch] [PATCH 1/2] New function notmuch-search-operate-all: operate on all messages in the current query.

2009-11-26 Thread Jed Brown
It is often convenient to change tags on several messages at once.  This
function applies any number of tag whitespace-delimited tag
modifications to all messages matching the current query.

I have bound this to `*'.

Signed-off-by: Jed Brown 
---
 notmuch.el |   24 
 1 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index d7c973c..6adac9e 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -801,6 +801,7 @@ thread from that buffer can be show when done with this 
one)."
 (define-key map [mouse-1] 'notmuch-search-show-thread)
 (define-key map "+" 'notmuch-search-add-tag)
 (define-key map "-" 'notmuch-search-remove-tag)
+(define-key map "*" 'notmuch-search-operate-all)
 (define-key map "<" 'beginning-of-buffer)
 (define-key map ">" 'notmuch-search-goto-last-thread)
 (define-key map "=" 'notmuch-search-refresh-view)
@@ -1001,6 +1002,29 @@ This function advances point to the next line when 
finished."
  (set 'more nil))
   (delete-process proc
 
+(defun notmuch-search-operate-all (action)
+  "Operate on all messages matching the current query.  Any
+number of whitespace separated actions can be given.  Each action
+must have one of the two forms
+
+  +tagname  Add the tag `tagname'
+  -tagname  Remove the tag `tagname'
+
+Each character of the tag name may consist of alphanumeric
+characters as well as `_.+-'.
+"
+  (interactive "sOperation (+add -drop): notmuch tag ")
+  (let ((action-split (split-string action " +")))
+;; Perform some validation
+(let ((words action-split))
+  (when (null words) (error "No operation given"))
+  (while words
+   (unless (string-match-p "^[\+\-][_\+\-\\w]+$" (car words))
+ (error "Action must be of the form `+thistag -that_tag'"))
+   (setq words (cdr words
+(apply 'notmuch-call-notmuch-process "tag"
+  (append action-split (list notmuch-search-query-string) nil
+
 (defun notmuch-search (query &optional oldest-first)
   "Run \"notmuch search\" with the given query string and display results."
   (interactive "sNotmuch search: ")
-- 
1.6.5.3

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


[notmuch] [PATCH 2/2] notmuch-search-add/remove-tag: restrict to messages in current query

2009-11-26 Thread Jed Brown
Rather than tagging the everything in the thread.  This is arguably more
desirable behavior and is consistent with clearly desirably behavior of
notmuch-search-operate-all.

Note that this change applies indirectly to
notmuch-search-archive-thread (which is actually equivalent behavior
since this function is primarily used when browsing an inbox).

Signed-off-by: Jed Brown 
---
 notmuch.el |8 ++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 6adac9e..e9786c0 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -935,15 +935,19 @@ and will also appear in a buffer named \"*Notmuch 
errors*\"."
(split-string (buffer-substring beg end))
 
 (defun notmuch-search-add-tag (tag)
+  "Add a tag to messages in the current thread matching the
+active query."
   (interactive
(list (notmuch-select-tag-with-completion "Tag to add: ")))
-  (notmuch-call-notmuch-process "tag" (concat "+" tag) 
(notmuch-search-find-thread-id))
+  (notmuch-call-notmuch-process "tag" (concat "+" tag) 
(notmuch-search-find-thread-id) " and " notmuch-search-query-string)
   (notmuch-search-set-tags (delete-dups (sort (cons tag 
(notmuch-search-get-tags)) 'string<
 
 (defun notmuch-search-remove-tag (tag)
+  "Remove a tag from messages in the current thread matching the
+active query."
   (interactive
(list (notmuch-select-tag-with-completion "Tag to remove: " 
(notmuch-search-find-thread-id
-  (notmuch-call-notmuch-process "tag" (concat "-" tag) 
(notmuch-search-find-thread-id))
+  (notmuch-call-notmuch-process "tag" (concat "-" tag) 
(notmuch-search-find-thread-id) " and " notmuch-search-query-string)
   (notmuch-search-set-tags (delete tag (notmuch-search-get-tags
 
 (defun notmuch-search-archive-thread ()
-- 
1.6.5.3

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


Re: [notmuch] [PATCH] New function notmuch-show-kill-ring-save-message-id.

2009-11-27 Thread Jed Brown
On Fri, 27 Nov 2009 05:41:44 -0800, Carl Worth  wrote:
> Thanks for the patch, Jed, I almost pushed it, but noticed that it's
> calling `called-interactively-p' with an argument even though that
> function does not accept an argument.

My docs say it does take an argument:

  called-interactively-p is a built-in function in `C source code'.
  
  (called-interactively-p KIND)
  
  Return t if the containing function was called by `call-interactively'.
  If KIND is `interactive', then only return t if the call was made
  interactively by the user, i.e. not in `noninteractive' mode nor
  when `executing-kbd-macro'.
  If KIND is `any', on the other hand, it will return t for any kind of
  interactive call, including being called as the binding of a key, or
  from a keyboard macro, or in `noninteractive' mode.
  
  The only known proper use of `interactive' for KIND is in deciding
  whether to display a helpful message, or how to display it.  If you're
  thinking of using it for any other purpose, it is quite likely that
  you're making a mistake.  Think: what do you want to do when the
  command is called from a keyboard macro?
  
  This function is meant for implementing advice and other
  function-modifying features.  Instead of using this, it is sometimes
  cleaner to give your function an extra optional argument whose
  `interactive' spec specifies non-nil unconditionally ("p" is a good
  way to do this), or via (not (or executing-kbd-macro noninteractive)).

> Meanwhile, the documentation of called-interactively-p suggests that
> using (interactive "p") is an easier way to check whether the function
> is called interactively.

I thought my usage fell precisely under "in deciding whether to display
a helpful message, or how to display it".  This message is just noise if
executed inside a macro.  As further evidence, see copy-region-as-kill
(simple.el):

  ;; This use of called-interactively-p is correct
  ;; because the code it controls just gives the user visual feedback.
  (if (called-interactively-p 'interactive)

Let me know if you still want me to change it.

> No, "git send-email" wouldn't strip that since it's a custom thing for
> notmuch.

Of course, I was just sloppy when pasting it into my shell, which rubbed
this issue in my face:

> So for passing the thread ID to notmuch users, the "id:" prefix is
> convenient. For passing it not non-notmuch-based consumers it won't be
> desired. And that's hard to fix.

I'm thinking of having a prefix determine whether it is stripped or not.
Do you have a preference about which is the non-prefix behavior?

> I think long-term, a good solution would be to switch from "id:foo" to
> "" as the syntax for message-ID-based search strings. That's then a
> syntax that almost any consumer of a message ID should be prepared to
> accept.

Downside is that it requires shell escapes when pasting into a terminal.

Jed


pgpgUNOoP8HQk.pgp
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [notmuch] [PATCH 1/2] New function notmuch-search-operate-all: operate on all messages in the current query.

2009-11-27 Thread Jed Brown
On Fri, 27 Nov 2009 06:02:45 -0800, Carl Worth  wrote:
> Since this operates via a single call to "notmuch tag" you might mention
> here that all tag removals occur before any tag additions.

I was unaware of this point, if I do

  notmuch tag -inbox +star tag:inbox some-expression

I will have starred nothing?

> > +   (unless (string-match-p "^[\+\-][_\+\-\\w]+$" (car words))
> > + (error "Action must be of the form `+thistag -that_tag'"))
> 
> The error message has inconsistent "thistag" and "that_tag".

That was somewhat intentional to illustrate that non-alphanumeric
characters could be used in tags.  Should the alphabet for tags be based
on a whitelist or blacklist?  It would be rather hard to validate a tag
operation when there is no assumption/restriction on the alphabet.

Jed


pgpLGtWCtzjq3.pgp
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [notmuch] [PATCH] New function notmuch-show-kill-ring-save-message-id.

2009-11-28 Thread Jed Brown
On Fri, 27 Nov 2009 21:54:11 -0800, Carl Worth  wrote:
> Ah. So we have our first case of emacs-lisp portability issues.

Bummer, my docs say nothing about this changing, let alone in a way
that's going to break anything that used it.

> I'm using "GNU emacs 23.1.1" currently, for what it's worth.

GNU Emacs 23.1.50.1 (x86_64-unknown-linux-gnu, GTK+ Version 2.16.5) of 
2009-10-08 on home.sergej.pp.ru

I'll fix it up and add the prefix argument.

Jed


pgpfDy33SzE8s.pgp
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[notmuch] Mailing list Reply-To munging and notmuch reply

2009-11-28 Thread Jed Brown
First, I'm aware that such munging is A Bad Thing

  http://www.unicom.com/pw/reply-to-harmful.html

but a lot of lists do it anyway (mostly to work around widely used
mailers with lame defaults).  After munging, we get headers looking like
this

  From: Some User 
  To: Sample users list 
  Reply-To: Sample users list 
  
Notmuch reply produces

  To: Sample users list ,
  Sample users list 

Handling this is a bit messy, I think we want the current behavior
unless To matches Reply-To, in which case we use From and Reply-To.  If
this is indeed the least bad behavior, I will make a patch for it.

Jed


pgpa3jjgDMPLC.pgp
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[notmuch] [PATCH] Documentation for notmuch reply --format=(default|headers-only)

2009-11-28 Thread Jed Brown
Signed-off-by: Jed Brown 
---
 notmuch.1 |   22 +++---
 notmuch.c |   16 ++--
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/notmuch.1 b/notmuch.1
index 2be77f9..04bd0cf 100644
--- a/notmuch.1
+++ b/notmuch.1
@@ -211,9 +211,9 @@ section below for details of the supported syntax for 
.
 The
 .B reply
 command is useful for preparing a template for an email reply.
-
-.TP
-.BR reply " ..."
+.RS 4
+.TP 4
+.BR reply " [options...] ..."
 
 Constructs a reply template for a set of messages.
 
@@ -236,6 +236,21 @@ each line with '> ' and included in the body.
 
 The resulting message template is output to stdout.
 
+Supported options for
+.B reply
+include
+.RS
+.TP 4
+.BR \-\-format= ( default | headers\-only )
+.RS
+.TP 4
+.BR default
+Includes subject and quoted message body.
+.TP
+.BR headers-only
+Only produces In-Reply-To, References, To, Cc, and Bcc headers.
+.RE
+
 See the
 .B "SEARCH SYNTAX"
 section below for details of the supported syntax for .
@@ -248,6 +263,7 @@ once. For example, when a series of patches are sent in a 
single
 thread, replying to the entire thread allows for the reply to comment
 on issue found in multiple patches.
 .RE
+.RE
 
 The
 .B tag
diff --git a/notmuch.c b/notmuch.c
index 5b0284c..d9846ce 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -204,7 +204,7 @@ command_t commands[] = {
   "\t\tSee \"notmuch help search-terms\" for details of the search\n"
   "\t\tterms syntax." },
 { "reply", notmuch_reply_command,
-  " [...]",
+  "[options...]  [...]",
   "\t\tConstruct a reply template for a set of messages.",
   "\t\tConstructs a new message as a reply to a set of existing\n"
   "\t\tmessages. The Reply-To: header (if any, otherwise From:) is\n"
@@ -213,10 +213,22 @@ command_t commands[] = {
   "\n"
   "\t\tA suitable subject is constructed. The In-Reply-to: and\n"
   "\t\tReferences: headers are set appropriately, and the content\n"
-  "\t\tof the original messages is quoted and included in the body.\n"
+  "\t\tof the original messages is quoted and included in the body\n"
+  "\t\t(unless --format=headers-only is given).\n"
   "\n"
   "\t\tThe resulting message template is output to stdout.\n"
   "\n"
+  "\t\tSupported options for reply include:\n"
+  "\n"
+  "\t\t--format=(default|headers-only)\n"
+  "\n"
+  "\t\t\tdefault:\n"
+  "\t\t\t\tIncludes subject and quoted message body.\n"
+  "\n"
+  "\t\t\theaders-only:\n"
+  "\t\t\t\tOnly produces In-Reply-To, References, To\n"
+  "\t\t\t\tCc, and Bcc headers.\n"
+  "\n"
   "\t\tSee \"notmuch help search-terms\" for details of the search\n"
   "\t\tterms syntax." },
 { "tag", notmuch_tag_command,
-- 
1.6.5.3

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


Re: [notmuch] Mailing list Reply-To munging and notmuch reply

2009-11-28 Thread Jed Brown
On Sat, 28 Nov 2009 09:55:43 -0800, Carl Worth  wrote:
> On Sat, 28 Nov 2009 17:05:06 +0100, Jed Brown  wrote:
> > Handling this is a bit messy, I think we want the current behavior
> > unless To matches Reply-To, in which case we use From and Reply-To.  If
> > this is indeed the least bad behavior, I will make a patch for it.
> 
> Oh, I really like that. The condition there avoids breaking legitimate
> uses of Reply-To, (such as the cairo lists I run, where cairo-commit@
> has no user-generated From:---just a single automated address, but has
> Reply-To: set to the cairo@ list instead so that replies to committed
> patches go to the right place).

I'm not sure I follow (at least not when comparing to the sanitized
headers shown in the online archives).  Could you send me one of these
headers?

When mailing lists munge, do they ever just add to that field (RFC-2822
says Reply-To may contain multiple addresses)?

Jed


pgpKirRQHlCT4.pgp
Description: PGP signature
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[notmuch] [PATCH] More portable and easier to read regex in notmuch-search-operate-all

2009-11-28 Thread Jed Brown
The former one worked in 23.1.50.1 but not in 23.1.1.

Signed-off-by: Jed Brown 
---
 notmuch.el |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 96c5d96..65473ba 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -1152,7 +1152,7 @@ characters as well as `_.+-'.
 (let ((words action-split))
   (when (null words) (error "No operation given"))
   (while words
-   (unless (string-match-p "^[\+\-][_\+\-\\w]+$" (car words))
+   (unless (string-match-p "^[-+][-+_.[:word:]]+$" (car words))
  (error "Action must be of the form `+thistag -that_tag'"))
(setq words (cdr words
 (apply 'notmuch-call-notmuch-process "tag"
-- 
1.6.5.3

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


[notmuch] [PATCH 1/2] notmuch-reply.c: factor adding recipients into common function

2009-11-28 Thread Jed Brown
add_recipients_from_message, in order to isolate more sophisticated
mailing list logic.

Signed-off-by: Jed Brown 
---
 notmuch-reply.c |   88 ---
 1 files changed, 45 insertions(+), 43 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 9ca1236..b91a830 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -23,17 +23,6 @@
 #include "notmuch-client.h"
 #include "gmime-filter-reply.h"
 
-static const struct {
-const char *header;
-const char *fallback;
-GMimeRecipientType recipient_type;
-} reply_to_map[] = {
-{ "reply-to", "from", GMIME_RECIPIENT_TYPE_TO  },
-{ "to", NULL, GMIME_RECIPIENT_TYPE_TO  },
-{ "cc", NULL, GMIME_RECIPIENT_TYPE_CC  },
-{ "bcc",NULL, GMIME_RECIPIENT_TYPE_BCC }
-};
-
 static void
 reply_part_content (GMimeObject *part)
 {
@@ -193,16 +182,56 @@ add_recipients_for_string (GMimeMessage *message,
 return add_recipients_for_address_list (message, config, type, list);
 }
 
+/* Augments the recipients of reply from the headers of message.
+ *
+ * If any of the user's addresses were found in these headers, the first
+ * of these returned, otherwise NULL is returned.
+ */
+static const char *
+add_recipients_from_message (GMimeMessage *reply,
+notmuch_config_t *config,
+notmuch_message_t *message)
+{
+static const struct {
+   const char *header;
+   const char *fallback;
+   GMimeRecipientType recipient_type;
+} reply_to_map[] = {
+   { "reply-to", "from", GMIME_RECIPIENT_TYPE_TO  },
+   { "to", NULL, GMIME_RECIPIENT_TYPE_TO  },
+   { "cc", NULL, GMIME_RECIPIENT_TYPE_CC  },
+   { "bcc",NULL, GMIME_RECIPIENT_TYPE_BCC }
+};
+const char *from_addr = NULL;
+unsigned int i;
+
+for (i = 0; i < ARRAY_SIZE (reply_to_map); i++) {
+   const char *addr, *recipients;
+
+   recipients = notmuch_message_get_header (message,
+reply_to_map[i].header);
+   if ((recipients == NULL || recipients[0] == '\0') && 
reply_to_map[i].fallback)
+   recipients = notmuch_message_get_header (message,
+reply_to_map[i].fallback);
+
+   addr = add_recipients_for_string (reply, config,
+ reply_to_map[i].recipient_type,
+ recipients);
+   if (from_addr == NULL)
+   from_addr = addr;
+}
+return from_addr;
+}
+
 static int
 notmuch_reply_format_default(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query)
 {
 GMimeMessage *reply;
 notmuch_messages_t *messages;
 notmuch_message_t *message;
-const char *subject, *recipients, *from_addr = NULL;
+const char *subject, *from_addr = NULL;
 const char *in_reply_to, *orig_references, *references;
 char *reply_headers;
-unsigned int i;
 
 for (messages = notmuch_query_search_messages (query);
 notmuch_messages_has_more (messages);
@@ -223,21 +252,7 @@ notmuch_reply_format_default(void *ctx, notmuch_config_t 
*config, notmuch_query_
subject = talloc_asprintf (ctx, "Re: %s", subject);
g_mime_message_set_subject (reply, subject);
 
-   for (i = 0; i < ARRAY_SIZE (reply_to_map); i++) {
-   const char *addr;
-
-   recipients = notmuch_message_get_header (message,
-reply_to_map[i].header);
-   if ((recipients == NULL || recipients[0] == '\0') && 
reply_to_map[i].fallback)
-   recipients = notmuch_message_get_header (message,
-
reply_to_map[i].fallback);
-
-   addr = add_recipients_for_string (reply, config,
- reply_to_map[i].recipient_type,
- recipients);
-   if (from_addr == NULL)
-   from_addr = addr;
-   }
+   from_addr = add_recipients_from_message (reply, config, message);
 
if (from_addr == NULL)
from_addr = notmuch_config_get_user_primary_email (config);
@@ -290,9 +305,8 @@ notmuch_reply_format_headers_only(void *ctx, 
notmuch_config_t *config, notmuch_q
 GMimeMessage *reply;
 notmuch_messages_t *messages;
 notmuch_message_t *message;
-const char *recipients, *in_reply_to, *orig_references, *references;
+const char *in_reply_to, *orig_references, *references;
 char *reply_headers;
-unsigned int i;
 
 for (messages = notmuch_query_search_messages (query);
 notmuch_messages_has_more (messages);
@@ -326,19 +340,7 @@ notmuch_reply_forma

[notmuch] [PATCH 2/2] notmuch-reply.c: Handle munged `Reply-To' headers.

2009-11-28 Thread Jed Brown
Some mailing lists engage in the evil practice of changing the Reply-To
header so that replies from all mailers go to the list by default, at
the expense of not responding to the person who actually sent the
message.  When this is detected, we reply to `From' and remove the
duplicate response to the mailing list.  Consider a reply to the
following message.

  From: Some User 
  To: Sample users list 
  Reply-To: Sample users list 

Prior to this patch, `notmuch reply' produces

  To: Sample users list ,
  Sample users list 

and after the patch,

  To: Some User ,
  Sample users list 

Signed-off-by: Jed Brown 
---
 notmuch-reply.c |   47 ++-
 1 files changed, 46 insertions(+), 1 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index b91a830..9b9e9ab 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -182,6 +182,39 @@ add_recipients_for_string (GMimeMessage *message,
 return add_recipients_for_address_list (message, config, type, list);
 }
 
+/* Some mailing lists munge the Reply-To header despite it being A Bad
+ * Thing, see http://www.unicom.com/pw/reply-to-harmful.html
+ *
+ * This function detects such munging so that reasonable headers can be
+ * generated anyway.  Returns 1 if munged, else 0.
+ *
+ * The current logic is fairly naive, Reply-To is diagnosed as munged if
+ * it contains exactly one address, and this address is also present in
+ * the To or Cc fields.
+ */
+static int
+mailing_list_munged_reply_to (notmuch_message_t *message)
+{
+const char *header, *addr;
+InternetAddressList *list;
+InternetAddress *address;
+InternetAddressMailbox *mailbox;
+
+header = notmuch_message_get_header (message, "reply-to");
+list = internet_address_list_parse_string (header);
+if (internet_address_list_length (list) != 1)
+   return 0;
+address = internet_address_list_get_address (list, 0);
+if (INTERNET_ADDRESS_IS_GROUP (address))
+   return 0;
+mailbox = INTERNET_ADDRESS_MAILBOX (address);
+addr = internet_address_mailbox_get_addr (mailbox);
+/* Note that strcasestr() is a GNU extension, strstr() might be sufficient 
*/
+if (strcasestr (notmuch_message_get_header (message, "to"), addr) == 0 ||
+   strcasestr (notmuch_message_get_header (message, "cc"), addr) == 0)
+   return 1;
+return 0; }
+
 /* Augments the recipients of reply from the headers of message.
  *
  * If any of the user's addresses were found in these headers, the first
@@ -192,7 +225,7 @@ add_recipients_from_message (GMimeMessage *reply,
 notmuch_config_t *config,
 notmuch_message_t *message)
 {
-static const struct {
+struct {
const char *header;
const char *fallback;
GMimeRecipientType recipient_type;
@@ -205,6 +238,18 @@ add_recipients_from_message (GMimeMessage *reply,
 const char *from_addr = NULL;
 unsigned int i;
 
+/* When we have detected Reply-To munging, we ignore the Reply-To
+ * field (because it appears in the To or Cc headers) and use the
+ * From header so that person will get pinged and will actually
+ * receive the response if not subscribed to the list.  Note that
+ * under no circumstances does this fail to reply to the address in
+ * the Reply-To header.
+ */
+if (mailing_list_munged_reply_to (message)) {
+   reply_to_map[0].header = "from";
+   reply_to_map[0].fallback = NULL;
+}
+
 for (i = 0; i < ARRAY_SIZE (reply_to_map); i++) {
const char *addr, *recipients;
 
-- 
1.6.5.3

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


[notmuch] [PATCH] notmuch-reply.c: early exit for munged Reply-To when header is not present

2009-11-30 Thread Jed Brown
This avoids erroneously calling internet_address_list_length() with a
NULL list (which was causing a gmime exception).

Signed-off-by: Jed Brown 
---
 notmuch-reply.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 9b9e9ab..6c9118e 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -202,7 +202,7 @@ mailing_list_munged_reply_to (notmuch_message_t *message)
 
 header = notmuch_message_get_header (message, "reply-to");
 list = internet_address_list_parse_string (header);
-if (internet_address_list_length (list) != 1)
+if (list == NULL || internet_address_list_length (list) != 1)
return 0;
 address = internet_address_list_get_address (list, 0);
 if (INTERNET_ADDRESS_IS_GROUP (address))
-- 
1.6.5.3

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


Re: [notmuch] Problem building notmuch

2009-12-01 Thread Jed Brown
On Tue, 1 Dec 2009 10:33:05 +0100, Steen Manniche  wrote:
> Probably unusable system info:
> % uname -a
> Linux algorithm 2.6.31-ARCH #1 SMP PREEMPT Fri Oct 23 11:12:58 CEST
> 2009 i686 Intel(R) Core(TM)2 Duo CPU P9500 @ 2.53GHz GenuineIntel
> GNU/Linux

This is pretty much my fault because I made the talloc package that is
on AUR.  The problem is that you have both talloc-1 (from the smbclient
package) and talloc-2 (from the AUR talloc).  The libtalloc.so symlink
points at smbclient's copy, but smbclient doesn't include a pkgconfig
for talloc, thus you are using the talloc-2 header and talloc-1 library.

How do other distros handle talloc-1/talloc-2 incompatibility?

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


Re: [notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-12-02 Thread Jed Brown
A patch for notmuch-search-filter follows, my change to
notmuch-search-filter-by-tag is not very useful since
notmuch-select-tag-with-completion does not allow a space to be
inserted.  I don't know how to get completion on multiple
space-separated terms.

On Tue, 01 Dec 2009 18:56:59 -0800, Carl Worth  wrote:
> PS. Hmm... "notmuch reply" needs to be more clever to avoid duplicate
> addresses in the To: and Cc: lines. See above.

Yes, uniquifying the headers actually requires some effort, unless I'm
missing something in the gmime API (which I've never looked at before).

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


[notmuch] [PATCH] Make search filters handle disjunctive queries.

2009-12-02 Thread Jed Brown
notmuch-search-filter now accepts an arbitrary query and will group if
necessary so that we get

  tag:inbox AND (gravy OR biscuits)

instead of the former

  tag:inbox AND gravy OR biscuits

Signed-off-by: Jed Brown 
---
 notmuch.el |5 -
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/notmuch.el b/notmuch.el
index 2509651..0bf82f5 100644
--- a/notmuch.el
+++ b/notmuch.el
@@ -995,6 +995,8 @@ thread from that buffer can be show when done with this 
one)."
 (defvar notmuch-search-oldest-first t
   "Show the oldest mail first in the search-mode")
 
+(defvar notmuch-search-disjunctive-regexp  "\\<[oO][rR]\\>")
+
 (defun notmuch-search-scroll-up ()
   "Move forward through search results by one window's worth."
   (interactive)
@@ -1327,7 +1329,8 @@ search."
 Runs a new search matching only messages that match both the
 current search results AND the additional query string provided."
   (interactive "sFilter search: ")
-  (notmuch-search (concat notmuch-search-query-string " and " query) 
notmuch-search-oldest-first))
+  (let ((grouped-query (if (string-match-p notmuch-search-disjunctive-regexp 
query) (concat "( " query " )") query)))
+(notmuch-search (concat notmuch-search-query-string " and " grouped-query) 
notmuch-search-oldest-first)))
 
 (defun notmuch-search-filter-by-tag (tag)
   "Filter the current search results based on a single tag.
-- 
1.6.5.3

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


  1   2   >